@warp-ds/elements 2.10.0-next.2 → 2.10.0-next.4

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 (59) hide show
  1. package/dist/custom-elements.json +149 -69
  2. package/dist/docs/combobox/accessibility.md +71 -0
  3. package/dist/docs/combobox/api.md +60 -30
  4. package/dist/docs/combobox/combobox.md +203 -30
  5. package/dist/docs/combobox/examples.md +44 -0
  6. package/dist/docs/combobox/usage.md +28 -0
  7. package/dist/docs/icon/accessibility.md +5 -0
  8. package/dist/docs/icon/api.md +37 -0
  9. package/dist/docs/icon/examples.md +45 -0
  10. package/dist/docs/icon/icon.md +107 -0
  11. package/dist/docs/icon/usage.md +11 -0
  12. package/dist/docs/link/api.md +18 -22
  13. package/dist/docs/link/examples.md +75 -0
  14. package/dist/docs/link/link.md +111 -22
  15. package/dist/docs/link/usage.md +18 -0
  16. package/dist/index.d.ts +443 -171
  17. package/dist/packages/affix/affix.js +3 -3
  18. package/dist/packages/affix/affix.js.map +3 -3
  19. package/dist/packages/alert/alert.js +1 -1
  20. package/dist/packages/alert/alert.js.map +3 -3
  21. package/dist/packages/attention/attention.js.map +3 -3
  22. package/dist/packages/button/button.js.map +2 -2
  23. package/dist/packages/checkbox/checkbox.d.ts +40 -11
  24. package/dist/packages/checkbox/checkbox.js.map +2 -2
  25. package/dist/packages/checkbox-group/checkbox-group.d.ts +30 -5
  26. package/dist/packages/checkbox-group/checkbox-group.js.map +2 -2
  27. package/dist/packages/combobox/combobox.a11y.test.js +24 -0
  28. package/dist/packages/combobox/combobox.d.ts +65 -45
  29. package/dist/packages/combobox/combobox.hydration.test.js +39 -1
  30. package/dist/packages/combobox/combobox.js +13 -13
  31. package/dist/packages/combobox/combobox.js.map +3 -3
  32. package/dist/packages/combobox/combobox.stories.js +28 -15
  33. package/dist/packages/combobox/combobox.test.js +110 -0
  34. package/dist/packages/datepicker/datepicker.js.map +3 -3
  35. package/dist/packages/expandable/expandable.js +2 -2
  36. package/dist/packages/expandable/expandable.js.map +3 -3
  37. package/dist/packages/icon/icon.d.ts +13 -3
  38. package/dist/packages/icon/icon.js +2 -2
  39. package/dist/packages/icon/icon.js.map +3 -3
  40. package/dist/packages/icon/icon.react.stories.d.ts +1 -1
  41. package/dist/packages/icon/react.d.ts +2 -2
  42. package/dist/packages/link/link.d.ts +15 -16
  43. package/dist/packages/link/link.js.map +2 -2
  44. package/dist/packages/modal/modal.d.ts +1 -0
  45. package/dist/packages/modal/modal.js +4 -4
  46. package/dist/packages/modal/modal.js.map +2 -2
  47. package/dist/packages/modal-header/modal-header.js +1 -1
  48. package/dist/packages/modal-header/modal-header.js.map +3 -3
  49. package/dist/packages/pagination/pagination.js.map +3 -3
  50. package/dist/packages/pill/pill.js.map +3 -3
  51. package/dist/packages/select/select.js.map +3 -3
  52. package/dist/packages/step/step.js +1 -1
  53. package/dist/packages/step/step.js.map +3 -3
  54. package/dist/packages/toast/toast.js +3 -3
  55. package/dist/packages/toast/toast.js.map +3 -3
  56. package/dist/packages/toast/toast.stories.d.ts +1 -5
  57. package/dist/packages/toast/toast.stories.js +0 -17
  58. package/dist/web-types.json +129 -72
  59. package/package.json +1 -1
