@carbon/ibm-products-web-components 0.0.1-canary.3564

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. package/.storybook/Preview.ts +161 -0
  2. package/.storybook/_container.scss +73 -0
  3. package/.storybook/container.ts +41 -0
  4. package/.storybook/main.ts +25 -0
  5. package/.storybook/manager.ts +13 -0
  6. package/.storybook/preview-head.html +3 -0
  7. package/.storybook/templates/with-layer.scss +38 -0
  8. package/.storybook/templates/with-layer.ts +90 -0
  9. package/.storybook/theme.ts +12 -0
  10. package/LICENSE +201 -0
  11. package/es/components/side-panel/defs.d.ts +39 -0
  12. package/es/components/side-panel/defs.js +51 -0
  13. package/es/components/side-panel/defs.js.map +1 -0
  14. package/es/components/side-panel/index.d.ts +9 -0
  15. package/es/components/side-panel/index.js +9 -0
  16. package/es/components/side-panel/index.js.map +1 -0
  17. package/es/components/side-panel/side-panel.d.ts +539 -0
  18. package/es/components/side-panel/side-panel.js +837 -0
  19. package/es/components/side-panel/side-panel.js.map +1 -0
  20. package/es/components/side-panel/side-panel.scss.js +13 -0
  21. package/es/components/side-panel/side-panel.scss.js.map +1 -0
  22. package/es/components/side-panel/side-panel.test.d.ts +7 -0
  23. package/es/components/side-panel/side-panel.test.js +56 -0
  24. package/es/components/side-panel/side-panel.test.js.map +1 -0
  25. package/es/globals/internal/handle.d.ts +18 -0
  26. package/es/globals/internal/handle.js +8 -0
  27. package/es/globals/internal/handle.js.map +1 -0
  28. package/es/globals/settings.d.ts +15 -0
  29. package/es/globals/settings.js +28 -0
  30. package/es/globals/settings.js.map +1 -0
  31. package/es/index.d.ts +9 -0
  32. package/es/index.js +9 -0
  33. package/es/index.js.map +1 -0
  34. package/lib/components/side-panel/defs.d.ts +39 -0
  35. package/lib/components/side-panel/defs.js +51 -0
  36. package/lib/components/side-panel/defs.js.map +1 -0
  37. package/lib/components/side-panel/index.d.ts +9 -0
  38. package/lib/components/side-panel/side-panel.d.ts +539 -0
  39. package/lib/components/side-panel/side-panel.test.d.ts +7 -0
  40. package/lib/globals/internal/handle.d.ts +18 -0
  41. package/lib/globals/settings.d.ts +15 -0
  42. package/lib/globals/settings.js +32 -0
  43. package/lib/globals/settings.js.map +1 -0
  44. package/lib/index.d.ts +9 -0
  45. package/netlify.toml +8 -0
  46. package/package.json +96 -0
  47. package/scss/components/side-panel/side-panel.scss +302 -0
  48. package/scss/components/side-panel/story-styles.scss +46 -0
  49. package/src/components/side-panel/defs.ts +46 -0
  50. package/src/components/side-panel/index.ts +10 -0
  51. package/src/components/side-panel/side-panel.mdx +106 -0
  52. package/src/components/side-panel/side-panel.scss +302 -0
  53. package/src/components/side-panel/side-panel.stories.ts +525 -0
  54. package/src/components/side-panel/side-panel.test.ts +52 -0
  55. package/src/components/side-panel/side-panel.ts +980 -0
  56. package/src/components/side-panel/story-styles.scss +46 -0
  57. package/src/globals/internal/handle.ts +19 -0
  58. package/src/globals/settings.ts +22 -0
  59. package/src/index.ts +10 -0
  60. package/src/typings/resources.d.ts +26 -0
  61. package/tasks/build.js +165 -0
  62. package/tools/rollup-plugin-icon-paths.js +39 -0
  63. package/tools/rollup-plugin-icons.js +73 -0
  64. package/tools/rollup-plugin-lit-scss.js +89 -0
  65. package/tools/svg-result-carbon-icon-loader.js +28 -0
  66. package/tools/svg-result-carbon-icon.js +42 -0
  67. package/tools/vite-svg-result-carbon-icon-loader.ts +65 -0
  68. package/tsconfig.json +36 -0
  69. package/vite.config.ts +32 -0
