From 1c13c343b5333a47450849d9b486756631fb9115 Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Tue, 7 Nov 2023 20:45:13 +0530 Subject: [PATCH 1/7] First pass for nimble listbox --- .../nimble-components/src/listbox/index.ts | 26 ++++++++++++++ .../nimble-components/src/listbox/styles.ts | 35 +++++++++++++++++++ .../src/listbox/tests/listbox.spec.ts | 13 +++++++ .../src/listbox/tests/listbox.stories.ts | 33 +++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 packages/nimble-components/src/listbox/index.ts create mode 100644 packages/nimble-components/src/listbox/styles.ts create mode 100644 packages/nimble-components/src/listbox/tests/listbox.spec.ts create mode 100644 packages/nimble-components/src/listbox/tests/listbox.stories.ts diff --git a/packages/nimble-components/src/listbox/index.ts b/packages/nimble-components/src/listbox/index.ts new file mode 100644 index 0000000000..12df8073c5 --- /dev/null +++ b/packages/nimble-components/src/listbox/index.ts @@ -0,0 +1,26 @@ +import { + DesignSystem, + ListboxElement as FoundationListbox, + listboxTemplate as template +} from '@microsoft/fast-foundation'; +import { styles } from './styles'; + +declare global { + interface HTMLElementTagNameMap { + 'nimble-listbox': Listbox; + } +} + +/** + * A nimble-styled HTML list box + */ +export class Listbox extends FoundationListbox {} + +const nimbleListbox = Listbox.compose({ + baseName: 'listbox', + template, + styles +}); + +DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleListbox()); +export const listboxTag = DesignSystem.tagFor(Listbox); diff --git a/packages/nimble-components/src/listbox/styles.ts b/packages/nimble-components/src/listbox/styles.ts new file mode 100644 index 0000000000..405fd3d118 --- /dev/null +++ b/packages/nimble-components/src/listbox/styles.ts @@ -0,0 +1,35 @@ +import { css } from '@microsoft/fast-element'; +import { display } from '@microsoft/fast-foundation'; + +import { + applicationBackgroundColor, + borderWidth, + popupBorderColor, + elevation2BoxShadow, + bodyFont, + bodyFontColor +} from '../theme-provider/design-tokens'; + +export const styles = css` + ${display('grid')} + + :host { + background: ${applicationBackgroundColor}; + border: ${borderWidth} solid ${popupBorderColor}; + margin: 0; + min-width: 176px; + width: max-content; + box-shadow: ${elevation2BoxShadow}; + color: ${bodyFontColor}; + font: ${bodyFont}; + } + + :host(:focus) { + outline: 0px; + } + + slot { + padding: 4px; + display: block; + } +`; diff --git a/packages/nimble-components/src/listbox/tests/listbox.spec.ts b/packages/nimble-components/src/listbox/tests/listbox.spec.ts new file mode 100644 index 0000000000..82d95cda82 --- /dev/null +++ b/packages/nimble-components/src/listbox/tests/listbox.spec.ts @@ -0,0 +1,13 @@ +import { Listbox, listboxTag } from '..'; + +describe('Listbox', () => { + it('should export its tag', () => { + expect(listboxTag).toBe('nimble-listbox'); + }); + + it('can construct an element instance', () => { + expect(document.createElement('nimble-listbox')).toBeInstanceOf( + Listbox + ); + }); +}); diff --git a/packages/nimble-components/src/listbox/tests/listbox.stories.ts b/packages/nimble-components/src/listbox/tests/listbox.stories.ts new file mode 100644 index 0000000000..1b760239af --- /dev/null +++ b/packages/nimble-components/src/listbox/tests/listbox.stories.ts @@ -0,0 +1,33 @@ +import { html } from '@microsoft/fast-element'; +import type { Meta, StoryObj } from '@storybook/html'; +import { createUserSelectedThemeStory } from '../../utilities/tests/storybook'; +import { listboxTag } from '..'; +import { listOptionTag } from '../../list-option'; + +const listboxDescription = 'Per [W3C](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/) - A listbox widget presents a list of options and allows a user to select one or more of them. A listbox that allows a single option to be chosen is a single-select listbox; one that allows multiple options to be selected is a multi-select listbox.'; + +const metadata: Meta = { + title: 'Tests/Listbox', + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: listboxDescription + } + } + }, + // prettier-ignore + render: createUserSelectedThemeStory(html` + <${listboxTag}> + <${listOptionTag} value="1">Option 1 + <${listOptionTag} value="2">Option 2 + <${listOptionTag} value="3">Option 3 + <${listOptionTag} value="4">Option 4 + <${listOptionTag} value="5">Option 5 + + `) +}; + +export default metadata; + +export const listbox: StoryObj = {}; From be0618dec7eedd81d78f7de9952e3618d9ea1150 Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Tue, 7 Nov 2023 20:48:44 +0530 Subject: [PATCH 2/7] Change files --- ...le-components-46cd01a3-0093-40b0-94b4-d5773a0a0582.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@ni-nimble-components-46cd01a3-0093-40b0-94b4-d5773a0a0582.json diff --git a/change/@ni-nimble-components-46cd01a3-0093-40b0-94b4-d5773a0a0582.json b/change/@ni-nimble-components-46cd01a3-0093-40b0-94b4-d5773a0a0582.json new file mode 100644 index 0000000000..75256eee7d --- /dev/null +++ b/change/@ni-nimble-components-46cd01a3-0093-40b0-94b4-d5773a0a0582.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Nimble list box component bring up", + "packageName": "@ni/nimble-components", + "email": "123377523+vivinkrishna-ni@users.noreply.github.com", + "dependentChangeType": "patch" +} From ef0baefc1335945b6c5968eba25902840694b158 Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:21:08 +0530 Subject: [PATCH 3/7] Resolve PR comments --- .../nimble-components/src/listbox/styles.ts | 8 +++-- .../listbox/tests/listbox-matrix.stories.ts | 32 ++++++++++++++++++ .../src/listbox/tests/listbox.stories.ts | 33 ------------------- packages/nimble-components/src/menu/styles.ts | 5 +-- .../theme-provider/design-token-comments.ts | 1 + .../src/theme-provider/design-token-names.ts | 1 + .../src/theme-provider/design-tokens.ts | 3 ++ 7 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts delete mode 100644 packages/nimble-components/src/listbox/tests/listbox.stories.ts diff --git a/packages/nimble-components/src/listbox/styles.ts b/packages/nimble-components/src/listbox/styles.ts index 405fd3d118..48ba8dd05c 100644 --- a/packages/nimble-components/src/listbox/styles.ts +++ b/packages/nimble-components/src/listbox/styles.ts @@ -7,7 +7,9 @@ import { popupBorderColor, elevation2BoxShadow, bodyFont, - bodyFontColor + bodyFontColor, + smallPadding, + menuMinWidth } from '../theme-provider/design-tokens'; export const styles = css` @@ -17,7 +19,7 @@ export const styles = css` background: ${applicationBackgroundColor}; border: ${borderWidth} solid ${popupBorderColor}; margin: 0; - min-width: 176px; + min-width: ${menuMinWidth}; width: max-content; box-shadow: ${elevation2BoxShadow}; color: ${bodyFontColor}; @@ -29,7 +31,7 @@ export const styles = css` } slot { - padding: 4px; + padding: ${smallPadding}; display: block; } `; diff --git a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts new file mode 100644 index 0000000000..2fb8f7c940 --- /dev/null +++ b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts @@ -0,0 +1,32 @@ +import { ViewTemplate, html } from '@microsoft/fast-element'; +import type { Meta, StoryFn } from '@storybook/html'; +import { + createMatrix, + sharedMatrixParameters +} from '../../utilities/tests/matrix'; +import { createMatrixThemeStory } from '../../utilities/tests/storybook'; +import { listboxTag } from '..'; +import { listOptionTag } from '../../list-option'; + +const metadata: Meta = { + title: 'Tests/Listbox', + parameters: { + ...sharedMatrixParameters() + } +}; + +export default metadata; + +const component = (): ViewTemplate => html` + <${listboxTag}> + <${listOptionTag} value="1">Option 1 + <${listOptionTag} value="2">Option 2 + <${listOptionTag} value="3">Option 3 + <${listOptionTag} value="4">Option 4 + <${listOptionTag} value="5">Option 5 + +`; + +export const listboxThemeMatrix: StoryFn = createMatrixThemeStory( + createMatrix(component) +); \ No newline at end of file diff --git a/packages/nimble-components/src/listbox/tests/listbox.stories.ts b/packages/nimble-components/src/listbox/tests/listbox.stories.ts deleted file mode 100644 index 1b760239af..0000000000 --- a/packages/nimble-components/src/listbox/tests/listbox.stories.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { html } from '@microsoft/fast-element'; -import type { Meta, StoryObj } from '@storybook/html'; -import { createUserSelectedThemeStory } from '../../utilities/tests/storybook'; -import { listboxTag } from '..'; -import { listOptionTag } from '../../list-option'; - -const listboxDescription = 'Per [W3C](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/) - A listbox widget presents a list of options and allows a user to select one or more of them. A listbox that allows a single option to be chosen is a single-select listbox; one that allows multiple options to be selected is a multi-select listbox.'; - -const metadata: Meta = { - title: 'Tests/Listbox', - tags: ['autodocs'], - parameters: { - docs: { - description: { - component: listboxDescription - } - } - }, - // prettier-ignore - render: createUserSelectedThemeStory(html` - <${listboxTag}> - <${listOptionTag} value="1">Option 1 - <${listOptionTag} value="2">Option 2 - <${listOptionTag} value="3">Option 3 - <${listOptionTag} value="4">Option 4 - <${listOptionTag} value="5">Option 5 - - `) -}; - -export default metadata; - -export const listbox: StoryObj = {}; diff --git a/packages/nimble-components/src/menu/styles.ts b/packages/nimble-components/src/menu/styles.ts index d920cfa80f..4e082728c0 100644 --- a/packages/nimble-components/src/menu/styles.ts +++ b/packages/nimble-components/src/menu/styles.ts @@ -12,7 +12,8 @@ import { groupHeaderFontColor, smallPadding, mediumPadding, - elevation2BoxShadow + elevation2BoxShadow, + menuMinWidth } from '../theme-provider/design-tokens'; import { Theme } from '../theme-provider/types'; import { hexToRgbaCssColor } from '../utilities/style/colors'; @@ -25,7 +26,7 @@ export const styles = css` background: ${applicationBackgroundColor}; border: ${borderWidth} solid ${popupBorderColor}; margin: 0; - min-width: 176px; + min-width: ${menuMinWidth}; width: max-content; box-shadow: ${elevation2BoxShadow}; } diff --git a/packages/nimble-components/src/theme-provider/design-token-comments.ts b/packages/nimble-components/src/theme-provider/design-token-comments.ts index 3530fe5a26..280faa86ff 100644 --- a/packages/nimble-components/src/theme-provider/design-token-comments.ts +++ b/packages/nimble-components/src/theme-provider/design-token-comments.ts @@ -70,6 +70,7 @@ export const comments: { readonly [key in TokenName]: string | null } = { dialogLargeWidth: 'Standard width for large dialogs.', dialogLargeHeight: 'Standard height for large dialogs.', dialogLargeMaxHeight: 'Standard maximum height for large dialogs.', + menuMinWidth: 'Standard menu min width for menu popup.', bannerGapSize: 'Space between stacked banners', spinnerSmallHeight: 'Small height (16px) for a spinner component', spinnerMediumHeight: 'Medium height (32px) for a spinner component', diff --git a/packages/nimble-components/src/theme-provider/design-token-names.ts b/packages/nimble-components/src/theme-provider/design-token-names.ts index 24ce825650..7d7e047b5d 100644 --- a/packages/nimble-components/src/theme-provider/design-token-names.ts +++ b/packages/nimble-components/src/theme-provider/design-token-names.ts @@ -53,6 +53,7 @@ export const tokenNames: { readonly [key in TokenName]: string } = { dialogLargeWidth: 'dialog-large-width', dialogLargeHeight: 'dialog-large-height', dialogLargeMaxHeight: 'dialog-large-max-height', + menuMinWidth: 'menu-min-width', bannerGapSize: 'banner-gap-size', spinnerSmallHeight: 'spinner-small-height', spinnerMediumHeight: 'spinner-medium-height', diff --git a/packages/nimble-components/src/theme-provider/design-tokens.ts b/packages/nimble-components/src/theme-provider/design-tokens.ts index ccc762e764..895add2af2 100644 --- a/packages/nimble-components/src/theme-provider/design-tokens.ts +++ b/packages/nimble-components/src/theme-provider/design-tokens.ts @@ -324,6 +324,9 @@ export const dialogLargeHeight = DesignToken.create( export const dialogLargeMaxHeight = DesignToken.create( styleNameFromTokenName(tokenNames.dialogLargeMaxHeight) ).withDefault('680px'); +export const menuMinWidth = DesignToken.create( + styleNameFromTokenName(tokenNames.menuMinWidth) +).withDefault('176px'); export const bannerGapSize = DesignToken.create( styleNameFromTokenName(tokenNames.bannerGapSize) ).withDefault('1px'); From 2bc7cbfbdad2dc2f1740962e98908105842c328a Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:27:41 +0530 Subject: [PATCH 4/7] lint fix --- .../src/listbox/tests/listbox-matrix.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts index 2fb8f7c940..28ad1abd3f 100644 --- a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts +++ b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts @@ -29,4 +29,4 @@ const component = (): ViewTemplate => html` export const listboxThemeMatrix: StoryFn = createMatrixThemeStory( createMatrix(component) -); \ No newline at end of file +); From fdda01520f5791e9aa7d31d532eb968af313251d Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:53:33 +0530 Subject: [PATCH 5/7] Address feedbacks --- .../listbox/tests/listbox-matrix.stories.ts | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts index 28ad1abd3f..74c3c84da0 100644 --- a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts +++ b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts @@ -4,9 +4,10 @@ import { createMatrix, sharedMatrixParameters } from '../../utilities/tests/matrix'; -import { createMatrixThemeStory } from '../../utilities/tests/storybook'; +import { createMatrixThemeStory, createStory } from '../../utilities/tests/storybook'; import { listboxTag } from '..'; import { listOptionTag } from '../../list-option'; +import { hiddenWrapper } from '../../utilities/tests/hidden'; const metadata: Meta = { title: 'Tests/Listbox', @@ -17,16 +18,30 @@ const metadata: Meta = { export default metadata; +const playFunction = (): void => { + const editorNodeList = document.querySelectorAll('nimble-listbox'); + editorNodeList.forEach(element => element.selectFirstOption()); +}; + const component = (): ViewTemplate => html` <${listboxTag}> - <${listOptionTag} value="1">Option 1 - <${listOptionTag} value="2">Option 2 - <${listOptionTag} value="3">Option 3 - <${listOptionTag} value="4">Option 4 - <${listOptionTag} value="5">Option 5 + <${listOptionTag} value="1">Loooooooooooooooooooooooong Word + <${listOptionTag} value="2">Word + <${listOptionTag} value="3">Short Word + <${listOptionTag} value="4" disabled>Disabled + <${listOptionTag} value="5">Multiple words in a single option to test the width of the option it gets wrapped `; export const listboxThemeMatrix: StoryFn = createMatrixThemeStory( createMatrix(component) ); +listboxThemeMatrix.play = playFunction; + +export const hiddenListbox: StoryFn = createStory( + hiddenWrapper( + html`<${listboxTag} hidden> + <${listOptionTag} value="1">Option 1 + ` + ) +); From e71c53b89208ab6e0de0033fba0df5700daee45a Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:01:25 +0530 Subject: [PATCH 6/7] Ellipsis text support --- .../nimble-components/src/list-option/styles.ts | 3 +++ packages/nimble-components/src/listbox/styles.ts | 4 ++-- .../src/listbox/tests/listbox-matrix.stories.ts | 14 ++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/nimble-components/src/list-option/styles.ts b/packages/nimble-components/src/list-option/styles.ts index 209527b4a4..6bcb9f23db 100644 --- a/packages/nimble-components/src/list-option/styles.ts +++ b/packages/nimble-components/src/list-option/styles.ts @@ -28,6 +28,9 @@ export const styles = css` .content { padding: 8px 4px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } :host([aria-selected='true']) { diff --git a/packages/nimble-components/src/listbox/styles.ts b/packages/nimble-components/src/listbox/styles.ts index 48ba8dd05c..15251c1c0e 100644 --- a/packages/nimble-components/src/listbox/styles.ts +++ b/packages/nimble-components/src/listbox/styles.ts @@ -13,14 +13,14 @@ import { } from '../theme-provider/design-tokens'; export const styles = css` - ${display('grid')} + ${display('inline-flex')} :host { background: ${applicationBackgroundColor}; border: ${borderWidth} solid ${popupBorderColor}; + flex-direction: column; margin: 0; min-width: ${menuMinWidth}; - width: max-content; box-shadow: ${elevation2BoxShadow}; color: ${bodyFontColor}; font: ${bodyFont}; diff --git a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts index 74c3c84da0..dc5c72a655 100644 --- a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts +++ b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts @@ -4,7 +4,10 @@ import { createMatrix, sharedMatrixParameters } from '../../utilities/tests/matrix'; -import { createMatrixThemeStory, createStory } from '../../utilities/tests/storybook'; +import { + createMatrixThemeStory, + createStory +} from '../../utilities/tests/storybook'; import { listboxTag } from '..'; import { listOptionTag } from '../../list-option'; import { hiddenWrapper } from '../../utilities/tests/hidden'; @@ -24,12 +27,11 @@ const playFunction = (): void => { }; const component = (): ViewTemplate => html` - <${listboxTag}> - <${listOptionTag} value="1">Loooooooooooooooooooooooong Word - <${listOptionTag} value="2">Word - <${listOptionTag} value="3">Short Word + <${listboxTag} style="width: 240px"> + <${listOptionTag} value="1">Selected Option + <${listOptionTag} value="3">Testing ellipsis text with a long sentence <${listOptionTag} value="4" disabled>Disabled - <${listOptionTag} value="5">Multiple words in a single option to test the width of the option it gets wrapped + <${listOptionTag} value="5">Option `; From 6c6df7b91a49c4765eb4dc958de8a33b6d297c98 Mon Sep 17 00:00:00 2001 From: Vivin Krishna <123377523+vivinkrishna-ni@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:08:47 +0530 Subject: [PATCH 7/7] Resolve comments --- packages/nimble-components/src/list-option/styles.ts | 3 --- .../src/listbox/tests/listbox-matrix.stories.ts | 11 ++++++----- .../src/theme-provider/design-token-names.ts | 1 + .../src/theme-provider/tests/tokens.stories.ts | 1 + 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/nimble-components/src/list-option/styles.ts b/packages/nimble-components/src/list-option/styles.ts index 6bcb9f23db..209527b4a4 100644 --- a/packages/nimble-components/src/list-option/styles.ts +++ b/packages/nimble-components/src/list-option/styles.ts @@ -28,9 +28,6 @@ export const styles = css` .content { padding: 8px 4px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } :host([aria-selected='true']) { diff --git a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts index dc5c72a655..58c048c2df 100644 --- a/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts +++ b/packages/nimble-components/src/listbox/tests/listbox-matrix.stories.ts @@ -27,11 +27,12 @@ const playFunction = (): void => { }; const component = (): ViewTemplate => html` - <${listboxTag} style="width: 240px"> - <${listOptionTag} value="1">Selected Option - <${listOptionTag} value="3">Testing ellipsis text with a long sentence - <${listOptionTag} value="4" disabled>Disabled - <${listOptionTag} value="5">Option + <${listboxTag}> + <${listOptionTag} value="1">Option 1 + <${listOptionTag} value="2">Option 2 + <${listOptionTag} value="3" disabled>Option 3 + <${listOptionTag} value="4">Option 4 + <${listOptionTag} value="5" hidden>Option 5 `; diff --git a/packages/nimble-components/src/theme-provider/design-token-names.ts b/packages/nimble-components/src/theme-provider/design-token-names.ts index 7d7e047b5d..40b1ccf918 100644 --- a/packages/nimble-components/src/theme-provider/design-token-names.ts +++ b/packages/nimble-components/src/theme-provider/design-token-names.ts @@ -257,6 +257,7 @@ const tokenSuffixes = [ 'FontFamily', 'BoxShadow', 'MaxHeight', + 'MinWidth', 'Font', 'Size', 'Width', diff --git a/packages/nimble-components/src/theme-provider/tests/tokens.stories.ts b/packages/nimble-components/src/theme-provider/tests/tokens.stories.ts index 675dbf4a24..2d15b1da04 100644 --- a/packages/nimble-components/src/theme-provider/tests/tokens.stories.ts +++ b/packages/nimble-components/src/theme-provider/tests/tokens.stories.ts @@ -110,6 +110,7 @@ const tokenTemplates: { FontFamily: stringValueTemplate, BoxShadow: stringValueTemplate, MaxHeight: stringValueTemplate, + MinWidth: stringValueTemplate, Font: fontTemplate, Size: stringValueTemplate, Width: stringValueTemplate,