@@ -9,7 +9,11 @@ const meta = {
9
9
  title: 'Forms/Combobox',
10
10
  component: 'w-combobox',
11
11
  render(args) {
12
- return html ` <w-combobox ${spread(prespread(args))} .options="${sampleOptions}"></w-combobox> `;
12
+ return html `
13
+ <w-combobox ${spread(prespread(args))}>
14
+ ${sampleOptionElements}
15
+ </w-combobox>
16
+ `;
13
17
  },
14
18
  parameters: {
15
19
  docs: {
@@ -34,21 +38,32 @@ const sampleOptions = [
34
38
  { value: 'pineapple', label: 'Pineapple' },
35
39
  { value: 'mango', label: 'Mango' },
36
40
  ];
41
+ const sampleOptionElements = html `
42
+ <option value="apple">Apple</option>
43
+ <option value="banana">Banana</option>
44
+ <option value="orange">Orange</option>
45
+ <option value="grape">Grape</option>
46
+ <option value="strawberry">Strawberry</option>
47
+ <option value="pineapple">Pineapple</option>
48
+ <option value="mango">Mango</option>
49
+ `;
37
50
  export const Default = {
38
51
  args: {},
39
- render: () => html ` <w-combobox label="Select a fruit" placeholder="Type to search..." .options="${sampleOptions}"></w-combobox> `,
52
+ render: () => html `
53
+ <w-combobox label="Select a fruit" placeholder="Type to search...">
54
+ ${sampleOptionElements}
55
+ </w-combobox>
56
+ `,
40
57
  };
41
58
  export const WithValue = {
42
59
  args: {
43
- options: sampleOptions,
44
60
  label: 'Select a fruit',
45
61
  placeholder: 'Type to search...',
46
- value: 'Apple',
62
+ value: 'apple',
47
63
  },
48
64
  };
49
65
  export const OpenOnFocus = {
50
66
  args: {
51
- options: sampleOptions,
52
67
  label: 'Select a fruit',
53
68
  placeholder: 'Type to search...',
54
69
  openOnFocus: true,
@@ -56,7 +71,6 @@ export const OpenOnFocus = {
56
71
  };
57
72
  export const WithTextMatching = {
58
73
  args: {
59
- options: sampleOptions,
60
74
  label: 'Select a fruit',
61
75
  placeholder: 'Type to search...',
62
76
  matchTextSegments: true,
@@ -64,7 +78,6 @@ export const WithTextMatching = {
64
78
  };
65
79
  export const Invalid = {
66
80
  args: {
67
- options: sampleOptions,
68
81
  label: 'Select a fruit',
69
82
  placeholder: 'Type to search...',
70
83
  value: 'Invalid fruit',
@@ -74,16 +87,14 @@ export const Invalid = {
74
87
  };
75
88
  export const Disabled = {
76
89
  args: {
77
- options: sampleOptions,
78
90
  label: 'Select a fruit',
79
91
  placeholder: 'Type to search...',
80
- value: 'Apple',
92
+ value: 'apple',
81
93
  disabled: true,
82
94
  },
83
95
  };
84
96
  export const Optional = {
85
97
  args: {
86
- options: sampleOptions,
87
98
  label: 'Select a fruit',
88
99
  placeholder: 'Type to search...',
89
100
  optional: true,
@@ -125,17 +136,19 @@ export const FormSubmission = {
125
136
  name="warp-combo-1"
126
137
  label="Select a fruit (dynamic)"
127
138
  placeholder="Type to search..."
128
- .options="${sampleOptions}"
129
- ></w-combobox>
139
+ >
140
+ ${sampleOptionElements}
141
+ </w-combobox>
130
142
  <br>
131
143
  <w-combobox
132
144
  id="form-submission"
133
145
  name="warp-combo-2"
134
146
  label="Select a fruit (dynamic)"
135
- value="Banana"
147
+ value="banana"
136
148
  placeholder="Type to search..."
137
- .options="${sampleOptions}"
138
- ></w-combobox>
149
+ >
150
+ ${sampleOptionElements}
151
+ </w-combobox>
139
152
  <button type="reset">Reset</button>
140
153
  <button type="submit">Submit</button>
141
154
  </form>
@@ -134,3 +134,113 @@ test('announces suggestion count when opened on focus with empty input', async (
134
134
  const statusText = el.shadowRoot?.querySelector('[role="status"]')?.textContent?.trim();
135
135
  expect(statusText).toBe('3 suggestions');
136
136
  });
137
+ test('renders light-DOM option children in the generated popup', async () => {
138
+ const component = html `
139
+ <w-combobox data-testid="combobox" open-on-focus>
140
+ <option value="no">Norway</option>
141
+ <option value="se">Sweden</option>
142
+ <option value="dk">Denmark</option>
143
+ </w-combobox>
144
+ `;
145
+ const page = render(component);
146
+ const locator = page.getByTestId('combobox');
147
+ await expect.element(locator).toBeVisible();
148
+ const el = (await locator.element());
149
+ const input = el.shadowRoot?.querySelector('w-textfield')?.shadowRoot?.querySelector('input');
150
+ input?.focus();
151
+ await new Promise((resolve) => setTimeout(resolve, 100));
152
+ const visibleOptions = el.shadowRoot?.querySelectorAll('[role="listbox"] [role="option"]');
153
+ const optionTexts = Array.from(visibleOptions || []).map((opt) => opt.textContent?.trim());
154
+ expect(optionTexts).toEqual(['Norway', 'Sweden', 'Denmark']);
155
+ });
156
+ test('filters light-DOM options by label attribute and stores option value on select', async () => {
157
+ const component = html `
158
+ <w-combobox data-testid="combobox" open-on-focus>
159
+ <option value="us" label="United States">US</option>
160
+ <option value="uk" label="United Kingdom">UK</option>
161
+ <option value="no">Norway</option>
162
+ </w-combobox>
163
+ `;
164
+ const page = render(component);
165
+ const locator = page.getByTestId('combobox');
166
+ await expect.element(locator).toBeVisible();
167
+ const el = (await locator.element());
168
+ const input = el.shadowRoot?.querySelector('w-textfield')?.shadowRoot?.querySelector('input');
169
+ const selectEvents = [];
170
+ el.addEventListener('select', (event) => selectEvents.push(event));
171
+ input.focus();
172
+ input.value = 'United';
173
+ input.dispatchEvent(new InputEvent('input', { bubbles: true, composed: true }));
174
+ await new Promise((resolve) => setTimeout(resolve, 100));
175
+ const visibleOptions = el.shadowRoot?.querySelectorAll('[role="listbox"] [role="option"]');
176
+ const optionTexts = Array.from(visibleOptions || []).map((opt) => opt.textContent?.trim());
177
+ expect(optionTexts).toEqual(['United States', 'United Kingdom']);
178
+ visibleOptions?.[1]?.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
179
+ await new Promise((resolve) => setTimeout(resolve, 100));
180
+ expect(input.value).toBe('United Kingdom');
181
+ expect(el.value).toBe('uk');
182
+ expect(selectEvents.at(-1)?.detail).toEqual({ value: 'uk' });
183
+ });
184
+ test('uses light-DOM options to display an initial value label', async () => {
185
+ const component = html `
186
+ <w-combobox data-testid="combobox" value="no">
187
+ <option value="se">Sweden</option>
188
+ <option value="no">Norway</option>
189
+ </w-combobox>
190
+ `;
191
+ const page = render(component);
192
+ const locator = page.getByTestId('combobox');
193
+ await expect.element(locator).toBeVisible();
194
+ const el = (await locator.element());
195
+ const input = el.shadowRoot?.querySelector('w-textfield')?.shadowRoot?.querySelector('input');
196
+ expect(input.value).toBe('Norway');
197
+ expect(el.value).toBe('no');
198
+ });
199
+ test('syncs dynamic light-DOM option child changes', async () => {
200
+ const component = html `
201
+ <w-combobox data-testid="combobox" open-on-focus>
202
+ <option value="no">Norway</option>
203
+ <option value="se">Sweden</option>
204
+ </w-combobox>
205
+ `;
206
+ const page = render(component);
207
+ const locator = page.getByTestId('combobox');
208
+ await expect.element(locator).toBeVisible();
209
+ const el = (await locator.element());
210
+ const input = el.shadowRoot?.querySelector('w-textfield')?.shadowRoot?.querySelector('input');
211
+ const denmark = document.createElement('option');
212
+ denmark.value = 'dk';
213
+ denmark.textContent = 'Denmark';
214
+ el.appendChild(denmark);
215
+ const sweden = el.querySelector('option[value="se"]');
216
+ sweden?.remove();
217
+ const norway = el.querySelector('option[value="no"]');
218
+ norway?.setAttribute('value', 'nor');
219
+ if (norway) {
220
+ norway.textContent = 'Norge';
221
+ }
222
+ await new Promise((resolve) => setTimeout(resolve, 100));
223
+ input.focus();
224
+ await new Promise((resolve) => setTimeout(resolve, 100));
225
+ const visibleOptions = el.shadowRoot?.querySelectorAll('[role="listbox"] [role="option"]');
226
+ const optionTexts = Array.from(visibleOptions || []).map((opt) => opt.textContent?.trim());
227
+ expect(optionTexts).toEqual(['Norge', 'Denmark']);
228
+ });
229
+ test('non-empty options property takes precedence over light-DOM option children', async () => {
230
+ const options = [{ value: 'apple', label: 'Apple' }];
231
+ const component = html `
232
+ <w-combobox data-testid="combobox" open-on-focus .options="${options}">
233
+ <option value="banana">Banana</option>
234
+ </w-combobox>
235
+ `;
236
+ const page = render(component);
237
+ const locator = page.getByTestId('combobox');
238
+ await expect.element(locator).toBeVisible();
239
+ const el = (await locator.element());
240
+ const input = el.shadowRoot?.querySelector('w-textfield')?.shadowRoot?.querySelector('input');
241
+ input.focus();
242
+ await new Promise((resolve) => setTimeout(resolve, 100));
243
+ const visibleOptions = el.shadowRoot?.querySelectorAll('[role="listbox"] [role="option"]');
244
+ const optionTexts = Array.from(visibleOptions || []).map((opt) => opt.textContent?.trim());
245
+ expect(optionTexts).toEqual(['Apple']);
246
+ });