@@ -0,0 +1,525 @@
1
+ /**
2
+ * @license
3
+ *
4
+ * Copyright IBM Corp. 2024, 2024
5
+ *
6
+ * This source code is licensed under the Apache-2.0 license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+ import { html } from 'lit';
11
+ import { SIDE_PANEL_SIZE, SIDE_PANEL_PLACEMENT } from './side-panel';
12
+ import './index';
13
+ // import Settings from '@carbon/icons/lib/settings/16';
14
+ // import Trashcan from '@carbon/icons/lib/trash-can/16';
15
+ import { prefix } from '../../globals/settings';
16
+
17
+ import styles from './story-styles.scss?lit';
18
+ import { BUTTON_KIND } from '@carbon/web-components/es/components/button/defs.js';
19
+ import '@carbon/web-components/es/components/button/index.js';
20
+ import '@carbon/web-components/es/components/text-input/index.js';
21
+ import '@carbon/web-components/es/components/textarea/index.js';
22
+
23
+ const toggleButton = () => {
24
+ document.querySelector(`${prefix}-side-panel`)?.toggleAttribute('open');
25
+ };
26
+
27
+ const nextStep = () => {
28
+ document
29
+ .querySelector(`${prefix}-side-panel`)
30
+ ?.setAttribute('current-step', '1');
31
+ };
32
+
33
+ const prevStep = () => {
34
+ document
35
+ .querySelector(`${prefix}-side-panel`)
36
+ ?.setAttribute('current-step', '0');
37
+ };
38
+
39
+ const sizes = {
40
+ // 'default (md)': null,
41
+ [`Extra small size (${SIDE_PANEL_SIZE.EXTRA_SMALL})`]:
42
+ SIDE_PANEL_SIZE.EXTRA_SMALL,
43
+ [`Small size (${SIDE_PANEL_SIZE.SMALL})`]: SIDE_PANEL_SIZE.SMALL,
44
+ [`Medium size (default) (${SIDE_PANEL_SIZE.MEDIUM})`]: SIDE_PANEL_SIZE.MEDIUM,
45
+ [`Large size (${SIDE_PANEL_SIZE.LARGE})`]: SIDE_PANEL_SIZE.LARGE,
46
+ [`Extra Extra Large size (${SIDE_PANEL_SIZE.EXTRA_EXTRA_LARGE})`]:
47
+ SIDE_PANEL_SIZE.EXTRA_EXTRA_LARGE,
48
+ };
49
+
50
+ const placements = {
51
+ // 'default (right)': null,
52
+ left: SIDE_PANEL_PLACEMENT.LEFT,
53
+ 'right (default)': SIDE_PANEL_PLACEMENT.RIGHT,
54
+ };
55
+
56
+ const contents = {
57
+ Empty: 0,
58
+ 'Brief content': 1,
59
+ 'Longer content': 2,
60
+ };
61
+
62
+ const storyPrefix = 'side-panel-stories__';
63
+
64
+ const getContent = (index) => {
65
+ switch (index) {
66
+ case 1:
67
+ return html`
68
+ <style>
69
+ ${styles}
70
+ </style>
71
+ <h5>Section</h5>
72
+ <cds-text-input
73
+ label="Input A"
74
+ id="side-panel-story-text-input-a"
75
+ class="${storyPrefix}text-input"
76
+ ></cds-text-input>
77
+ <cds-text-input
78
+ label="Input B"
79
+ id="side-panel-story-text-input-b"
80
+ class="${storyPrefix}text-input"
81
+ ></cds-text-input>
82
+ `;
83
+ case 2:
84
+ return html`
85
+ <style>
86
+ ${styles}
87
+ </style>
88
+ <h5>Section</h5>
89
+ <div class="${storyPrefix}text-inputs">
90
+ <cds-text-input
91
+ label="Input A"
92
+ id="side-panel-story-text-input-a"
93
+ ></cds-text-input>
94
+ <cds-text-input
95
+ label="Input B"
96
+ id="side-panel-story-text-input-b"
97
+ ></cds-text-input>
98
+ </div>
99
+ <div class="${storyPrefix}text-inputs">
100
+ <cds-text-input
101
+ label="Input C"
102
+ id="side-panel-story-text-input-c"
103
+ ></cds-text-input>
104
+ <cds-text-input
105
+ label="Input D"
106
+ id="side-panel-story-text-input-d"
107
+ ></cds-text-input>
108
+ </div>
109
+ <div class="${storyPrefix}textarea-container">
110
+ <cds-textarea
111
+ label="Notes"
112
+ value="This is a text area"
113
+ ></cds-textarea>
114
+ <cds-textarea
115
+ label="Notes"
116
+ value="This is a text area"
117
+ ></cds-textarea>
118
+ <cds-textarea
119
+ label="Notes"
120
+ value="This is a text area"
121
+ ></cds-textarea>
122
+ </div>
123
+ `;
124
+
125
+ default:
126
+ return null;
127
+ }
128
+ };
129
+
130
+ const labels = {
131
+ 'No label': 0,
132
+ 'Shorter label': 1,
133
+ 'Longer label': 2,
134
+ };
135
+
136
+ const getLabel = (index) => {
137
+ switch (index) {
138
+ case 1:
139
+ return 'A short label';
140
+ case 2:
141
+ return 'A longer label that might go on for a little bit';
142
+ default:
143
+ return '';
144
+ }
145
+ };
146
+
147
+ const subtitles = {
148
+ 'No subtitle': 0,
149
+ 'Short subtitle': 1,
150
+ 'Longer subtitle': 2,
151
+ };
152
+ const getSubTitle = (index) => {
153
+ switch (index) {
154
+ case 1:
155
+ return html`<div slot="subtitle">This is your subtitle slot.</div>`;
156
+ case 2:
157
+ return html`<div slot="subtitle">
158
+ I am your subtitle slot for <strong>adding detail</strong> that can be
159
+ one or two lines.
160
+ </div>`;
161
+ default:
162
+ return null;
163
+ }
164
+ };
165
+
166
+ const actionToolbarItems = {
167
+ 'No action toolbar': 0,
168
+ 'With action toolbar': 1,
169
+ };
170
+
171
+ const getActionToolbarItems = (index) => {
172
+ switch (index) {
173
+ case 1:
174
+ return html`
175
+ <cds-button slot="action-toolbar">Copy</cds-button>
176
+ <cds-button
177
+ slot="action-toolbar"
178
+ aria-label="Settings"
179
+ has-icon-only="true"
180
+ kind=${BUTTON_KIND.GHOST}
181
+ size="sm"
182
+ tooltip-text="Settings"
183
+ >
184
+ </cds-button>
185
+ <cds-button
186
+ slot="action-toolbar"
187
+ aria-label="Delete"
188
+ has-icon-only="true"
189
+ kind=${BUTTON_KIND.GHOST}
190
+ size="sm"
191
+ tooltip-text="Delete"
192
+ >
193
+ </cds-button>
194
+ `;
195
+ default:
196
+ return null;
197
+ }
198
+ };
199
+
200
+ const actionItems = {
201
+ 'No actions': 0,
202
+ 'One button': 1,
203
+ 'Two buttons with ghost': 2,
204
+ 'Two buttons with danger': 3,
205
+ 'Three buttons with ghost': 4,
206
+ 'Three buttons with danger': 5,
207
+ 'Too many buttons': 6,
208
+ };
209
+
210
+ // TODO: There are problems switching this
211
+ const getActionItems = (index) => {
212
+ switch (index) {
213
+ case 1:
214
+ return html`<cds-button key="p" slot="actions" kind=${BUTTON_KIND.PRIMARY}
215
+ >Primary</cds-button
216
+ >`;
217
+ case 2:
218
+ return html`
219
+ <cds-button slot="actions" kind=${BUTTON_KIND.GHOST}>Ghost</cds-button>
220
+ <cds-button slot="actions" kind=${BUTTON_KIND.PRIMARY}
221
+ >Primary</cds-button
222
+ >
223
+ `;
224
+ case 3:
225
+ return html` <cds-button slot="actions" kind=${BUTTON_KIND.DANGER}
226
+ >Danger</cds-button
227
+ >
228
+ <cds-button slot="actions" kind=${BUTTON_KIND.PRIMARY}
229
+ >Primary</cds-button
230
+ >`;
231
+ case 4:
232
+ return html` <cds-button slot="actions" kind=${BUTTON_KIND.GHOST}
233
+ >Ghost</cds-button
234
+ >
235
+ <cds-button slot="actions" kind=${BUTTON_KIND.SECONDARY}
236
+ >Secondary</cds-button
237
+ >
238
+ <cds-button slot="actions" kind=${BUTTON_KIND.PRIMARY}
239
+ >Primary</cds-button
240
+ >`;
241
+ case 5:
242
+ return html`<cds-button
243
+ key="danger"
244
+ slot="actions"
245
+ kind=${BUTTON_KIND.DANGER}
246
+ >Danger</cds-button
247
+ >
248
+ <cds-button key="secondary" slot="actions" kind=${BUTTON_KIND.SECONDARY}
249
+ >Secondary</cds-button
250
+ >
251
+ <cds-button key="primary" slot="actions" kind=${BUTTON_KIND.PRIMARY}
252
+ >Primary</cds-button
253
+ >`;
254
+ case 6:
255
+ return html`<cds-button
256
+ key="danger"
257
+ slot="actions"
258
+ kind=${BUTTON_KIND.DANGER}
259
+ >Danger</cds-button
260
+ >
261
+ <cds-button key="tertiary" slot="actions" kind=${BUTTON_KIND.TERTIARY}
262
+ >Tertiary</cds-button
263
+ >
264
+ <cds-button key="secondary" slot="actions" kind=${BUTTON_KIND.SECONDARY}
265
+ >Secondary</cds-button
266
+ >
267
+ <cds-button key="primary" slot="actions" kind=${BUTTON_KIND.PRIMARY}
268
+ >Primary</cds-button
269
+ >`;
270
+ default:
271
+ return null;
272
+ }
273
+ };
274
+
275
+ const slugs = {
276
+ 'No Slug': 0,
277
+ 'With Slug': 1,
278
+ };
279
+
280
+ const getSlug = (index) => {
281
+ switch (index) {
282
+ case 1:
283
+ return html`<cds-slug size="xs" alignment="bottom-right">
284
+ <div slot="body-text">
285
+ <p class="secondary">AI Explained</p>
286
+ <h1>84%</h1>
287
+ <p class="secondary bold">Confidence score</p>
288
+ <!-- //cspell: disable -->
289
+ <p class="secondary">
290
+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed
291
+ do eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.
292
+ </p>
293
+ <!-- //cspell: enable -->
294
+ <hr />
295
+ <p class="secondary">Model type</p>
296
+ <p class="bold">Foundation model</p>
297
+ </div>
298
+ </cds-slug>`;
299
+ default:
300
+ return null;
301
+ }
302
+ };
303
+
304
+ const defaultTemplate = {
305
+ args: {
306
+ actionItems: getActionItems(1),
307
+ actionToolbarItems: getActionToolbarItems(0),
308
+ animateTitle: true,
309
+ class: 'a-user-class',
310
+ closeIconDescription: 'Close panel',
311
+ condensedActions: false,
312
+ content: getContent(2),
313
+ includeOverlay: true,
314
+ label: getLabel(2),
315
+ open: false,
316
+ placement: SIDE_PANEL_PLACEMENT.RIGHT,
317
+ preventCloseOnClickOutside: false,
318
+ selectorPageContent: '#page-content-selector',
319
+ selectorInitialFocus: '#side-panel-story-text-input-a',
320
+ size: SIDE_PANEL_SIZE.MEDIUM,
321
+ slideIn: false,
322
+ slug: getSlug(0),
323
+ subtitle: getSubTitle(1),
324
+ title:
325
+ 'This title is testing a very long title to see how this behaves with a longer title. It needs to be long enough to trigger overflow when collapsed.',
326
+ },
327
+ argTypes: {
328
+ actionItems: {
329
+ control: 'select',
330
+ description: 'Slot (actions)',
331
+ options: actionItems,
332
+ },
333
+ actionToolbarItems: {
334
+ control: 'select',
335
+ description: 'Slot (action-toolbar)',
336
+ options: actionToolbarItems,
337
+ },
338
+ animateTitle: {
339
+ control: 'boolean',
340
+ description: 'animate-title (Title animates on scroll)',
341
+ },
342
+ class: {
343
+ control: 'text',
344
+ description: 'class',
345
+ },
346
+ closeIconDescription: {
347
+ control: 'text',
348
+ description: 'Close icon description',
349
+ },
350
+ condensedActions: {
351
+ control: 'boolean',
352
+ description: 'condensed-actions',
353
+ },
354
+ content: {
355
+ control: 'select',
356
+ description: 'Slot (default), panel contents',
357
+ options: contents,
358
+ },
359
+ includeOverlay: {
360
+ control: 'boolean',
361
+ description: 'include-overlay',
362
+ },
363
+ label: {
364
+ control: 'select',
365
+ description: 'label',
366
+ options: labels,
367
+ },
368
+ open: {
369
+ control: 'boolean',
370
+ description: 'open',
371
+ },
372
+ placement: {
373
+ control: 'select',
374
+ description: 'placement',
375
+ options: placements,
376
+ },
377
+ preventCloseOnClickOutside: {
378
+ control: 'boolean',
379
+ description: 'prevent-close-on-click-outside',
380
+ },
381
+ selectorPageContent: {
382
+ control: 'text',
383
+ description: 'selector-page-content',
384
+ },
385
+ selectorInitialFocus: {
386
+ control: 'text',
387
+ description: 'selector-initial-focus',
388
+ },
389
+ size: {
390
+ control: 'select',
391
+ description: 'size',
392
+ options: sizes,
393
+ },
394
+ slideIn: {
395
+ control: 'boolean',
396
+ description: 'slide-in',
397
+ },
398
+ slug: {
399
+ control: 'select',
400
+ description: 'slug (AI slug)',
401
+ options: slugs,
402
+ },
403
+ subtitle: {
404
+ control: 'select',
405
+ description: 'Slot (subtitle)',
406
+ options: subtitles,
407
+ },
408
+ title: {
409
+ control: 'text',
410
+ description: 'title',
411
+ },
412
+ },
413
+ render: (args) => {
414
+ return html`
415
+ <div class="${storyPrefix}story-container">
416
+ <div class="${storyPrefix}story-header"></div>
417
+ <div id="page-content-selector" class="${storyPrefix}story-content">
418
+ <cds-button @click="${toggleButton}">Toggle side-panel</cds-button>
419
+ </div>
420
+ </div>
421
+ <c4p-side-panel
422
+ ?animate-title=${args.animateTitle}
423
+ ?condensed-actions=${args.condensedActions}
424
+ current-step="0"
425
+ ?include-overlay=${args.includeOverlay && !args.slideIn}
426
+ selector-initial-focus=${args.selectorInitialFocus}
427
+ label-text="${args.label}"
428
+ ?open=${args.open}
429
+ placement=${args.placement}
430
+ ?prevent-close-on-click-outside=${args.preventCloseOnClickOutside}
431
+ selector-page-content=${args.selectorPageContent}
432
+ size=${args.size}
433
+ ?slide-in=${args.slideIn}
434
+ .title=${args.title}
435
+ @cds-side-panel-navigate-back=${prevStep}
436
+ >
437
+ <!-- default slotted content -->
438
+ ${args.content}
439
+ <cds-button @click="${nextStep}">Step two</cds-button>
440
+
441
+ <!-- slotted subtitle slotted content -->
442
+ ${args.subtitle}
443
+
444
+ <!-- slotted action toolbar cds-buttons -->
445
+ ${args.actionToolbarItems}
446
+
447
+ <!-- slotted action items cds-buttons -->
448
+ ${args.actionItems}
449
+
450
+ <!-- slotted slug -->
451
+ ${args.slug}
452
+ </c4p-side-panel>
453
+ `;
454
+ },
455
+ };
456
+
457
+ export const SlideOver = {
458
+ ...defaultTemplate,
459
+ };
460
+
461
+ export const SlideIn = {
462
+ ...defaultTemplate,
463
+ args: {
464
+ ...defaultTemplate.args,
465
+ slideIn: true,
466
+ },
467
+ };
468
+
469
+ export const WithActionToolbar = {
470
+ ...defaultTemplate,
471
+ args: {
472
+ ...defaultTemplate.args,
473
+ actionToolbarItems: getActionToolbarItems(1),
474
+ },
475
+ };
476
+
477
+ export const SpecifyElementToHaveFocus = {
478
+ ...defaultTemplate,
479
+ args: {
480
+ ...defaultTemplate.args,
481
+ focusSelector: '#side-panel-story-text-input-a',
482
+ label: getLabel(0),
483
+ },
484
+ argTypes: {
485
+ ...defaultTemplate.argTypes,
486
+ focusSelector: {
487
+ control: 'text',
488
+ description: 'selector-primary-focus',
489
+ },
490
+ },
491
+ };
492
+
493
+ export const WithStaticTitle = {
494
+ ...defaultTemplate,
495
+ args: {
496
+ ...defaultTemplate.args,
497
+ animateTitle: false,
498
+ label: getLabel(0),
499
+ },
500
+ };
501
+
502
+ export const WithStaticTitleAndActionToolbar = {
503
+ ...defaultTemplate,
504
+ args: {
505
+ ...defaultTemplate.args,
506
+ actionToolbarItems: getActionToolbarItems(1),
507
+ animateTitle: false,
508
+ label: getLabel(0),
509
+ },
510
+ };
511
+
512
+ export const WithoutTitle = {
513
+ ...defaultTemplate,
514
+ args: {
515
+ ...defaultTemplate.args,
516
+ label: getLabel(0),
517
+ title: '',
518
+ },
519
+ };
520
+
521
+ const meta = {
522
+ title: 'Experimental/SidePanel',
523
+ };
524
+
525
+ export default meta;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024, 2024
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ vi.mock('@carbon/icons/lib/close/20', () => vi.fn().mockReturnValue({}));
9
+ import { describe, expect, it, vi } from 'vitest';
10
+ import { render, html } from 'lit';
11
+
12
+ const defaultProps = {
13
+ animateTitle: true,
14
+ includeOverlay: true,
15
+ slideIn: false,
16
+ selectorInitialFocus: '',
17
+ label: '',
18
+ open: true,
19
+ placement: 'right',
20
+ preventCloseOnClickOutside: false,
21
+ selectorPageContent: '',
22
+ size: 'md',
23
+ title: 'Side panel title',
24
+ };
25
+
26
+ const template = (props = defaultProps) =>
27
+ html`
28
+ <c4p-side-panel
29
+ ?animate-title=${props.animateTitle}
30
+ ?include-overlay=${props.includeOverlay && !props.slideIn}
31
+ selector-initial-focus=${props.selectorInitialFocus}
32
+ label-text="${props.label}"
33
+ ?open=${props.open}
34
+ placement=${props.placement}
35
+ ?prevent-close-on-click-outside=${props.preventCloseOnClickOutside}
36
+ selector-page-content=${props.selectorPageContent}
37
+ size=${props.size}
38
+ ?slide-in=${props.slideIn}
39
+ .title=${props.title}
40
+ >
41
+ content
42
+ </c4p-side-panel>
43
+ `;
44
+
45
+ describe('c4p-side-panel', () => {
46
+ it('should render a side panel', async () => {
47
+ render(template(), document.body);
48
+ await Promise.resolve();
49
+ const elem = document.body.querySelector('c4p-side-panel' as any);
50
+ expect(elem).toBeDefined();
51
+ });
52
+ });