@trimble-oss/moduswebcomponents-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +337 -0
  3. package/package.json +39 -0
  4. package/versions/1.0.0/component-docs/_all_components.json +56 -0
  5. package/versions/1.0.0/component-docs/modus-wc-autocomplete.json +415 -0
  6. package/versions/1.0.0/component-docs/modus-wc-date.json +227 -0
  7. package/versions/1.0.0/component-docs/modus-wc-dropdown-menu.json +164 -0
  8. package/versions/1.0.0/component-docs/modus-wc-logo.json +61 -0
  9. package/versions/1.0.0/component-docs/modus-wc-menu-item.json +165 -0
  10. package/versions/1.0.0/component-docs/modus-wc-menu.json +106 -0
  11. package/versions/1.0.0/component-docs/modus-wc-navbar.json +290 -0
  12. package/versions/1.0.0/component-docs/modus-wc-profile-menu.json +64 -0
  13. package/versions/1.0.0/component-docs/modus-wc-side-navigation.json +102 -0
  14. package/versions/1.0.0/component-docs/modus-wc-table.json +202 -0
  15. package/versions/1.0.0/component-docs/modus-wc-tooltip.json +94 -0
  16. package/versions/1.0.0/component-docs/modus-wc-typography.json +78 -0
  17. package/versions/1.0.0/docs/_all_docs.json +15 -0
  18. package/versions/1.0.0/docs/angular.mdx +374 -0
  19. package/versions/1.0.0/docs/getting-started.mdx +131 -0
  20. package/versions/1.0.7/component-docs/_all_components.json +55 -0
  21. package/versions/1.0.7/component-docs/modus-wc-autocomplete.json +405 -0
  22. package/versions/1.0.7/component-docs/modus-wc-table.json +202 -0
  23. package/versions/1.0.7/component-docs/modus-wc-tooltip.json +94 -0
  24. package/versions/1.0.7/docs/_all_docs.json +15 -0
  25. package/versions/1.0.7/docs/angular.mdx +374 -0
  26. package/versions/1.1.0/component-docs/_all_components.json +56 -0
  27. package/versions/1.1.0/component-docs/modus-wc-autocomplete.json +405 -0
  28. package/versions/1.1.0/component-docs/modus-wc-navbar.json +290 -0
  29. package/versions/1.1.0/component-docs/modus-wc-profile-menu.json +64 -0
  30. package/versions/1.1.0/component-docs/modus-wc-side-navigation.json +102 -0
  31. package/versions/1.1.0/component-docs/modus-wc-table.json +202 -0
  32. package/versions/1.1.0/component-docs/modus-wc-tooltip.json +94 -0
  33. package/versions/1.1.0/component-docs/modus-wc-typography.json +78 -0
  34. package/versions/1.1.0/docs/_all_docs.json +15 -0
  35. package/versions/1.1.0/docs/angular.mdx +374 -0
  36. package/versions/1.1.0/docs/getting-started.mdx +131 -0
  37. package/versions/1.1.1/component-docs/_all_components.json +56 -0
  38. package/versions/1.1.1/component-docs/modus-wc-autocomplete.json +405 -0
  39. package/versions/1.1.1/component-docs/modus-wc-navbar.json +290 -0
  40. package/versions/1.1.1/component-docs/modus-wc-profile-menu.json +64 -0
  41. package/versions/1.1.1/component-docs/modus-wc-side-navigation.json +102 -0
  42. package/versions/1.1.1/component-docs/modus-wc-table.json +202 -0
  43. package/versions/1.1.1/component-docs/modus-wc-tooltip.json +94 -0
  44. package/versions/1.1.1/component-docs/modus-wc-typography.json +78 -0
  45. package/versions/1.1.1/docs/_all_docs.json +15 -0
  46. package/versions/1.1.1/docs/angular.mdx +374 -0
  47. package/versions/1.1.1/docs/getting-started.mdx +131 -0
  48. package/versions/base/component-docs/_all_components.json +55 -0
  49. package/versions/base/component-docs/modus-wc-accordion.json +48 -0
  50. package/versions/base/component-docs/modus-wc-alert.json +112 -0
  51. package/versions/base/component-docs/modus-wc-autocomplete.json +397 -0
  52. package/versions/base/component-docs/modus-wc-avatar.json +83 -0
  53. package/versions/base/component-docs/modus-wc-badge.json +68 -0
  54. package/versions/base/component-docs/modus-wc-breadcrumbs.json +63 -0
  55. package/versions/base/component-docs/modus-wc-button-group.json +100 -0
  56. package/versions/base/component-docs/modus-wc-button.json +130 -0
  57. package/versions/base/component-docs/modus-wc-card.json +98 -0
  58. package/versions/base/component-docs/modus-wc-checkbox.json +149 -0
  59. package/versions/base/component-docs/modus-wc-chip.json +132 -0
  60. package/versions/base/component-docs/modus-wc-collapse.json +90 -0
  61. package/versions/base/component-docs/modus-wc-date.json +227 -0
  62. package/versions/base/component-docs/modus-wc-divider.json +85 -0
  63. package/versions/base/component-docs/modus-wc-dropdown-menu.json +154 -0
  64. package/versions/base/component-docs/modus-wc-file-dropzone.json +155 -0
  65. package/versions/base/component-docs/modus-wc-handle.json +135 -0
  66. package/versions/base/component-docs/modus-wc-icon.json +722 -0
  67. package/versions/base/component-docs/modus-wc-input-feedback.json +71 -0
  68. package/versions/base/component-docs/modus-wc-input-label.json +84 -0
  69. package/versions/base/component-docs/modus-wc-loader.json +65 -0
  70. package/versions/base/component-docs/modus-wc-logo.json +61 -0
  71. package/versions/base/component-docs/modus-wc-menu-item.json +173 -0
  72. package/versions/base/component-docs/modus-wc-menu.json +86 -0
  73. package/versions/base/component-docs/modus-wc-modal.json +108 -0
  74. package/versions/base/component-docs/modus-wc-navbar.json +280 -0
  75. package/versions/base/component-docs/modus-wc-number-input.json +219 -0
  76. package/versions/base/component-docs/modus-wc-pagination.json +103 -0
  77. package/versions/base/component-docs/modus-wc-panel.json +76 -0
  78. package/versions/base/component-docs/modus-wc-progress.json +86 -0
  79. package/versions/base/component-docs/modus-wc-radio.json +139 -0
  80. package/versions/base/component-docs/modus-wc-rating.json +117 -0
  81. package/versions/base/component-docs/modus-wc-select.json +159 -0
  82. package/versions/base/component-docs/modus-wc-side-navigation.json +102 -0
  83. package/versions/base/component-docs/modus-wc-skeleton.json +65 -0
  84. package/versions/base/component-docs/modus-wc-slider.json +163 -0
  85. package/versions/base/component-docs/modus-wc-stepper.json +47 -0
  86. package/versions/base/component-docs/modus-wc-switch.json +149 -0
  87. package/versions/base/component-docs/modus-wc-table.json +202 -0
  88. package/versions/base/component-docs/modus-wc-tabs.json +86 -0
  89. package/versions/base/component-docs/modus-wc-text-input.json +278 -0
  90. package/versions/base/component-docs/modus-wc-textarea.json +215 -0
  91. package/versions/base/component-docs/modus-wc-theme-switcher.json +49 -0
  92. package/versions/base/component-docs/modus-wc-time-input.json +211 -0
  93. package/versions/base/component-docs/modus-wc-toast.json +56 -0
  94. package/versions/base/component-docs/modus-wc-toolbar.json +44 -0
  95. package/versions/base/component-docs/modus-wc-tooltip.json +94 -0
  96. package/versions/base/component-docs/modus-wc-typography.json +73 -0
  97. package/versions/base/component-docs/modus-wc-utility-panel.json +86 -0
  98. package/versions/base/docs/_all_docs.json +15 -0
  99. package/versions/base/docs/accessibility.mdx +32 -0
  100. package/versions/base/docs/angular.mdx +346 -0
  101. package/versions/base/docs/form-inputs.mdx +86 -0
  102. package/versions/base/docs/getting-started.mdx +91 -0
  103. package/versions/base/docs/modus-figma-mcp-integration-guide.mdx +254 -0
  104. package/versions/base/docs/modus-icon-usage.mdx +210 -0
  105. package/versions/base/docs/react.mdx +129 -0
  106. package/versions/base/docs/styling.mdx +107 -0
  107. package/versions/base/docs/testing.mdx +18 -0
  108. package/versions/base/docs/vue.mdx +159 -0
