diff --git a/.storybook/main.js b/.storybook/main.js index 9e47a21c..2bf0114b 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -10,14 +10,17 @@ module.exports = { "../stories/components/Accordion.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Alert.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Badge.@(mdx|stories.@(js|jsx|ts|tsx))", + "../stories/components/Breadcrumb.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Button.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Checkbox.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Divider.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Footer.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Icon.@(mdx|stories.@(js|jsx|ts|tsx))", + "../stories/components/IconButton.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Input.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Radio.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Masthead.@(mdx|stories.@(js|jsx|ts|tsx))", + "../stories/components/Modal.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Progress.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Skeleton.@(mdx|stories.@(js|jsx|ts|tsx))", "../stories/components/Spinner.@(mdx|stories.@(js|jsx|ts|tsx))", diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index b7cb76df..39cbbc80 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -8,7 +8,7 @@ Install SGDS web components locally with the following command ```js -npm install @govtechsg/sgds-web-component@3.0.0-rc.3 +npm install @govtechsg/sgds-web-component@3.0.0-rc.4 ``` @@ -62,13 +62,13 @@ This method registers all SGDS elements up front in the Custom Elements Registry ```js // Load global css file - + // it is recommended to load a particular version when using cdn e.g. https://cdn.jsdelivr.net/npm/@govtechsg/sgds-web-component@1.0.2 - + //or load a single component e.g. Masthead - + ``` diff --git a/index.html b/index.html index cb7ec4cb..b1eb24c9 100644 --- a/index.html +++ b/index.html @@ -283,7 +283,7 @@

IconList

- item one + item one
item one @@ -1159,7 +1159,7 @@

Close Button

Modal

Open Modal - +

Modal title

Modal description

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam dictum est vitae erat molestie blandit. Pellentesque at nunc at mi auctor imperdiet eu at leo. Integer aliquam, turpis vel ultricies ornare, sem massa commodo velit, pretium dictum quam nibh et ex. Suspendisse eu dignissim libero. Donec aliquam, lacus eu pellentesque interdum, arcu nisl blandit turpis, at tincidunt purus orci ut dolor. Morbi malesuada faucibus lorem, ornare accumsan sapien lacinia vel. In enim justo, hendrerit eu mi vitae, viverra fringilla nunc. Proin semper nunc a mollis faucibus. Nam at arcu non justo congue tincidunt. Donec vehicula felis risus, et lobortis lacus fringilla eu. Proin faucibus, nisi non semper elementum, sapien nisi viverra urna, id tempus augue felis ac nibh. Nullam pulvinar magna eros. Vestibulum at orci elit. Sed convallis fermentum gravida. diff --git a/src/components/Breadcrumb/sgds-breadcrumb-item.ts b/src/components/Breadcrumb/sgds-breadcrumb-item.ts index e11edce9..6ed67f47 100644 --- a/src/components/Breadcrumb/sgds-breadcrumb-item.ts +++ b/src/components/Breadcrumb/sgds-breadcrumb-item.ts @@ -2,14 +2,15 @@ import { html } from "lit"; import { property } from "lit/decorators.js"; import SgdsLink from "../Link/sgds-link"; import breadcrumbItemStyle from "./breadcrumb-item.css"; +import SgdsElement from "../../base/sgds-element"; /** * @summary Breadcrumb Item are navigational links used in Breadcrumb component * - * @slot default - The title of the item + * @slot default - The link of the item. Pass in anchor tags into this slot */ -export class SgdsBreadcrumbItem extends SgdsLink { +export class SgdsBreadcrumbItem extends SgdsElement { static styles = [...SgdsLink.styles, breadcrumbItemStyle]; - /** Specifies the url path of the breadcrumb-item. When defined, the breadcrumb-items is a anchor element. When not defined, indicates that the breadcrumb item is active. In such cases, a span element is rendered. */ + /** Indicates the link matches the current location of the page. Programmatically handled by SgdsBreadcrumb to set this prop to true for the last breadcrumb item */ @property({ type: Boolean, reflect: true }) active = false; render() { diff --git a/src/components/Icon/icon.css b/src/components/Icon/icon.css index 5f523beb..cfe83e2a 100644 --- a/src/components/Icon/icon.css +++ b/src/components/Icon/icon.css @@ -1,6 +1,6 @@ :host { color: inherit; - display: inline-block; + display: inline-flex; } :host([size="sm"]) svg { width: var(--sgds-icon-size-sm); diff --git a/src/components/IconButton/icon-button.css b/src/components/IconButton/icon-button.css index b9fefb61..53f4df47 100644 --- a/src/components/IconButton/icon-button.css +++ b/src/components/IconButton/icon-button.css @@ -1,3 +1,7 @@ +:host { + display: inline-block; +} + .btn.btn-icon { display: flex; width: var(--sgds-dimension-48, 56px); diff --git a/src/components/IconButton/sgds-icon-button.ts b/src/components/IconButton/sgds-icon-button.ts index d4926ee3..24feff19 100644 --- a/src/components/IconButton/sgds-icon-button.ts +++ b/src/components/IconButton/sgds-icon-button.ts @@ -9,8 +9,6 @@ import iconButtonStyles from "./icon-button.css"; /** * @summary An icon button is a user interface element that combines an icon and a button, serving as a clickable or tabbable component. * - * @slot default - The slot for sgds-icon - * * @event sgds-blur - Emitted when the button is blurred. * @event sgds-focus - Emitted when the button is focused. */ diff --git a/src/components/IconList/sgds-icon-list.ts b/src/components/IconList/sgds-icon-list.ts index c33058da..a379a9ad 100644 --- a/src/components/IconList/sgds-icon-list.ts +++ b/src/components/IconList/sgds-icon-list.ts @@ -1,36 +1,24 @@ -import SgdsElement from "../../base/sgds-element"; import { html } from "lit"; -import iconListStyles from "./icon-list.css"; import { property } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; -import SgdsIcon from "../Icon/sgds-icon"; -import { ifDefined } from "lit/directives/if-defined.js"; +import SgdsElement from "../../base/sgds-element"; +import iconListStyles from "./icon-list.css"; /** * @summary A IconList can be used to display content related to the same topic. Each list item begins an icon. * - * @slot default - The list items of IconList. Each list items should have aria attribute role="list" added + * @slot default - The list items of IconList. Each list items should have aria attribute role="listitem" added */ export class SgdsIconList extends SgdsElement { static styles = [...SgdsElement.styles, iconListStyles]; - static dependencies = { "sgds-icon": SgdsIcon }; /** Sets the aria-role of the sgds-icon-list */ @property({ type: String, reflect: true }) role = "list"; /** The size of icon list. Changes the font-size the list items */ @property({ type: String, reflect: true }) size: "sm" | "md" | "lg" = "md"; - /** The name of the icon from sgds icon library */ - @property({ type: String, reflect: true }) name: string; - - private _assignIconSize(buttonSize: "sm" | "md" | "lg") { - if (buttonSize === "sm") return "md"; - if (buttonSize === "md") return "lg"; - if (buttonSize === "lg") return "xl"; - } render() { return html`

-
`; diff --git a/src/components/Modal/modal.css b/src/components/Modal/modal.css index 4031820f..fa916ca4 100644 --- a/src/components/Modal/modal.css +++ b/src/components/Modal/modal.css @@ -35,12 +35,11 @@ width: 100%; max-width: 640px; border-radius: var(--sgds-border-radius-md); - margin: var(--sgds-spacer-9) auto; + margin: var(--sgds-spacer-9) var(--sgds-spacer-6); position: relative; - display:flex; + display: flex; flex-direction: column; - max-height: calc(100% - var(--sgds-spacer-9) - var(--sgds-spacer-9)) - + max-height: calc(100% - var(--sgds-spacer-9) - var(--sgds-spacer-9)); } .modal-panel:focus { @@ -50,7 +49,7 @@ /* Ensure there's enough vertical padding for phones that don't update vh when chrome appears (e.g. iPhone) */ @media screen and (max-width: 420px) { .modal-panel { - margin: var(--sgds-spacer-8) auto; + margin: var(--sgds-spacer-8) var(--sgds-spacer-6); max-height: calc(100% - var(--sgds-spacer-8) - var(--sgds-spacer-8)); } } @@ -68,7 +67,7 @@ padding: var(--sgds-padding-xl); } .modal-header__title-description { - display: flex; + display: flex; flex-direction: column; gap: var(--sgds-gap-xs); } @@ -128,4 +127,4 @@ slot[name="description"]::slotted(*) { [hidden] { display: none; -} \ No newline at end of file +} diff --git a/stories/templates/Breadcrumb/additional.mdx b/stories/templates/Breadcrumb/additional.mdx new file mode 100644 index 00000000..8466e000 --- /dev/null +++ b/stories/templates/Breadcrumb/additional.mdx @@ -0,0 +1,13 @@ +## Pass in anchor tags in default slot of `sgds-breadcrumb-item` + +For better SEO, anchor tags are to be passed by the user in the light dom or the slot of `sgds-breadcrumb-item`. +Every `sgds-breadcrumb-item` requires an anchor element. + +## Overflow menu + +Breadcrumb should show up to 4 breadcrumb items. Beyond that, the breadcrumb component will be re-grouped the excess items and render in a overflow dropdown menu automatically, displaying only the first , second last and last links + + + + + \ No newline at end of file diff --git a/stories/templates/Breadcrumb/additional.stories.js b/stories/templates/Breadcrumb/additional.stories.js new file mode 100644 index 00000000..7d3771d6 --- /dev/null +++ b/stories/templates/Breadcrumb/additional.stories.js @@ -0,0 +1,29 @@ +import { html } from "lit-html"; + +const OverflowTemplate = args => { + return html` + + Home + About + Contacts + Link-1 + Link-2 + Link-3 + Link-4 + + `; +}; + +export const Overflow = { + render: OverflowTemplate.bind({}), + name: "Overflow", + args: {}, + parameters: { + docs: { + story: { + height: "500px" + } + } + }, + tags: ["!dev"] +}; diff --git a/stories/templates/Breadcrumb/basic.js b/stories/templates/Breadcrumb/basic.js index b05eef95..8260b82b 100644 --- a/stories/templates/Breadcrumb/basic.js +++ b/stories/templates/Breadcrumb/basic.js @@ -3,18 +3,12 @@ import { ifDefined } from "lit/directives/if-defined.js"; export const Template = args => html` - - Home - Item 1 - Item 2 - Item 3 - Last Item + + Home + About + Contacts `; -export const args = { - href: "https://www.designsystem.tech.gov.sg/" -}; +export const args = {}; export const parameters = {}; diff --git a/stories/templates/IconButton/additional.mdx b/stories/templates/IconButton/additional.mdx new file mode 100644 index 00000000..98217859 --- /dev/null +++ b/stories/templates/IconButton/additional.mdx @@ -0,0 +1,41 @@ +## Variants + +The default variant is `primary`. Modify the `variant` prop to the intended value. + +- Use `primary` buttons to show the key action on a page or view. Most pages should only have one primary action. +- Use `outlined` buttons next to primary buttons to indicate alternative or less pronounced actions. +- Use `ghost` button for supplementary action as they are subtle in their appearance +- Use `danger` buttons to remove things or for irreversible actions. + + + + + +## Sizes + +The default button size is medium. Add `size="lg"`,` size="sm"` for additional sizes. + +- Large buttons are used sparingly across the UI. They may be used for page components that demand attention, such as on the homepage banner. +- The medium (default) button is the standard size for buttons everywhere. +- Small button should be used sparingly and only in places where the UI is very dense. + + + + + +## Hover / Active state + +To set a button's active state, set the component's `active` prop. + + + + + +## Disabled state + +The disabled state indicates that an action can’t be taken until a previous action is completed. +Add `disabled` prop to the button to apply the disabled state + + + + diff --git a/stories/templates/IconButton/additional.stories.js b/stories/templates/IconButton/additional.stories.js new file mode 100644 index 00000000..7b552a0f --- /dev/null +++ b/stories/templates/IconButton/additional.stories.js @@ -0,0 +1,62 @@ +import { html } from "lit-html"; + +const VariantTemplate = args => { + return html` + + + + + `; +}; + +export const Variants = { + render: VariantTemplate.bind({}), + name: "Variants", + args: {}, + parameters: {}, + tags: ["!dev"] +}; + +const SizeTemplate = () => { + return html` + + `; +}; + +export const Sizes = { + render: SizeTemplate.bind({}), + name: "Sizes", + args: {}, + parameters: {}, + tags: ["!dev"] +}; + +const ActiveTemplate = () => { + return html` + + + + + `; +}; + +export const Active = { + render: ActiveTemplate.bind({}), + name: "Hover / Active state", + args: {}, + parameters: {}, + tags: ["!dev"] +}; + +export const Disabled = { + render: () => html` + + + + + `, + name: "Disabled state", + args: {}, + parameters: {}, + tags: ["!dev"] +}; diff --git a/stories/templates/IconButton/basic.js b/stories/templates/IconButton/basic.js index 232d0b35..a86b2f94 100644 --- a/stories/templates/IconButton/basic.js +++ b/stories/templates/IconButton/basic.js @@ -1,7 +1,13 @@ import { html } from "lit-html"; +import { ifDefined } from "lit/directives/if-defined.js"; -export const Template = args => html``; +export const Template = args => html` `; -export const args = {}; +export const args = { + name: "plus" +}; export const parameters = {}; diff --git a/stories/templates/Modal/additional.mdx b/stories/templates/Modal/additional.mdx new file mode 100644 index 00000000..5c7ab1a5 --- /dev/null +++ b/stories/templates/Modal/additional.mdx @@ -0,0 +1,42 @@ +## Sizes + +### Small modal + + + + + +### Medium modal (default) + + + + + +### Large modal + + + + + +### Fullscreen modal + + + + + + +## Long content + +When content is long, auto-scrolling will be activated in the modal body. Modal header and footer are in fixed position + + + + + +## No animation + +Disabled animation by setting `noAnimation` to true + + + + diff --git a/stories/templates/Modal/additional.stories.js b/stories/templates/Modal/additional.stories.js new file mode 100644 index 00000000..d86f1368 --- /dev/null +++ b/stories/templates/Modal/additional.stories.js @@ -0,0 +1,155 @@ +import { html } from "lit-html"; + +export const SizeTemplate = args => { + return html` + e.preventDefault()}> +

Modal title

+

Modal description

+

+ Etiam suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in +

+ Submit +
+ `; +}; + +export const LongContentTemplate = args => { + return html` + e.preventDefault()}> +

Modal title

+

Modal description

+

+ Etiam suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in Etiam + suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in Etiam + suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in Etiam + suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in Etiam + suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in +

+ Submit +
+ `; +}; +export const noAnimationTemplate = args => { + return html` + Open Modal + +

Modal title

+

Modal description

+

+ Etiam suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in +

+ Close + Submit +
+ `; +}; + +const showModal = () => { + const modal = document.querySelector("#no-animation-modal"); + modal.show(); +}; +const closeModal = () => { + const modal = document.querySelector("#no-animation-modal"); + modal.hide(); +}; +export const SmallSize = { + render: SizeTemplate.bind({}), + name: "Small size", + args: { size: "sm" }, + parameters: { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } + } +}; +export const MediumSize = { + render: SizeTemplate.bind({}), + name: "Medium size", + args: { size: "md" }, + parameters: { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } + } +}; +export const LargeSize = { + render: SizeTemplate.bind({}), + name: "Large size", + args: { size: "lg" }, + parameters: { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } + } +}; +export const FullscreenSize = { + render: SizeTemplate.bind({}), + name: "Fullscreen size", + args: { size: "fullscreen" }, + parameters: { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } + } +}; + +export const LongContent = { + render: LongContentTemplate.bind({}), + name: "Long content", + args: { size: "md" }, + parameters: { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } + } +}; + +export const noAnimation = { + render: noAnimationTemplate.bind({}), + name: "No animation", + args: {}, + parameters: { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } + } +}; diff --git a/stories/templates/Modal/basic.js b/stories/templates/Modal/basic.js index 1180e8fb..da87ca7c 100644 --- a/stories/templates/Modal/basic.js +++ b/stories/templates/Modal/basic.js @@ -3,18 +3,21 @@ import { ifDefined } from "lit/directives/if-defined.js"; export const Template = args => { return html` - Open Modal + Open Modal - This is a Modal +

Modal title

+

Modal description

+

+ Etiam suscipit nisi eget porta cursus. Ut sit amet felis aliquet, pellentesque mi at, vulputate nunc. Vivamus ac + facilisis tellus. Maecenas ac libero scelerisque tellus maximus accumsan a vehicula arcu. Aenean quis leo + gravida, congue sapien eu, rhoncus ante. Quisque velit est, sodales vitae turpis vitae, hendrerit facilisis + nulla. Suspendisse potenti. Nulla hendrerit enim sed leo rutrum auctor. Praesent volutpat rutrum purus in +

Close Submit
@@ -30,11 +33,13 @@ export const closeModal = () => { modal.hide(); }; -export const args = { - titleIcon: ` - -`, - title: "hello" -}; +export const args = {}; -export const parameters = {}; +export const parameters = { + layout: "fullscreen", + docs: { + story: { + height: "700px" + } + } +}; diff --git a/test/breadcrumb.test.ts b/test/breadcrumb.test.ts index 5a3eaea6..a7d6112a 100644 --- a/test/breadcrumb.test.ts +++ b/test/breadcrumb.test.ts @@ -52,16 +52,12 @@ describe("sgds-breadcrumb", () => { `