@@ -0,0 +1,139 @@
1
+ {
2
+ "description": "A customizable radio button component.",
3
+ "properties": [
4
+ {
5
+ "name": "customClass",
6
+ "type": "string",
7
+ "description": "Custom CSS class to apply to the inner div.",
8
+ "default": "''",
9
+ "mutable": false,
10
+ "end_line": 31
11
+ },
12
+ {
13
+ "name": "disabled",
14
+ "type": "boolean",
15
+ "description": "The disabled state of the radio.",
16
+ "default": "false",
17
+ "mutable": false,
18
+ "end_line": 34
19
+ },
20
+ {
21
+ "name": "inputId",
22
+ "type": "string",
23
+ "description": "The ID of the input element.",
24
+ "default": null,
25
+ "mutable": false,
26
+ "end_line": 37
27
+ },
28
+ {
29
+ "name": "inputTabIndex",
30
+ "type": "number",
31
+ "description": "The tabindex of the input.",
32
+ "default": null,
33
+ "mutable": false,
34
+ "end_line": 40
35
+ },
36
+ {
37
+ "name": "label",
38
+ "type": "string",
39
+ "description": "The text to display within the label.",
40
+ "default": null,
41
+ "mutable": false,
42
+ "end_line": 43
43
+ },
44
+ {
45
+ "name": "name",
46
+ "type": "string",
47
+ "description": "Name of the form control. Submitted with the form as part of a name/value pair.",
48
+ "default": "''",
49
+ "mutable": false,
50
+ "end_line": 46
51
+ },
52
+ {
53
+ "name": "required",
54
+ "type": "boolean",
55
+ "description": "A value is required for the form to be submittable.",
56
+ "default": "false",
57
+ "mutable": false,
58
+ "end_line": 49
59
+ },
60
+ {
61
+ "name": "size",
62
+ "type": "ModusSize",
63
+ "description": "The size of the input.",
64
+ "default": "'md'",
65
+ "mutable": false,
66
+ "end_line": 52
67
+ },
68
+ {
69
+ "name": "value",
70
+ "type": "boolean",
71
+ "description": "The value of the radio.",
72
+ "default": "false",
73
+ "mutable": true,
74
+ "end_line": 55
75
+ }
76
+ ],
77
+ "events": [
78
+ {
79
+ "name": "inputBlur",
80
+ "detail": "FocusEvent",
81
+ "description": "Emitted when the input loses focus.",
82
+ "end_line": 58
83
+ },
84
+ {
85
+ "name": "inputChange",
86
+ "detail": "InputEvent",
87
+ "description": "Emitted when the input value changes.",
88
+ "end_line": 61
89
+ },
90
+ {
91
+ "name": "inputFocus",
92
+ "detail": "FocusEvent",
93
+ "description": "Emitted when the input gains focus.",
94
+ "end_line": 64
95
+ }
96
+ ],
97
+ "methods": [],
98
+ "slots": [],
99
+ "examples": {
100
+ "basic": "<modus-wc-radio\n aria-label=\"Radio\"\n custom-class=${ifDefined(args['custom-class'])}\n ?disabled=${args.disabled}\n input-id=${ifDefined(args['input-id'])}\n input-tab-index=${ifDefined(args['input-tab-index'])}\n label=${ifDefined(args.label)}\n name=${ifDefined(args.name)}\n ?required=${args.required}\n size=${ifDefined(args.size)}\n .value=${args.value}\n ></modus-wc-radio>",
101
+ "variations": [],
102
+ "args": {
103
+ "custom-class": "''",
104
+ "disabled": "false",
105
+ "label": "'Label'",
106
+ "name": "''",
107
+ "required": "false",
108
+ "size": "'md'",
109
+ "value": "true"
110
+ },
111
+ "argTypes": {},
112
+ "usage": [],
113
+ "events": [
114
+ "inputBlur",
115
+ "inputChange",
116
+ "inputFocus"
117
+ ]
118
+ },
119
+ "tag": "modus-wc-radio",
120
+ "storyExample": {
121
+ "template": "<modus-wc-radio\n aria-label=\"Radio\"\n custom-class=${ifDefined(args['custom-class'])}\n ?disabled=${args.disabled}\n input-id=${ifDefined(args['input-id'])}\n input-tab-index=${ifDefined(args['input-tab-index'])}\n label=${ifDefined(args.label)}\n name=${ifDefined(args.name)}\n ?required=${args.required}\n size=${ifDefined(args.size)}\n .value=${args.value}\n ></modus-wc-radio>",
122
+ "args": {
123
+ "custom-class": "''",
124
+ "disabled": "false",
125
+ "label": "'Label'",
126
+ "name": "''",
127
+ "required": "false",
128
+ "size": "'md'",
129
+ "value": "true"
130
+ },
131
+ "argTypes": {},
132
+ "events": [
133
+ "inputBlur",
134
+ "inputChange",
135
+ "inputFocus"
136
+ ],
137
+ "fullContent": "import { withActions } from '@storybook/addon-actions/decorator';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { createShadowHostClass } from '../../providers/shadow-dom/shadow-host-helper';\nimport { ModusSize } from '../types';\n\ninterface RadioArgs {\n 'custom-class'?: string;\n disabled?: boolean;\n 'input-id'?: string;\n 'input-tab-index'?: number;\n label?: string;\n name?: string;\n required?: boolean;\n size?: ModusSize;\n value: boolean;\n}\n\nconst meta: Meta<RadioArgs> = {\n title: 'Components/Forms/Radio',\n component: 'modus-wc-radio',\n args: {\n 'custom-class': '',\n disabled: false,\n label: 'Label',\n name: '',\n required: false,\n size: 'md',\n value: true,\n },\n argTypes: {\n size: {\n control: { type: 'select' },\n options: ['xs', 'sm', 'md', 'lg'],\n },\n },\n decorators: [withActions],\n parameters: {\n actions: {\n handles: ['inputBlur', 'inputChange', 'inputFocus'],\n },\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<RadioArgs>;\n\nexport const Default: Story = {\n render: (args) => {\n return html`\n <modus-wc-radio\n aria-label=\"Radio\"\n custom-class=${ifDefined(args['custom-class'])}\n ?disabled=${args.disabled}\n input-id=${ifDefined(args['input-id'])}\n input-tab-index=${ifDefined(args['input-tab-index'])}\n label=${ifDefined(args.label)}\n name=${ifDefined(args.name)}\n ?required=${args.required}\n size=${ifDefined(args.size)}\n .value=${args.value}\n ></modus-wc-radio>\n `;\n },\n};\n\nexport const RadioGroup: Story = {\n // prettier-ignore\n render: (args) => {\n return html`\n<style>\n .radio-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n .radio-group legend {\n margin-bottom: 0.5rem;\n }\n</style>\n\n<main role=\"main\">\n <fieldset class=\"radio-group\">\n <legend>Select an option:</legend>\n\n <modus-wc-radio\n label=\"Option 1\"\n name=\"radio-group-demo\"\n input-id=\"option1\"\n ?disabled=${args.disabled}\n size=${ifDefined(args.size)}\n .value=${true}\n @inputChange=${(e: CustomEvent) => {\n // In a real app, you would update your state management here\n console.log('Selected:', e.target);\n }}\n ></modus-wc-radio>\n\n <modus-wc-radio\n label=\"Option 2\"\n name=\"radio-group-demo\"\n input-id=\"option2\"\n ?disabled=${args.disabled}\n size=${ifDefined(args.size)}\n .value=${false}\n @inputChange=${(e: CustomEvent) => {\n console.log('Selected:', e.target);\n }}\n ></modus-wc-radio>\n\n <modus-wc-radio\n label=\"Option 3\"\n name=\"radio-group-demo\"\n input-id=\"option3\"\n ?disabled=${args.disabled}\n size=${ifDefined(args.size)}\n .value=${false}\n @inputChange=${(e: CustomEvent) => {\n console.log('Selected:', e.target);\n }}\n ></modus-wc-radio>\n </fieldset>\n</main>\n `;\n },\n};\n\nexport const ShadowDomParent: Story = {\n render: (args) => {\n // Create a unique shadow host for radio component\n if (!customElements.get('radio-shadow-host')) {\n const RadioShadowHost = createShadowHostClass<RadioArgs>({\n componentTag: 'modus-wc-radio',\n propsMapper: (v: RadioArgs, el: HTMLElement) => {\n const radioEl = el as unknown as {\n customClass: string;\n disabled: boolean;\n inputId: string;\n inputTabIndex: number;\n label: string;\n name: string;\n required: boolean;\n size: string;\n value: boolean;\n };\n radioEl.customClass = v['custom-class'] || '';\n radioEl.disabled = Boolean(v.disabled);\n radioEl.inputId = v['input-id'] || '';\n radioEl.inputTabIndex = v['input-tab-index'] || 0;\n radioEl.label = v.label || '';\n radioEl.name = v.name || '';\n radioEl.required = Boolean(v.required);\n radioEl.size = v.size || 'md';\n radioEl.value = Boolean(v.value);\n },\n });\n customElements.define('radio-shadow-host', RadioShadowHost);\n }\n\n return html`<radio-shadow-host .props=${{ ...args }}></radio-shadow-host>`;\n },\n};\n\nexport const Migration: Story = {\n parameters: {\n docs: {\n description: {\n story: `\n#### Breaking Changes\n\n - In 1.0 input state was maintained by the component. 2.0 components encourage users to follow a controlled\n input model. See the Form Inputs [documentation](/docs/documentation-form-inputs--docs) for\n additional info and examples.\n - Size values have changed from verbose names (\\`small\\`, \\`medium\\`) to abbreviations (\\`xs\\`, \\`sm\\`, \\`md\\`, \\`lg\\`).\n\n#### Prop Mapping\n\n| 1.0 Prop | 2.0 Prop | Notes |\n|---------------------|-------------|----------------------------------------------------- |\n| checked | value | |\n| disabled | disabled | |\n| handle-button-click | | Not carried over |\n| handle-keydown | | Not carried over |\n| id | input-id | |\n| label | label | |\n| name | name | |\n| ref | | Not carried over |\n| size | size | \\`small\\` → \\`sm\\`, \\`medium\\` → \\`md\\` |\n\n#### Event Mapping\n\n| 1.0 Event | 2.0 Event | Notes |\n|-------------|-------------|-----------------------------------------------------|\n| buttonClick | inputChange | Now emits an \\`InputEvent\\` instead of a \\`string\\` |\n `,\n },\n },\n // To hide the actual story rendering and only show docs:\n controls: { disable: true },\n canvas: { disable: true },\n },\n // Simple render function or leave it empty\n render: () => html`<div></div>`,\n};\n"
138
+ }
139
+ }
@@ -0,0 +1,117 @@
1
+ {
2
+ "description": "A rating component that allows users to choose a rating from predefined options",
3
+ "properties": [
4
+ {
5
+ "name": "allowHalf",
6
+ "type": "boolean",
7
+ "description": "Whether to allow half-ratings. Only applies to star and heart variants.",
8
+ "default": "false",
9
+ "mutable": false,
10
+ "end_line": 43
11
+ },
12
+ {
13
+ "name": "count",
14
+ "type": "number",
15
+ "description": "The number of rating items to display",
16
+ "default": "5",
17
+ "mutable": false,
18
+ "end_line": 46
19
+ },
20
+ {
21
+ "name": "customClass",
22
+ "type": "string",
23
+ "description": "Custom CSS class to apply",
24
+ "default": "''",
25
+ "mutable": false,
26
+ "end_line": 49
27
+ },
28
+ {
29
+ "name": "disabled",
30
+ "type": "boolean",
31
+ "description": "Whether the rating component is disabled",
32
+ "default": "false",
33
+ "mutable": false,
34
+ "end_line": 52
35
+ },
36
+ {
37
+ "name": "getAriaLabelText",
38
+ "type": "(ratingValue: number)",
39
+ "description": "Function to provide aria-label text for a given rating-item index",
40
+ "default": "> string = (ratingValue) => `Rating item ${ratingValue}`",
41
+ "mutable": false,
42
+ "end_line": 56
43
+ },
44
+ {
45
+ "name": "size",
46
+ "type": "ModusSize",
47
+ "description": "The size of the rating component",
48
+ "default": "'md'",
49
+ "mutable": false,
50
+ "end_line": 59
51
+ },
52
+ {
53
+ "name": "variant",
54
+ "type": "ModusWcRatingVariant",
55
+ "description": "The variant of the rating scale",
56
+ "default": "'smiley'",
57
+ "mutable": false,
58
+ "end_line": 62
59
+ },
60
+ {
61
+ "name": "value",
62
+ "type": "number",
63
+ "description": "The current value of the rating",
64
+ "default": "0",
65
+ "mutable": true,
66
+ "end_line": 65
67
+ }
68
+ ],
69
+ "events": [
70
+ {
71
+ "name": "ratingChange",
72
+ "detail": "IRatingChange",
73
+ "description": "Event emitted when the rating changes",
74
+ "end_line": 68
75
+ }
76
+ ],
77
+ "methods": [],
78
+ "slots": [],
79
+ "examples": {
80
+ "basic": "<script>\n const myAriaLabelText = (index) => {\n return 'Custom label for rating item ' + index.toString();\n };\n</script>\n<modus-wc-rating\n aria-label=\"Rating scale component\"\n allow-half=${ifDefined(args['allow-half'])}\n count=${args.count}\n custom-class=\"custom-rating-component\"\n disabled=${ifDefined(args.disabled)}\n size=${ifDefined(args.size)}\n value=${ifDefined(args.value)}\n variant=${args.variant}\n .getAriaLabelText=${ariaLabelText}\n></modus-wc-rating>",
81
+ "variations": [],
82
+ "args": {
83
+ "allow-half": "false",
84
+ "count": "5",
85
+ "custom-class": "''",
86
+ "disabled": "false",
87
+ "getAriaLabelText": "(index: number) => `$",
88
+ "size": "'md'",
89
+ "value": "0",
90
+ "variant": "'smiley'"
91
+ },
92
+ "argTypes": {},
93
+ "usage": [],
94
+ "events": [
95
+ "ratingChange"
96
+ ]
97
+ },
98
+ "tag": "modus-wc-rating",
99
+ "storyExample": {
100
+ "template": "<script>\n const myAriaLabelText = (index) => {\n return 'Custom label for rating item ' + index.toString();\n };\n</script>\n<modus-wc-rating\n aria-label=\"Rating scale component\"\n allow-half=${ifDefined(args['allow-half'])}\n count=${args.count}\n custom-class=\"custom-rating-component\"\n disabled=${ifDefined(args.disabled)}\n size=${ifDefined(args.size)}\n value=${ifDefined(args.value)}\n variant=${args.variant}\n .getAriaLabelText=${ariaLabelText}\n></modus-wc-rating>",
101
+ "args": {
102
+ "allow-half": "false",
103
+ "count": "5",
104
+ "custom-class": "''",
105
+ "disabled": "false",
106
+ "getAriaLabelText": "(index: number) => `$",
107
+ "size": "'md'",
108
+ "value": "0",
109
+ "variant": "'smiley'"
110
+ },
111
+ "argTypes": {},
112
+ "events": [
113
+ "ratingChange"
114
+ ],
115
+ "fullContent": "import { withActions } from '@storybook/addon-actions/decorator';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { ModusWcRatingVariant } from './modus-wc-rating';\nimport { createShadowHostClass } from '../../providers/shadow-dom/shadow-host-helper';\n\ninterface RatingArgs {\n 'allow-half'?: boolean;\n count: number;\n 'custom-class'?: string;\n disabled?: boolean;\n getAriaLabelText?: (index: number) => string;\n size?: 'sm' | 'md' | 'lg';\n value?: number;\n variant: ModusWcRatingVariant;\n}\n\nconst meta: Meta<RatingArgs> = {\n title: 'Components/Forms/Rating',\n component: 'modus-wc-rating',\n args: {\n 'allow-half': false,\n count: 5,\n 'custom-class': '',\n disabled: false,\n getAriaLabelText: (index: number) => `${index} rating`,\n size: 'md',\n value: 0,\n variant: 'smiley',\n },\n argTypes: {\n size: {\n control: { type: 'select' },\n options: ['sm', 'md', 'lg'],\n },\n variant: {\n control: { type: 'select' },\n options: ['heart', 'smiley', 'star', 'thumb'],\n },\n },\n decorators: [withActions],\n parameters: {\n actions: {\n handles: ['ratingChange'],\n },\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<RatingArgs>;\n\nexport const Default: Story = {\n render: (args) => html`\n <modus-wc-rating\n aria-label=\"Rating scale component\"\n allow-half=${ifDefined(args['allow-half'])}\n count=${args.count}\n custom-class=${ifDefined(args['custom-class'])}\n disabled=${ifDefined(args.disabled)}\n size=${ifDefined(args.size)}\n value=${ifDefined(args.value)}\n variant=${args.variant}\n .getAriaLabelText=${args.getAriaLabelText}\n ></modus-wc-rating>\n `,\n};\n\nexport const CustomAriaLabels: Story = {\n render: (args) => {\n const ariaLabelText = (index: number) =>\n `Custom label for rating item ${index}`;\n\n // prettier-ignore\n return html`\n<script>\n const myAriaLabelText = (index) => {\n return 'Custom label for rating item ' + index.toString();\n };\n</script>\n<modus-wc-rating\n aria-label=\"Rating scale component\"\n allow-half=${ifDefined(args['allow-half'])}\n count=${args.count}\n custom-class=\"custom-rating-component\"\n disabled=${ifDefined(args.disabled)}\n size=${ifDefined(args.size)}\n value=${ifDefined(args.value)}\n variant=${args.variant}\n .getAriaLabelText=${ariaLabelText}\n></modus-wc-rating>\n `;\n },\n};\n\nexport const CustomColors: Story = {\n // prettier-ignore\n render: (args) => html`\n<style>\n .custom-color-rating-component {\n --modus-wc-rating-item-color: var(--modus-wc-color-yellow-dark);\n }\n</style>\n<modus-wc-rating\n aria-label=\"Rating scale component\"\n allow-half=${ifDefined(args['allow-half'])}\n count=${args.count}\n custom-class=\"custom-color-rating-component\"\n disabled=${ifDefined(args.disabled)}\n size=${ifDefined(args.size)}\n value=\"3\"\n variant=\"star\"\n></modus-wc-rating>\n `,\n};\n\nexport const ShadowDomParent: Story = {\n render: (args) => {\n // Create a unique shadow host for rating component\n if (!customElements.get('rating-shadow-host')) {\n const RatingShadowHost = createShadowHostClass<RatingArgs>({\n componentTag: 'modus-wc-rating',\n propsMapper: (v: RatingArgs, el: HTMLElement) => {\n const ratingEl = el as unknown as {\n allowHalf: boolean;\n count: number;\n customClass: string;\n disabled: boolean;\n getAriaLabelText: (index: number) => string;\n size: string;\n value: number;\n variant: string;\n };\n ratingEl.allowHalf = Boolean(v['allow-half']);\n ratingEl.count = v.count;\n ratingEl.customClass = v['custom-class'] || '';\n ratingEl.disabled = Boolean(v.disabled);\n if (v.getAriaLabelText) {\n ratingEl.getAriaLabelText = v.getAriaLabelText; // Conditional assignment only if provided\n }\n ratingEl.size = v.size || 'md';\n ratingEl.value = v.value || 0;\n ratingEl.variant = v.variant;\n },\n });\n customElements.define('rating-shadow-host', RatingShadowHost);\n }\n\n return html`<rating-shadow-host\n .props=${{ ...args }}\n ></rating-shadow-host>`;\n },\n};\n\nexport const Migration: Story = {\n parameters: {\n docs: {\n description: {\n story: `\n#### Breaking Changes\n\n - In 1.0 input state was maintained by the component. 2.0 components encourage users to follow a controlled\n input model. See the Form Inputs [documentation](/docs/documentation-form-inputs--docs) for\n additional info and examples.\n - Type/variant values have changed from \\`smileys\\` to \\`smiley\\` and \\`thumbs\\` to \\`thumb\\`.\n\n#### Prop Mapping\n\n| 1.0 Prop | 2.0 Prop | Notes |\n|-------------|-------------|------------------------------------------------------|\n| aria-label | aria-label | |\n| disabled | disabled | |\n| type | variant | \\`smileys\\` → \\`smiley\\`, \\`thumbs\\` → \\`thumb\\` |\n\n#### Event Mapping\n\n| 1.0 Event | 2.0 Event | Notes |\n|--------------------|--------------|-----------------------------------------------|\n| sentimentSelection | ratingChange | |\n `,\n },\n },\n controls: { disable: true },\n canvas: { disable: true },\n },\n render: () => html`<div></div>`,\n};\n"
116
+ }
117
+ }
@@ -0,0 +1,159 @@
1
+ {
2
+ "description": "A customizable select component used to pick a value from a list of options",
3
+ "properties": [
4
+ {
5
+ "name": "bordered",
6
+ "type": "boolean",
7
+ "description": "Indicates that the input should have a border.",
8
+ "default": "true",
9
+ "mutable": false,
10
+ "end_line": 39
11
+ },
12
+ {
13
+ "name": "customClass",
14
+ "type": "string",
15
+ "description": "Custom CSS class to apply to the inner div.",
16
+ "default": "''",
17
+ "mutable": false,
18
+ "end_line": 42
19
+ },
20
+ {
21
+ "name": "disabled",
22
+ "type": "boolean",
23
+ "description": "Whether the form control is disabled.",
24
+ "default": "false",
25
+ "mutable": false,
26
+ "end_line": 45
27
+ },
28
+ {
29
+ "name": "feedback",
30
+ "type": "IInputFeedbackProp",
31
+ "description": "Feedback to render below the input.",
32
+ "default": null,
33
+ "mutable": false,
34
+ "end_line": 48
35
+ },
36
+ {
37
+ "name": "inputId",
38
+ "type": "string",
39
+ "description": "The ID of the input element.",
40
+ "default": null,
41
+ "mutable": false,
42
+ "end_line": 51
43
+ },
44
+ {
45
+ "name": "inputTabIndex",
46
+ "type": "number",
47
+ "description": "Determine the control's relative ordering for sequential focus navigation (typically with the Tab key).",
48
+ "default": null,
49
+ "mutable": false,
50
+ "end_line": 54
51
+ },
52
+ {
53
+ "name": "label",
54
+ "type": "string",
55
+ "description": "The text to display within the label.",
56
+ "default": null,
57
+ "mutable": false,
58
+ "end_line": 57
59
+ },
60
+ {
61
+ "name": "name",
62
+ "type": "string",
63
+ "description": "Name of the form control. Submitted with the form as part of a name/value pair.",
64
+ "default": null,
65
+ "mutable": false,
66
+ "end_line": 60
67
+ },
68
+ {
69
+ "name": "options",
70
+ "type": "ISelectOption[]",
71
+ "description": "The options to display in the select dropdown.",
72
+ "default": "[]",
73
+ "mutable": true,
74
+ "end_line": 63
75
+ },
76
+ {
77
+ "name": "required",
78
+ "type": "boolean",
79
+ "description": "A value is required for the form to be submittable.",
80
+ "default": "false",
81
+ "mutable": false,
82
+ "end_line": 66
83
+ },
84
+ {
85
+ "name": "size",
86
+ "type": "ModusSize",
87
+ "description": "The size of the input.",
88
+ "default": "'md'",
89
+ "mutable": false,
90
+ "end_line": 69
91
+ },
92
+ {
93
+ "name": "value",
94
+ "type": "string",
95
+ "description": "The value of the control.",
96
+ "default": "''",
97
+ "mutable": true,
98
+ "end_line": 72
99
+ }
100
+ ],
101
+ "events": [
102
+ {
103
+ "name": "inputBlur",
104
+ "detail": "FocusEvent",
105
+ "description": "Event emitted when the input loses focus.",
106
+ "end_line": 75
107
+ },
108
+ {
109
+ "name": "inputChange",
110
+ "detail": "InputEvent",
111
+ "description": "Event emitted when the input value changes.",
112
+ "end_line": 78
113
+ },
114
+ {
115
+ "name": "inputFocus",
116
+ "detail": "FocusEvent",
117
+ "description": "Event emitted when the input gains focus.",
118
+ "end_line": 81
119
+ }
120
+ ],
121
+ "methods": [],
122
+ "slots": [],
123
+ "examples": {
124
+ "basic": "<select-shadow-host\n .props=${{ ...args }}\n ></select-shadow-host>",
125
+ "variations": [],
126
+ "args": {
127
+ "bordered": "true",
128
+ "disabled": "false",
129
+ "label": "'Label'",
130
+ "size": "'md'",
131
+ "value": "''"
132
+ },
133
+ "argTypes": {},
134
+ "usage": [],
135
+ "events": [
136
+ "inputBlur",
137
+ "inputChange",
138
+ "inputFocus"
139
+ ]
140
+ },
141
+ "tag": "modus-wc-select",
142
+ "storyExample": {
143
+ "template": "<select-shadow-host\n .props=${{ ...args }}\n ></select-shadow-host>",
144
+ "args": {
145
+ "bordered": "true",
146
+ "disabled": "false",
147
+ "label": "'Label'",
148
+ "size": "'md'",
149
+ "value": "''"
150
+ },
151
+ "argTypes": {},
152
+ "events": [
153
+ "inputBlur",
154
+ "inputChange",
155
+ "inputFocus"
156
+ ],
157
+ "fullContent": "import { withActions } from '@storybook/addon-actions/decorator';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { ISelectOption } from './modus-wc-select';\nimport { createShadowHostClass } from '../../providers/shadow-dom/shadow-host-helper';\nimport { IInputFeedbackProp, ModusSize } from '../types';\n\nconst options: ISelectOption[] = [\n { label: 'Option 1', value: '1' },\n { label: 'Option 2', value: '2' },\n { label: 'Option 3', value: '3' },\n];\n\ninterface SelectArgs {\n bordered?: boolean;\n 'custom-class'?: string;\n disabled?: boolean;\n feedback?: IInputFeedbackProp;\n 'input-aria-invalid'?: 'true' | 'false';\n 'input-id'?: string;\n 'input-tab-index'?: number;\n label?: string;\n name?: string;\n options: ISelectOption[];\n required?: boolean;\n size?: ModusSize;\n value: string;\n}\n\nconst meta: Meta<SelectArgs> = {\n title: 'Components/Forms/Select',\n component: 'modus-wc-select',\n args: {\n bordered: true,\n disabled: false,\n label: 'Label',\n options,\n size: 'md',\n value: '',\n },\n argTypes: {\n feedback: {\n description: 'Feedback prop for input components',\n table: {\n type: {\n detail: `\n Interface: IInputFeedbackProp\n Properties:\n - level ('error' | 'info' | 'success' | 'warning'): The feedback level\n - message (string, optional): The feedback message\n `,\n },\n },\n },\n 'input-aria-invalid': {\n control: { type: 'select' },\n options: ['true', 'false'],\n },\n options: {\n description: 'Array of option objects for the select dropdown',\n table: {\n type: {\n detail: `\n Interface: ISelectOption\n Properties:\n - disabled (boolean, optional): Whether the option is disabled and cannot be selected\n - label (string): Display text for the option\n - value (string): The value of the option\n `,\n },\n },\n },\n size: {\n control: { type: 'select' },\n options: ['sm', 'md', 'lg'],\n },\n },\n decorators: [withActions],\n parameters: {\n actions: {\n handles: ['inputBlur', 'inputChange', 'inputFocus'],\n },\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<SelectArgs>;\n\nexport const Default: Story = {\n render: (args) => html`\n <modus-wc-select\n aria-label=\"Select input\"\n ?bordered=${args.bordered}\n custom-class=${ifDefined(args['custom-class'])}\n ?disabled=${args.disabled}\n .feedback=${args.feedback}\n input-aria-invalid=${ifDefined(args['input-aria-invalid'])}\n input-id=${ifDefined(args['input-id'])}\n input-tab-index=${ifDefined(args['input-tab-index'])}\n label=${ifDefined(args.label)}\n name=${ifDefined(args.name)}\n .options=${args.options}\n ?required=${args.required}\n size=${ifDefined(args.size)}\n .value=${args.value}\n ></modus-wc-select>\n <script>\n const options = [\n { label: 'Option 1', value: '1' },\n { label: 'Option 2', value: '2' },\n { label: 'Option 3', value: '3' },\n ];\n // Adding this block to show how to set options via JS\n // const select = document.querySelector('modus-wc-select');\n // select.options = options;\n </script>\n `,\n};\n\nconst errorFeedback: IInputFeedbackProp = {\n level: 'error',\n message: 'Value is required.',\n};\n\nexport const WithErrorFeedback: Story = {\n render: (args) => html`\n <modus-wc-select\n aria-label=\"Select input\"\n .feedback=${errorFeedback}\n id=\"error-select\"\n label=${ifDefined(args.label)}\n .options=${[]}\n ?required=${true}\n .value=${args.value}\n ></modus-wc-select>\n <script>\n // Adding this block to show how to set feedback via JS\n // const select = document.getElementById('error-select');\n // select.feedback = { level: 'error', message: 'Value is required.' };\n </script>\n `,\n};\n\nexport const ShadowDomParent: Story = {\n render: (args) => {\n // Create a unique shadow host for select component\n if (!customElements.get('select-shadow-host')) {\n const SelectShadowHost = createShadowHostClass<SelectArgs>({\n componentTag: 'modus-wc-select',\n propsMapper: (v: SelectArgs, el: HTMLElement) => {\n const selectEl = el as unknown as {\n bordered: boolean;\n customClass: string;\n disabled: boolean;\n feedback: IInputFeedbackProp;\n inputId: string;\n inputTabIndex: number;\n label: string;\n name: string;\n options: ISelectOption[];\n required: boolean;\n size: string;\n value: string;\n };\n selectEl.bordered = Boolean(v.bordered);\n selectEl.customClass = v['custom-class'] || '';\n selectEl.disabled = Boolean(v.disabled);\n selectEl.inputId = v['input-id'] || '';\n selectEl.inputTabIndex = v['input-tab-index'] || 0;\n selectEl.label = v.label || '';\n selectEl.name = v.name || '';\n selectEl.options = v.options;\n selectEl.required = Boolean(v.required);\n selectEl.size = v.size || 'md';\n selectEl.value = v.value;\n },\n });\n customElements.define('select-shadow-host', SelectShadowHost);\n }\n\n return html`<select-shadow-host\n .props=${{ ...args }}\n ></select-shadow-host>`;\n },\n};\n\nexport const Migration: Story = {\n parameters: {\n docs: {\n description: {\n story: `\n#### Breaking Changes\n\n - In 1.0 input state was maintained by the component. 2.0 components encourage users to follow a controlled\n input model. See the Form Inputs [documentation](/docs/documentation-form-inputs--docs) for\n additional info and examples.\n - The options format has changed to use a standardized \\`ISelectOption\\` object array.\n - Size values have changed from verbose names (\\`medium\\`, \\`large\\`) to abbreviations (\\`sm\\`, \\`md\\`, \\`lg\\`).\n\n#### Prop Mapping\n\n| 1.0 Prop | 2.0 Prop | Notes |\n|-----------------------|---------------------|------------------------------------------------------|\n| aria-label | aria-label | |\n| disabled | disabled | |\n| error-text | feedback.message | Use \\`feedback\\` level |\n| helper-text | | Not carried over |\n| label | label | |\n| options | options | Format changed to require array of \\`ISelectOption\\` objects |\n| options-display-prop | | Not carried over |\n| placeholder | | Not carried over |\n| required | required | |\n| size | size | \\`medium\\` → \\`md\\`, \\`large\\` → \\`lg\\` |\n| valid-text | feedback.message | Use \\`feedback\\` level |\n| value | value | |\n\n#### Event Mapping\n\n| 1.0 Event | 2.0 Event | Notes |\n|--------------|-------------|------------------|\n| valueChange | inputChange | |\n| inputBlur | inputBlur | |\n `,\n },\n },\n controls: { disable: true },\n canvas: { disable: true },\n },\n render: () => html`<div></div>`,\n};\n"
158
+ }
159
+ }
@@ -0,0 +1,102 @@
1
+ {
2
+ "description": "A customizable side navigation component for organizing primary navigation and content areas in an application. The component supports a `<slot>` for injecting custom content inside the side navigation panel.",
3
+ "properties": [
4
+ {
5
+ "name": "collapseOnClickOutside",
6
+ "type": "boolean",
7
+ "description": "Whether the side navigation should collapse when clicking outside of it.",
8
+ "default": "true",
9
+ "mutable": false,
10
+ "end_line": 32
11
+ },
12
+ {
13
+ "name": "customClass",
14
+ "type": "string",
15
+ "description": "Custom CSS class to apply to the inner div.",
16
+ "default": "''",
17
+ "mutable": false,
18
+ "end_line": 35
19
+ },
20
+ {
21
+ "name": "expanded",
22
+ "type": "boolean",
23
+ "description": "Whether the side navigation is expanded.",
24
+ "default": "false",
25
+ "mutable": true,
26
+ "end_line": 38
27
+ },
28
+ {
29
+ "name": "maxWidth",
30
+ "type": "string",
31
+ "description": "Maximum width of the side navigation panel in an expanded state.",
32
+ "default": "'256px'",
33
+ "mutable": false,
34
+ "end_line": 41
35
+ },
36
+ {
37
+ "name": "mode",
38
+ "type": "'overlay' | 'push'",
39
+ "description": "Mode to make side navigation either overlay or push the content for the selector specified in targetContent",
40
+ "default": "'overlay'",
41
+ "mutable": false,
42
+ "end_line": 44
43
+ },
44
+ {
45
+ "name": "targetContent",
46
+ "type": "string",
47
+ "description": "(optional) Specify the selector for the page's content for which paddings and margins will be set by side navigation based on the mode.",
48
+ "default": "''",
49
+ "mutable": false,
50
+ "end_line": 47
51
+ }
52
+ ],
53
+ "events": [
54
+ {
55
+ "name": "expandedChange",
56
+ "detail": "boolean",
57
+ "description": "Event emitted when the expanded state changes (expanded/collapsed).",
58
+ "end_line": 50
59
+ }
60
+ ],
61
+ "methods": [],
62
+ "slots": [
63
+ {
64
+ "name": "default",
65
+ "description": "Slot for default content"
66
+ }
67
+ ],
68
+ "examples": {
69
+ "basic": "<style>\n .layout-with-navbar {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n .modus-wc-menu-item-labels {\n padding: 0 16px;\n }\n .navbar {\n box-shadow: none;\n }\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n .side-navigation {\n height: 500px;\n align-self: flex-start;\n position: relative;\n }\n </style>\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n logo=\"/assets/logo.svg\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n >\n <modus-wc-menu size=\"lg\">\n <modus-wc-menu-item label=\"home\" selected>\n <modus-wc-icon slot=\"start-icon\" name=\"home\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"profile\">\n <modus-wc-icon slot=\"start-icon\" name=\"person\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"settings\">\n <modus-wc-icon slot=\"start-icon\" name=\"gears\"></modus-wc-icon>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <p>\n The side navigation of an application provides context through\n accessible menu options and positions a consistent component to\n connect to various pages in the application.\n </p>\n <p>\n The side navigation is a collapsible side content of the site’s\n pages. It is located alongside the page’s primary content. The\n component is designed to add side content to a fullscreen\n application. It is activated through the “hamburger” menu in the\n Navbar.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript.\n // const menuItems = document.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((item) => {\n // item.addEventListener('itemSelect', () => {\n // menuItems.forEach((i) => i.removeAttribute('selected'));\n // item.setAttribute('selected', '');\n // });\n // });\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // const userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // const navbar = document.querySelector('modus-wc-navbar');\n // const sideNav = document.querySelector('modus-wc-side-navigation');\n // navbar.visibility = visibility;\n // navbar.userCard = userCard;\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n </script>",
70
+ "variations": [],
71
+ "args": {
72
+ "collapse-on-click-outside": "true",
73
+ "expanded": "false",
74
+ "max-width": "'256px'",
75
+ "mode": "'push'",
76
+ "target-content": "'.panel-content'"
77
+ },
78
+ "argTypes": {},
79
+ "usage": [],
80
+ "events": [
81
+ "expandedChange",
82
+ "itemSelect"
83
+ ]
84
+ },
85
+ "tag": "modus-wc-side-navigation",
86
+ "storyExample": {
87
+ "template": "<style>\n .layout-with-navbar {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n .modus-wc-menu-item-labels {\n padding: 0 16px;\n }\n .navbar {\n box-shadow: none;\n }\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n .side-navigation {\n height: 500px;\n align-self: flex-start;\n position: relative;\n }\n </style>\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n logo=\"/assets/logo.svg\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n >\n <modus-wc-menu size=\"lg\">\n <modus-wc-menu-item label=\"home\" selected>\n <modus-wc-icon slot=\"start-icon\" name=\"home\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"profile\">\n <modus-wc-icon slot=\"start-icon\" name=\"person\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"settings\">\n <modus-wc-icon slot=\"start-icon\" name=\"gears\"></modus-wc-icon>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <p>\n The side navigation of an application provides context through\n accessible menu options and positions a consistent component to\n connect to various pages in the application.\n </p>\n <p>\n The side navigation is a collapsible side content of the site’s\n pages. It is located alongside the page’s primary content. The\n component is designed to add side content to a fullscreen\n application. It is activated through the “hamburger” menu in the\n Navbar.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript.\n // const menuItems = document.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((item) => {\n // item.addEventListener('itemSelect', () => {\n // menuItems.forEach((i) => i.removeAttribute('selected'));\n // item.setAttribute('selected', '');\n // });\n // });\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // const userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // const navbar = document.querySelector('modus-wc-navbar');\n // const sideNav = document.querySelector('modus-wc-side-navigation');\n // navbar.visibility = visibility;\n // navbar.userCard = userCard;\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n </script>",
88
+ "args": {
89
+ "collapse-on-click-outside": "true",
90
+ "expanded": "false",
91
+ "max-width": "'256px'",
92
+ "mode": "'push'",
93
+ "target-content": "'.panel-content'"
94
+ },
95
+ "argTypes": {},
96
+ "events": [
97
+ "expandedChange",
98
+ "itemSelect"
99
+ ],
100
+ "fullContent": "import { withActions } from '@storybook/addon-actions/decorator';\nimport { Meta, StoryObj } from '@storybook/web-components';\nimport { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\n\ninterface SideNavigationArgs {\n 'custom-class'?: string;\n expanded: boolean;\n 'max-width': string;\n 'collapse-on-click-outside'?: boolean;\n mode: 'overlay' | 'push';\n 'target-content'?: string;\n}\n\nconst meta: Meta<SideNavigationArgs> = {\n title: 'Components/Side Navigation',\n component: 'modus-wc-side-navigation',\n args: {\n 'collapse-on-click-outside': true,\n expanded: false,\n 'max-width': '256px',\n mode: 'push',\n 'target-content': '.panel-content',\n },\n argTypes: {\n 'max-width': {\n control: { type: 'text' },\n description:\n 'Maximum width of the side navigation panel in an expanded state.',\n },\n mode: {\n control: { type: 'select' },\n options: ['overlay', 'push'],\n description: 'Display mode of the side navigation (overlay or push).',\n },\n },\n decorators: [withActions],\n parameters: {\n layout: 'padded',\n actions: {\n handles: ['expandedChange', 'itemSelect'],\n },\n },\n};\n\nexport default meta;\n\ntype Story = StoryObj<SideNavigationArgs>;\n\nexport const Default: Story = {\n render: (args) => {\n const handleMenuOpenChange = (e: CustomEvent) => {\n const eventSource = e.target as HTMLElement;\n const storyContainer = eventSource?.closest('.layout-with-navbar');\n let sideNav: Element | null;\n\n if (storyContainer) {\n sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n } else {\n sideNav = document.querySelector('modus-wc-side-navigation');\n }\n\n if (sideNav) {\n (sideNav as HTMLElement & { expanded: boolean }).expanded = e.detail;\n }\n };\n\n return html`\n <style>\n .layout-with-navbar {\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n .modus-wc-menu-item-labels {\n padding: 0 16px;\n }\n .navbar {\n box-shadow: none;\n }\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n .side-navigation {\n height: 500px;\n align-self: flex-start;\n position: relative;\n }\n </style>\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n logo=\"/assets/logo.svg\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n >\n <modus-wc-menu size=\"lg\">\n <modus-wc-menu-item label=\"home\" selected>\n <modus-wc-icon slot=\"start-icon\" name=\"home\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"profile\">\n <modus-wc-icon slot=\"start-icon\" name=\"person\"></modus-wc-icon>\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"settings\">\n <modus-wc-icon slot=\"start-icon\" name=\"gears\"></modus-wc-icon>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <p>\n The side navigation of an application provides context through\n accessible menu options and positions a consistent component to\n connect to various pages in the application.\n </p>\n <p>\n The side navigation is a collapsible side content of the site’s\n pages. It is located alongside the page’s primary content. The\n component is designed to add side content to a fullscreen\n application. It is activated through the “hamburger” menu in the\n Navbar.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript.\n // const menuItems = document.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((item) => {\n // item.addEventListener('itemSelect', () => {\n // menuItems.forEach((i) => i.removeAttribute('selected'));\n // item.setAttribute('selected', '');\n // });\n // });\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // const userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // const navbar = document.querySelector('modus-wc-navbar');\n // const sideNav = document.querySelector('modus-wc-side-navigation');\n // navbar.visibility = visibility;\n // navbar.userCard = userCard;\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n </script>\n `;\n },\n};\n\nexport const WithSubmenu: Story = {\n render: (args) => {\n const handleMenuOpenChange = (e: CustomEvent) => {\n const eventSource = e.target as HTMLElement;\n const storyContainer = eventSource?.closest('.layout-with-navbar');\n let sideNav: HTMLElement | null;\n\n if (storyContainer) {\n sideNav = storyContainer.querySelector(\n 'modus-wc-side-navigation'\n ) as HTMLElement;\n\n if (sideNav) {\n // Toggle the side nav state (navbar and side nav can be out of sync)\n const sideNavEl = sideNav as HTMLElement & { expanded: boolean };\n sideNavEl.expanded = e.detail;\n }\n }\n };\n\n const handleExpandedChange = (e: CustomEvent) => {\n // Collapse all menu items when side nav closes\n if (!e.detail) {\n const eventSource = e.target as HTMLElement;\n const menuItems = eventSource.querySelectorAll('modus-wc-menu-item');\n menuItems.forEach((menuItem) => {\n const item = menuItem as unknown as {\n hasSubmenu?: boolean;\n collapseSubmenu?: () => Promise<void>;\n };\n if (item.hasSubmenu && typeof item.collapseSubmenu === 'function') {\n void item.collapseSubmenu();\n }\n });\n }\n };\n\n return html`\n <style>\n .layout-with-navbar {\n box-shadow: rgba(36, 35, 45, 0.3) 1px 0 4px;\n display: flex;\n flex-direction: column;\n height: 100%;\n }\n\n .main-content-row {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n\n .panel-content {\n margin-left: 4rem;\n padding: 10px;\n }\n\n .side-navigation {\n align-self: flex-start;\n height: 500px;\n position: relative;\n }\n .flex-right {\n float: right;\n display: flex;\n margin-left: 50px;\n }\n\n .flex-right:hover {\n background-color: unset;\n }\n .flex-right:active {\n background-color: unset !important;\n }\n </style>\n\n <div class=\"layout-with-navbar\">\n <modus-wc-navbar\n app-title=\"Modus App\"\n class=\"navbar\"\n id=\"main-navbar\"\n logo=\"/assets/logo.svg\"\n @mainMenuOpenChange=${handleMenuOpenChange}\n .userCard=${{\n avatarAlt: 'User Avatar',\n avatarSrc:\n 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n email: 'user@trimble.com',\n name: 'Sonic the Hedgehog',\n }}\n .visibility=${{\n ai: true,\n apps: true,\n help: true,\n mainMenu: true,\n notifications: true,\n search: true,\n searchInput: false,\n user: true,\n }}\n style=\"z-index: 2;\"\n ></modus-wc-navbar>\n <div class=\"main-content-row\">\n <modus-wc-side-navigation\n class=\"side-navigation\"\n collapse-on-click-outside=${args['collapse-on-click-outside']}\n custom-class=${ifDefined(args['custom-class'])}\n expanded=${args.expanded}\n id=\"main-side-nav\"\n max-width=${args['max-width']}\n mode=${ifDefined(args.mode)}\n target-content=${ifDefined(args['target-content'])}\n @expandedChange=${handleExpandedChange}\n >\n <modus-wc-menu>\n <li>\n <div class=\"flex-right\">\n <modus-wc-button custom-class=\"menu-icon\" color=\"tertiary\">\n <modus-wc-icon\n name=\"filter\"\n size=\"xs\"\n variant=\"solid\"\n ></modus-wc-icon>\n </modus-wc-button>\n <modus-wc-button custom-class=\"menu-icon\" color=\"tertiary\">\n <modus-wc-icon\n name=\"settings\"\n size=\"xs\"\n variant=\"solid\"\n ></modus-wc-icon>\n </modus-wc-button>\n <modus-wc-button custom-class=\"menu-icon\" color=\"tertiary\">\n <modus-wc-icon\n name=\"more_vertical\"\n size=\"xs\"\n variant=\"solid\"\n ></modus-wc-icon>\n </modus-wc-button>\n </div>\n </li>\n <modus-wc-menu-item\n label=\"Charts\"\n id=\"charts-menu\"\n .hasSubmenu=${true}\n value=\"charts\"\n >\n <modus-wc-icon\n slot=\"start-icon\"\n decorative=\"true\"\n name=\"bar_graph\"\n ></modus-wc-icon>\n <modus-wc-menu .isSubMenu=${true} id=\"charts-submenu\">\n <modus-wc-menu-item label=\"Bar Chart\" value=\"bar-chart\">\n </modus-wc-menu-item>\n <modus-wc-menu-item label=\"Line Chart\" value=\"line-chart\">\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-menu-item>\n\n <modus-wc-menu-item label=\"Calendar\" value=\"calendar\">\n <modus-wc-icon\n slot=\"start-icon\"\n decorative=\"true\"\n name=\"calendar\"\n ></modus-wc-icon>\n </modus-wc-menu-item>\n\n <modus-wc-menu-item\n label=\"Reports\"\n .hasSubmenu=${true}\n id=\"reports-menu\"\n value=\"reports\"\n >\n <modus-wc-icon\n slot=\"start-icon\"\n decorative=\"true\"\n name=\"master_data\"\n ></modus-wc-icon>\n <modus-wc-menu .isSubMenu=${true} id=\"reports-submenu\">\n <modus-wc-menu-item\n label=\"Monthly Report\"\n value=\"monthly-report\"\n >\n </modus-wc-menu-item>\n <modus-wc-menu-item\n label=\"Annual Report\"\n value=\"annual-report\"\n >\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-menu-item>\n </modus-wc-menu>\n </modus-wc-side-navigation>\n <div class=\"panel-content\">\n <div id=\"overview\">\n <h3>Side Navigation with Submenu</h3>\n <p>\n This example demonstrates the side navigation component with\n submenus, allowing for a more organized and hierarchical\n navigation structure.\n </p>\n <p>\n When the side navigation closes, the expandedChange event is\n used to call the collapseSubmenu() method on each menu item.\n This keeps the side navigation component generic while allowing\n the story to coordinate behavior between components.\n </p>\n <p>\n Menu items inside a collapsed side nav cannot expand their\n submenus, ensuring a consistent user experience.\n </p>\n </div>\n </div>\n </div>\n </div>\n <script>\n // const handleMenuOpenChange = (e) => {\n // const eventSource = e.target;\n // const storyContainer = eventSource?.closest('.layout-with-navbar');\n // let sideNav;\n\n // if (storyContainer) {\n // sideNav = storyContainer.querySelector('modus-wc-side-navigation');\n // } else {\n // sideNav = document.querySelector('modus-wc-side-navigation');\n // }\n\n // if (sideNav) {\n // sideNav.expanded = e.detail;\n // }\n // };\n\n // const handleExpandedChange = (e) => {\n // // Collapse all menu items when side nav closes\n // if (!e.detail) {\n // const eventSource = e.target;\n // const menuItems =\n // eventSource.querySelectorAll('modus-wc-menu-item');\n // menuItems.forEach((menuItem) => {\n // if (\n // menuItem.hasSubmenu &&\n // typeof menuItem.collapseSubmenu === 'function'\n // ) {\n // menuItem.collapseSubmenu();\n // }\n // });\n // }\n // };\n // // Adding event listeners and setting properties here as the storybook initially does not load them\n // document.addEventListener('DOMContentLoaded', () => {\n // const navbar = document.querySelector('#main-navbar');\n // const sideNav = document.querySelector('#main-side-nav');\n // const chartsMenu = document.querySelector('#charts-menu');\n // const reportsMenu = document.querySelector('#reports-menu');\n // const chartsSubMenu = document.querySelector('#charts-submenu');\n // const reportsSubMenu = document.querySelector('#reports-submenu');\n\n // if (navbar) {\n // // Set navbar properties\n // navbar.userCard = {\n // avatarAlt: 'User Avatar',\n // avatarSrc:\n // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg',\n // email: 'user@trimble.com',\n // name: 'Sonic the Hedgehog',\n // };\n\n // navbar.visibility = {\n // ai: true,\n // apps: true,\n // help: true,\n // mainMenu: true,\n // notifications: true,\n // search: true,\n // searchInput: false,\n // user: true,\n // };\n\n // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange);\n // }\n\n // if (sideNav) {\n // sideNav.addEventListener('expandedChange', handleExpandedChange);\n // }\n\n // // Set hasSubmenu property for menu items with submenus\n // [chartsMenu, reportsMenu].forEach((menuItem) => {\n // if (menuItem) {\n // menuItem.hasSubmenu = true;\n // }\n // });\n\n // // Set isSubMenu for all submenu elements\n // [chartsSubMenu, reportsSubMenu].forEach((submenu) => {\n // if (submenu) {\n // submenu.isSubMenu = true;\n // }\n // });\n // });\n //\n </script>\n `;\n },\n};\n"
101
+ }
102
+ }