@repobit/dex-system-design 0.22.12 → 0.23.2

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 (39) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/package.json +4 -3
  3. package/src/components/Button/button.stories.js +292 -120
  4. package/src/components/accordion/accordion-bg.css.js +7 -2
  5. package/src/components/accordion/accordion-bg.stories.js +268 -449
  6. package/src/components/accordion/accordion.stories.js +259 -265
  7. package/src/components/anchor/anchor.stories.js +160 -159
  8. package/src/components/awards/awards-icon.js +44 -0
  9. package/src/components/awards/awards.css.js +328 -0
  10. package/src/components/awards/awards.js +224 -0
  11. package/src/components/awards/awards.stories.js +447 -0
  12. package/src/components/back/back.stories.js +100 -375
  13. package/src/components/badge/badge.stories.js +241 -129
  14. package/src/components/breadcrumb/breadcrumb.stories.js +218 -219
  15. package/src/components/cards/card.stories.js +174 -622
  16. package/src/components/carousel/carousel.stories.js +196 -225
  17. package/src/components/checkbox/checkbox.stories.js +136 -51
  18. package/src/components/compare/compare.css.js +237 -0
  19. package/src/components/compare/compare.js +253 -0
  20. package/src/components/compare/compare.stories.js +372 -0
  21. package/src/components/display/display.stories.js +91 -297
  22. package/src/components/divider/divider.stories.js +160 -342
  23. package/src/components/footer/footer.stories.js +177 -402
  24. package/src/components/header/header.stories.js +130 -338
  25. package/src/components/heading/heading.js +8 -5
  26. package/src/components/heading/heading.stories.js +162 -471
  27. package/src/components/highlight/highlight.stories.js +153 -38
  28. package/src/components/image/image.stories.js +135 -563
  29. package/src/components/input/custom-form.stories.js +761 -224
  30. package/src/components/link/link.js +29 -12
  31. package/src/components/link/link.stories.js +130 -468
  32. package/src/components/modal/modal.stories.js +174 -28
  33. package/src/components/paragraph/paragraph.css.js +10 -1
  34. package/src/components/paragraph/paragraph.stories.js +85 -410
  35. package/src/components/picture/picture.stories.js +147 -561
  36. package/src/components/radio/radio.stories.js +230 -81
  37. package/src/components/tabs/tabs.stories.js +126 -10
  38. package/src/components/termsOfUse/terms.stories.js +223 -8
  39. package/src/tokens/tokens.js +1 -0
@@ -1,33 +1,173 @@
1
+ // form-inputs.stories.js
1
2
  import { html } from 'lit';
3
+ import '../Button/Button.js';
2
4
  import '../dropdown/dropdown.js';
3
5
  import './input-clipboard.js';
4
6
  import './input.js';
5
-
6
7
  export default {
7
- title: 'Components/Form Inputs and Dropdown',
8
- tags : ['autodocs']
9
- };
8
+ title : 'Components/Form Inputs',
9
+ component : 'bd-custom-input',
10
+ tags : ['autodocs'],
11
+ parameters: {
12
+ docs: {
13
+ description: {
14
+ component: `
15
+ **FormInputs** is a suite of Lit web components providing accessible, themeable form controls for Bitdefender interfaces.
16
+
17
+ It includes:
18
+ - A text / email / password / number / tel **Input** field with validation states
19
+ - A **Dropdown** select with configurable options and sizing
20
+ - An **InputClipboard** field with one-click copy/paste functionality
21
+
22
+ ### States
23
+ | State | Description |
24
+ |---|---|
25
+ | \`default\` | Idle, no interaction |
26
+ | \`focused\` | Active keyboard / pointer focus |
27
+ | \`invalid\` | Failed validation — red border + helper text |
28
+ | \`validated\` | Passed validation — green border + check icon |
29
+ | \`disabled\` | Non-interactive, visually muted |
30
+
31
+ ### Sizes (\`kind\`)
32
+ | Value | Use case |
33
+ |---|---|
34
+ | \`sm\` | Compact forms, sidebars, modals |
35
+ | \`md\` | Default forms |
36
+ | \`lg\` | Hero / marketing sign-up areas |
37
+
38
+ ### Input Types
39
+ Supports all native HTML input types: \`text\`, \`email\`, \`password\`, \`number\`, \`tel\`.
40
+ `
41
+ }
42
+ }
43
+ },
44
+ argTypes: {
45
+ // ── Input props ──────────────────────────────────────────────────────────
46
+ label: {
47
+ control : 'text',
48
+ description: 'Visible label rendered above the field',
49
+ table : {
50
+ type : { summary: 'string' },
51
+ defaultValue: { summary: 'Nume complet' },
52
+ category : 'Input'
53
+ }
54
+ },
55
+ type: {
56
+ control : { type: 'select' },
57
+ options : ['text', 'email', 'password', 'number', 'tel'],
58
+ description: 'Native HTML input type',
59
+ table : {
60
+ type : { summary: "'text' | 'email' | 'password' | 'number' | 'tel'" },
61
+ defaultValue: { summary: 'text' },
62
+ category : 'Input'
63
+ }
64
+ },
65
+ placeholder: {
66
+ control : 'text',
67
+ description: 'Placeholder text shown when the field is empty',
68
+ table : {
69
+ type : { summary: 'string' },
70
+ defaultValue: { summary: 'Introdu numele tău' },
71
+ category : 'Input'
72
+ }
73
+ },
74
+ kind: {
75
+ control : { type: 'select' },
76
+ options : ['sm', 'md', 'lg'],
77
+ description: 'Size variant — controls height, font-size, and padding',
78
+ table : {
79
+ type : { summary: "'sm' | 'md' | 'lg'" },
80
+ defaultValue: { summary: 'sm' },
81
+ category : 'Layout'
82
+ }
83
+ },
84
+ required: {
85
+ control : 'boolean',
86
+ description: 'Marks the field as required and appends an asterisk to the label',
87
+ table : {
88
+ type : { summary: 'boolean' },
89
+ defaultValue: { summary: false },
90
+ category : 'State'
91
+ }
92
+ },
93
+ focused: {
94
+ control : 'boolean',
95
+ description: 'Forces the focus ring on; useful for design review in Storybook',
96
+ table : {
97
+ type : { summary: 'boolean' },
98
+ defaultValue: { summary: false },
99
+ category : 'State'
100
+ }
101
+ },
102
+ invalid: {
103
+ control : 'boolean',
104
+ description: 'Applies the error / invalid styling — red border, warning icon, helper text',
105
+ table : {
106
+ type : { summary: 'boolean' },
107
+ defaultValue: { summary: false },
108
+ category : 'State'
109
+ }
110
+ },
111
+ validated: {
112
+ control : 'boolean',
113
+ description: 'Applies the success / validated styling — green border and check icon',
114
+ table : {
115
+ type : { summary: 'boolean' },
116
+ defaultValue: { summary: false },
117
+ category : 'State'
118
+ }
119
+ },
120
+ disabled: {
121
+ control : 'boolean',
122
+ description: 'Disables the field — prevents interaction and applies muted styles',
123
+ table : {
124
+ type : { summary: 'boolean' },
125
+ defaultValue: { summary: false },
126
+ category : 'State'
127
+ }
128
+ },
129
+ tooltip: {
130
+ control : 'text',
131
+ description: 'Optional tooltip text shown via an info icon adjacent to the label',
132
+ table : {
133
+ type : { summary: 'string' },
134
+ defaultValue: { summary: '' },
135
+ category : 'Input'
136
+ }
137
+ },
138
+
139
+ // ── Dropdown props ───────────────────────────────────────────────────────
140
+ options: {
141
+ control : 'object',
142
+ description: `
143
+ Array of option strings rendered inside the dropdown list.
144
+
145
+ \`\`\`js
146
+ options: ['Small', 'Medium', 'Large']
147
+ \`\`\`
148
+ `,
149
+ table: {
150
+ type : { summary: 'string[]' },
151
+ category: 'Dropdown'
152
+ }
153
+ },
10
154
 
11
- // ---------- INPUT COMPONENT ----------
12
- const InputTemplate = (args) => {
13
- return html`
14
- <bd-custom-input
15
- label="${args.label}"
16
- type="${args.type}"
17
- placeholder="${args.placeholder}"
18
- kind="${args.kind}"
19
- ?required="${args.required}"
20
- ?focused="${args.focused}"
21
- ?invalid="${args.invalid}"
22
- ?validated="${args.validated}"
23
- ?disabled="${args.disabled}"
24
- tooltip="${args.tooltip}"
25
- ></bd-custom-input>
26
- `;
155
+ // ── InputClipboard props ─────────────────────────────────────────────────
156
+ value: {
157
+ control : 'text',
158
+ description: 'Pre-filled value for the clipboard input',
159
+ table : {
160
+ type : { summary: 'string' },
161
+ defaultValue: { summary: '' },
162
+ category : 'InputClipboard'
163
+ }
164
+ }
165
+ }
27
166
  };
28
167
 
29
- export const Input = InputTemplate.bind({});
30
- Input.args = {
168
+ // ─── Default args shared across stories ─────────────────────────────────────
169
+
170
+ const defaultInputArgs = {
31
171
  label : 'Nume complet',
32
172
  type : 'text',
33
173
  placeholder: 'Introdu numele tău',
@@ -40,246 +180,643 @@ Input.args = {
40
180
  tooltip : ''
41
181
  };
42
182
 
43
- Input.argTypes = {
44
- label: { control: 'text' },
45
- type : {
46
- control: { type: 'select' },
47
- options: ['text', 'email', 'password', 'number', 'tel']
48
- },
49
- placeholder: { control: 'text' },
50
- kind : {
51
- control: { type: 'select' },
52
- options: ['sm', 'md', 'lg']
53
- },
54
- required : { control: 'boolean' },
55
- focused : { control: 'boolean' },
56
- invalid : { control: 'boolean' },
57
- validated: { control: 'boolean' },
58
- disabled : { control: 'boolean' },
59
- tooltip : { control: 'text' }
183
+ const defaultDropdownArgs = {
184
+ label : 'Select size',
185
+ kind : 'md',
186
+ options: ['Small', 'Medium', 'Large'],
187
+ tooltip: 'Choose an option'
60
188
  };
61
189
 
62
- Input.parameters = {
63
- docs: {
64
- description: {
65
- component: 'Custom input component with various states and sizes.'
190
+ const defaultClipboardArgs = {
191
+ label : 'Token',
192
+ kind : 'sm',
193
+ placeholder: 'Paste token here',
194
+ value : '',
195
+ disabled : false,
196
+ tooltip : ''
197
+ };
198
+
199
+ // ─── Render helpers ──────────────────────────────────────────────────────────
200
+
201
+ const renderInput = (args) => html`
202
+ <bd-custom-input
203
+ label="${args.label}"
204
+ type="${args.type}"
205
+ placeholder="${args.placeholder}"
206
+ kind="${args.kind}"
207
+ ?required="${args.required}"
208
+ ?focused="${args.focused}"
209
+ ?invalid="${args.invalid}"
210
+ ?validated="${args.validated}"
211
+ ?disabled="${args.disabled}"
212
+ tooltip="${args.tooltip}"
213
+ ></bd-custom-input>
214
+ `;
215
+
216
+ const renderDropdown = (args) => html`
217
+ <bd-custom-dropdown
218
+ label="${args.label}"
219
+ kind="${args.kind}"
220
+ options='${JSON.stringify(args.options)}'
221
+ tooltip="${args.tooltip}"
222
+ ></bd-custom-dropdown>
223
+ `;
224
+
225
+ const renderClipboard = (args) => html`
226
+ <bd-custom-input-clipboard
227
+ label="${args.label}"
228
+ kind="${args.kind}"
229
+ placeholder="${args.placeholder}"
230
+ value="${args.value}"
231
+ ?disabled="${args.disabled}"
232
+ tooltip="${args.tooltip}"
233
+ ></bd-custom-input-clipboard>
234
+ `;
235
+
236
+ // ─── Stories ─────────────────────────────────────────────────────────────────
237
+
238
+ /**
239
+ * Default idle state of the Input component — no validation, no focus.
240
+ */
241
+ export const InputDefault = {
242
+ name : 'Input — Default',
243
+ args : { ...defaultInputArgs },
244
+ render : renderInput,
245
+ parameters: {
246
+ docs: {
247
+ description: {
248
+ story:
249
+ 'The base input in its idle state. No validation, no focus ring. Use the Controls panel to toggle `required`, `focused`, `invalid`, `validated`, and `disabled` states, or switch `type` and `kind`.'
250
+ }
66
251
  }
67
252
  }
68
253
  };
69
254
 
70
- // ---------- DROPDOWN COMPONENT ----------
71
- const DropdownTemplate = (args) => {
72
- return html`
73
- <bd-custom-dropdown
74
- label="${args.label}"
75
- kind="${args.kind}"
76
- options='${JSON.stringify(args.options)}'
77
- tooltip="${args.tooltip}"
78
- ></bd-custom-dropdown>
79
- `;
255
+ /**
256
+ * Input with the focused ring forced on — useful for design review without interaction.
257
+ */
258
+ export const InputFocused = {
259
+ name : 'Input — Focused',
260
+ args : { ...defaultInputArgs, focused: true, label: 'Adresă de email', type: 'email', placeholder: 'you@example.com', kind: 'md' },
261
+ render : renderInput,
262
+ parameters: {
263
+ docs: {
264
+ description: {
265
+ story:
266
+ 'Focus ring applied via the `focused` boolean prop. Demonstrates the active ring style without requiring pointer or keyboard interaction inside the story frame.'
267
+ }
268
+ }
269
+ }
80
270
  };
81
271
 
82
- export const Dropdown = DropdownTemplate.bind({});
83
- Dropdown.args = {
84
- label : 'Select size',
85
- kind : 'md',
86
- options: ['Small', 'Medium', 'Large'],
87
- tooltip: 'Choose an option'
272
+ /**
273
+ * Input in the invalid / error state — red border, warning icon, helper text.
274
+ */
275
+ export const InputInvalid = {
276
+ name : 'Input Invalid',
277
+ args : { ...defaultInputArgs, invalid: true, label: 'Email', type: 'email', placeholder: 'Enter your email', required: true, tooltip: 'Please enter a valid email address' },
278
+ render : renderInput,
279
+ parameters: {
280
+ docs: {
281
+ description: {
282
+ story:
283
+ 'The `invalid` prop activates the error state: red/danger border color, warning icon, and any associated helper or error message text. Combine with `required` for a realistic validation flow.'
284
+ }
285
+ }
286
+ }
88
287
  };
89
288
 
90
- Dropdown.argTypes = {
91
- label: { control: 'text' },
92
- kind : {
93
- control: { type: 'select' },
94
- options: ['sm', 'md', 'lg']
289
+ /**
290
+ * Input in the validated / success state — green border and check icon.
291
+ */
292
+ export const InputValidated = {
293
+ name : 'Input — Validated',
294
+ args : { ...defaultInputArgs, validated: true, label: 'Email', placeholder: 'Enter email', tooltip: 'Looks good!' },
295
+ render : renderInput,
296
+ parameters: {
297
+ docs: {
298
+ description: {
299
+ story:
300
+ 'The `validated` prop activates the success state: green border and a check icon confirming the value passed validation. Typically toggled after a successful async check or on `blur`.'
301
+ }
302
+ }
303
+ }
304
+ };
305
+
306
+ /**
307
+ * Input in the disabled state — non-interactive and visually muted.
308
+ */
309
+ export const InputDisabled = {
310
+ name : 'Input — Disabled',
311
+ args : { ...defaultInputArgs, disabled: true, label: 'Disabled Input', placeholder: "Can't type here", tooltip: 'This field is disabled' },
312
+ render : renderInput,
313
+ parameters: {
314
+ docs: {
315
+ description: {
316
+ story:
317
+ "The `disabled` prop prevents all user interaction. The field is rendered with reduced opacity and a `not-allowed` cursor. The native `<input>` element's disabled attribute is also set."
318
+ }
319
+ }
320
+ }
321
+ };
322
+
323
+ /**
324
+ * All three size variants of the Input rendered for side-by-side comparison.
325
+ */
326
+ export const InputSizes = {
327
+ name : 'Input — All Sizes',
328
+ render: () => html`
329
+ <div style="display: grid; gap: 1.5rem; max-width: 420px; margin: 2rem auto;">
330
+ <bd-custom-input label="Small (sm)" placeholder="sm variant" kind="sm"></bd-custom-input>
331
+ <bd-custom-input label="Medium (md)" placeholder="md variant" kind="md"></bd-custom-input>
332
+ <bd-custom-input label="Large (lg)" placeholder="lg variant" kind="lg"></bd-custom-input>
333
+ </div>
334
+ `,
335
+ parameters: {
336
+ docs: {
337
+ description: {
338
+ story:
339
+ 'Side-by-side comparison of all three `kind` values: `sm`, `md`, and `lg`. Height, font-size, and internal padding scale proportionally.'
340
+ }
341
+ }
342
+ }
343
+ };
344
+
345
+ /**
346
+ * All five input types rendered together.
347
+ */
348
+ export const InputTypes = {
349
+ name : 'Input — All Types',
350
+ render: () => html`
351
+ <div style="display: grid; gap: 1.5rem; max-width: 420px; margin: 2rem auto;">
352
+ <bd-custom-input label="Text" type="text" placeholder="Plain text" kind="sm"></bd-custom-input>
353
+ <bd-custom-input label="Email" type="email" placeholder="you@example.com" kind="sm"></bd-custom-input>
354
+ <bd-custom-input label="Password" type="password" placeholder="••••••••" kind="sm"></bd-custom-input>
355
+ <bd-custom-input label="Number" type="number" placeholder="0" kind="sm"></bd-custom-input>
356
+ <bd-custom-input label="Tel" type="tel" placeholder="+40 700 000 000" kind="sm"></bd-custom-input>
357
+ </div>
358
+ `,
359
+ parameters: {
360
+ docs: {
361
+ description: {
362
+ story:
363
+ 'One input per supported `type`: `text`, `email`, `password`, `number`, `tel`. Verifies that each type renders without layout regressions and that browser-native affordances (toggle eye, number stepper) are preserved.'
364
+ }
365
+ }
366
+ }
367
+ };
368
+
369
+ // ─── Dropdown Stories ─────────────────────────────────────────────────────────
370
+
371
+ /**
372
+ * Default Dropdown with three size options.
373
+ */
374
+ export const DropdownDefault = {
375
+ name : 'Dropdown — Default',
376
+ args : { ...defaultDropdownArgs },
377
+ render : renderDropdown,
378
+ parameters: {
379
+ docs: {
380
+ description: {
381
+ story:
382
+ 'Base dropdown in its idle state. The `options` array is serialised to JSON and passed as an attribute. Use the Controls panel to add, remove, or reorder options live.'
383
+ }
384
+ }
385
+ }
386
+ };
387
+
388
+ /**
389
+ * Dropdown with a long options list — verifies scroll behavior.
390
+ */
391
+ export const DropdownLongList = {
392
+ name: 'Dropdown — Long Options List',
393
+ args: {
394
+ ...defaultDropdownArgs,
395
+ label : 'Select country',
396
+ kind : 'sm',
397
+ options: ['Romania', 'Germany', 'Canada', 'Japan', 'Brazil', 'France', 'Spain', 'Italy', 'United States', 'United Kingdom', 'Australia', 'Netherlands'],
398
+ tooltip: 'Choose your country'
95
399
  },
96
- options: { control: 'object' },
97
- tooltip: { control: 'text' }
400
+ render : renderDropdown,
401
+ parameters: {
402
+ docs: {
403
+ description: {
404
+ story:
405
+ 'Twelve options provided — verifies that the dropdown list scrolls or truncates gracefully when the viewport height is limited. The max-height and overflow-y behaviour should activate.'
406
+ }
407
+ }
408
+ }
98
409
  };
99
410
 
100
- Dropdown.parameters = {
101
- docs: {
102
- description: {
103
- component: 'Custom dropdown component with configurable options.'
411
+ /**
412
+ * All three size variants of the Dropdown.
413
+ */
414
+ export const DropdownSizes = {
415
+ name : 'Dropdown — All Sizes',
416
+ render: () => html`
417
+ <div style="display: grid; gap: 1.5rem; max-width: 420px; margin: 2rem auto;">
418
+ <bd-custom-dropdown label="Small (sm)" kind="sm" options='["Option A","Option B","Option C"]'></bd-custom-dropdown>
419
+ <bd-custom-dropdown label="Medium (md)" kind="md" options='["Option A","Option B","Option C"]'></bd-custom-dropdown>
420
+ <bd-custom-dropdown label="Large (lg)" kind="lg" options='["Option A","Option B","Option C"]'></bd-custom-dropdown>
421
+ </div>
422
+ `,
423
+ parameters: {
424
+ docs: {
425
+ description: {
426
+ story:
427
+ 'Side-by-side comparison of `sm`, `md`, and `lg` dropdown variants, matching the Input size spec so they can be used interchangeably within the same form row.'
428
+ }
104
429
  }
105
430
  }
106
431
  };
107
432
 
108
- // ---------- INPUT CLIPBOARD COMPONENT ----------
109
- const InputClipboardTemplate = (args) => {
110
- return html`
111
- <bd-custom-input-clipboard
112
- label="${args.label}"
113
- kind="${args.kind}"
114
- placeholder="${args.placeholder}"
115
- value="${args.value}"
116
- ?disabled="${args.disabled}"
117
- tooltip="${args.tooltip}"
118
- ></bd-custom-input-clipboard>
119
- `;
433
+ // ─── InputClipboard Stories ───────────────────────────────────────────────────
434
+
435
+ /**
436
+ * Default InputClipboard with no pre-filled value.
437
+ */
438
+ export const ClipboardDefault = {
439
+ name : 'InputClipboard — Default',
440
+ args : { ...defaultClipboardArgs },
441
+ render : renderClipboard,
442
+ parameters: {
443
+ docs: {
444
+ description: {
445
+ story:
446
+ 'Base clipboard input with an empty value. Clicking the copy icon while the field is empty should be a no-op or show a subtle "nothing to copy" signal.'
447
+ }
448
+ }
449
+ }
120
450
  };
121
451
 
122
- export const InputClipboard = InputClipboardTemplate.bind({});
123
- InputClipboard.args = {
124
- label : 'Token',
125
- kind : 'sm',
126
- placeholder: 'Paste token here',
127
- value : '',
128
- disabled : false,
129
- tooltip : ''
452
+ /**
453
+ * InputClipboard pre-filled with an API token string.
454
+ */
455
+ export const ClipboardWithValue = {
456
+ name: 'InputClipboard Pre-filled Value',
457
+ args: {
458
+ ...defaultClipboardArgs,
459
+ label : 'API Token',
460
+ value : 'sk-bd-live-4f8a2c1e9b3d7f6a0e5c8b2d4f1a9e7c',
461
+ tooltip: 'Copy your API token to the clipboard'
462
+ },
463
+ render : renderClipboard,
464
+ parameters: {
465
+ docs: {
466
+ description: {
467
+ story:
468
+ 'The `value` prop pre-populates the field with an API token. Clicking the clipboard icon copies the value to the OS clipboard and should toggle a brief success indicator.'
469
+ }
470
+ }
471
+ }
130
472
  };
131
473
 
132
- InputClipboard.argTypes = {
133
- label: { control: 'text' },
134
- kind : {
135
- control: { type: 'select' },
136
- options: ['sm', 'md', 'lg']
474
+ /**
475
+ * InputClipboard in the disabled state.
476
+ */
477
+ export const ClipboardDisabled = {
478
+ name: 'InputClipboard — Disabled',
479
+ args: {
480
+ ...defaultClipboardArgs,
481
+ label : 'Revoked Token',
482
+ value : 'sk-bd-revoked-0000000000000000',
483
+ disabled: true,
484
+ tooltip : 'This token has been revoked'
137
485
  },
138
- placeholder: { control: 'text' },
139
- value : { control: 'text' },
140
- disabled : { control: 'boolean' },
141
- tooltip : { control: 'text' }
486
+ render : renderClipboard,
487
+ parameters: {
488
+ docs: {
489
+ description: {
490
+ story:
491
+ 'Both the text field and the copy button are non-interactive when `disabled` is set. The copy icon should also appear muted to communicate its unavailability.'
492
+ }
493
+ }
494
+ }
142
495
  };
143
496
 
144
- InputClipboard.parameters = {
145
- docs: {
146
- description: {
147
- component: 'Input field with clipboard functionality for easy copy/paste.'
497
+ /**
498
+ * All three size variants of InputClipboard.
499
+ */
500
+ export const ClipboardSizes = {
501
+ name : 'InputClipboard — All Sizes',
502
+ render: () => html`
503
+ <div style="display: grid; gap: 1.5rem; max-width: 420px; margin: 2rem auto;">
504
+ <bd-custom-input-clipboard label="Small (sm)" kind="sm" value="token-sm-example-value"></bd-custom-input-clipboard>
505
+ <bd-custom-input-clipboard label="Medium (md)" kind="md" value="token-md-example-value"></bd-custom-input-clipboard>
506
+ <bd-custom-input-clipboard label="Large (lg)" kind="lg" value="token-lg-example-value"></bd-custom-input-clipboard>
507
+ </div>
508
+ `,
509
+ parameters: {
510
+ docs: {
511
+ description: {
512
+ story:
513
+ 'Size comparison for all three `kind` values of InputClipboard. Ensures the clipboard icon scales proportionally alongside the field height.'
514
+ }
148
515
  }
149
516
  }
150
517
  };
151
518
 
152
- // ---------- SHOWCASE STORIES ----------
153
- export const InputsShowcase = () => html`
154
- <div style="display: grid; gap: 1rem; max-width: 400px; margin: 2rem auto;">
155
- <h3>Input Variants</h3>
156
-
157
- <bd-custom-input
158
- label="Nume complet"
159
- placeholder="Introdu numele tău"
160
- kind="sm"
161
- required
162
- tooltip="Choose a unique username">
163
- </bd-custom-input>
164
-
165
- <bd-custom-input
166
- label="Adresă de email"
167
- type="email"
168
- placeholder="you@example.com"
169
- kind="md"
170
- focused
171
- tooltip="Click to see focus state">
172
- </bd-custom-input>
173
-
174
- <bd-custom-input
175
- label="Email"
176
- type="email"
177
- kind="sm"
178
- placeholder="Enter your email"
179
- required
180
- invalid
181
- tooltip="Please enter a valid email address">
182
- </bd-custom-input>
183
-
184
- <bd-custom-input
185
- label="Email"
186
- kind="sm"
187
- placeholder="Enter email"
188
- tooltip="Looks good!"
189
- validated>
190
- </bd-custom-input>
191
-
192
- <bd-custom-input
193
- label="Disabled Input"
194
- placeholder="Can't type here"
195
- tooltip="This field is disabled"
196
- kind="sm"
197
- disabled>
198
- </bd-custom-input>
199
- </div>
200
- `;
519
+ // ─── Showcase / Combined Stories ─────────────────────────────────────────────
201
520
 
202
- export const DropdownsShowcase = () => html`
203
- <div style="display: grid; gap: 1rem; max-width: 400px; margin: 2rem auto;">
204
- <h3>Dropdown Variants</h3>
205
-
206
- <bd-custom-dropdown
207
- label="Select size"
208
- kind="md"
209
- options='["Small", "Medium", "Large"]'
210
- tooltip="Choose an option">
211
- </bd-custom-dropdown>
212
-
213
- <bd-custom-dropdown
214
- label="Select country"
215
- kind="sm"
216
- options='["Romania", "Germany", "Canada", "Japan", "Brazil"]'
217
- tooltip="Choose an option">
218
- </bd-custom-dropdown>
219
- </div>
220
- `;
521
+ /**
522
+ * All Input states in a single grid — quick visual regression reference.
523
+ */
524
+ export const InputsShowcase = {
525
+ name : 'Showcase — Input States',
526
+ render: () => html`
527
+ <div style="display: grid; gap: 1rem; max-width: 400px; margin: 2rem auto;">
528
+ <h3 style="margin: 0 0 .5rem;">Input Variants</h3>
221
529
 
222
- export const InputClipboardShowcase = () => html`
223
- <div style="display: grid; gap: 1rem; max-width: 400px; margin: 2rem auto;">
224
- <h3>Input Clipboard</h3>
225
-
226
- <bd-custom-input-clipboard
227
- label="Token"
228
- kind="sm"
229
- placeholder="Paste token here">
230
- </bd-custom-input-clipboard>
231
- </div>
232
- `;
530
+ <bd-custom-input
531
+ label="Nume complet"
532
+ placeholder="Introdu numele tău"
533
+ kind="sm"
534
+ required
535
+ tooltip="Choose a unique username">
536
+ </bd-custom-input>
233
537
 
234
- // ---------- COMBINED FORM EXAMPLE ----------
235
- export const FormExample = () => html`
236
- <div style="max-width: 500px; margin: 2rem auto; padding: 2rem; border: 1px solid #e0e0e0; border-radius: 8px;">
237
- <h3 style="margin-top: 0;">Complete Form Example</h3>
238
-
239
- <div style="display: grid; gap: 1.5rem;">
240
- <bd-custom-input
241
- label="Full Name"
242
- placeholder="John Doe"
243
- kind="md"
244
- required>
538
+ <bd-custom-input
539
+ label="Adresă de email"
540
+ type="email"
541
+ placeholder="you@example.com"
542
+ kind="md"
543
+ focused
544
+ tooltip="Click to see focus state">
245
545
  </bd-custom-input>
246
546
 
247
- <bd-custom-input
248
- label="Email Address"
249
- type="email"
250
- placeholder="john@example.com"
251
- kind="md"
252
- required>
547
+ <bd-custom-input
548
+ label="Email"
549
+ type="email"
550
+ kind="sm"
551
+ placeholder="Enter your email"
552
+ required
553
+ invalid
554
+ tooltip="Please enter a valid email address">
253
555
  </bd-custom-input>
254
556
 
255
- <bd-custom-dropdown
256
- label="Country"
257
- kind="md"
258
- options='["Select a country", "United States", "Canada", "United Kingdom", "Germany", "France"]'
259
- required>
557
+ <bd-custom-input
558
+ label="Email"
559
+ kind="sm"
560
+ placeholder="Enter email"
561
+ tooltip="Looks good!"
562
+ validated>
563
+ </bd-custom-input>
564
+
565
+ <bd-custom-input
566
+ label="Disabled Input"
567
+ placeholder="Can't type here"
568
+ tooltip="This field is disabled"
569
+ kind="sm"
570
+ disabled>
571
+ </bd-custom-input>
572
+ </div>
573
+ `,
574
+ parameters: {
575
+ docs: {
576
+ description: {
577
+ story:
578
+ 'All five input states — default, focused, invalid, validated, and disabled — rendered in a single column for quick visual regression testing.'
579
+ }
580
+ }
581
+ }
582
+ };
583
+
584
+ /**
585
+ * All Dropdown variants in a single column.
586
+ */
587
+ export const DropdownsShowcase = {
588
+ name : 'Showcase — Dropdowns',
589
+ render: () => html`
590
+ <div style="display: grid; gap: 1rem; max-width: 400px; margin: 2rem auto;">
591
+ <h3 style="margin: 0 0 .5rem;">Dropdown Variants</h3>
592
+
593
+ <bd-custom-dropdown
594
+ label="Select size"
595
+ kind="md"
596
+ options='["Small", "Medium", "Large"]'
597
+ tooltip="Choose an option">
598
+ </bd-custom-dropdown>
599
+
600
+ <bd-custom-dropdown
601
+ label="Select country"
602
+ kind="sm"
603
+ options='["Romania", "Germany", "Canada", "Japan", "Brazil"]'
604
+ tooltip="Choose an option">
260
605
  </bd-custom-dropdown>
606
+ </div>
607
+ `,
608
+ parameters: {
609
+ docs: {
610
+ description: {
611
+ story:
612
+ 'Two dropdown instances with different `kind` and `options` props. Useful for verifying that option rendering and sizing are consistent across configurations.'
613
+ }
614
+ }
615
+ }
616
+ };
261
617
 
262
- <bd-custom-input-clipboard
263
- label="API Token"
264
- kind="md"
265
- placeholder="Click to paste your token"
266
- tooltip="Copy your API token from your account settings">
618
+ /**
619
+ * All InputClipboard variants in a single column.
620
+ */
621
+ export const InputClipboardShowcase = {
622
+ name : 'Showcase InputClipboard',
623
+ render: () => html`
624
+ <div style="display: grid; gap: 1rem; max-width: 400px; margin: 2rem auto;">
625
+ <h3 style="margin: 0 0 .5rem;">Input Clipboard</h3>
626
+
627
+ <bd-custom-input-clipboard
628
+ label="Token"
629
+ kind="sm"
630
+ placeholder="Paste token here">
267
631
  </bd-custom-input-clipboard>
268
632
 
269
- <div style="display: flex; gap: 1rem; margin-top: 1rem;">
270
- <bd-button
271
- label="Submit"
272
- size="md"
273
- kind="primary"
274
- strong>
275
- </bd-button>
276
-
277
- <bd-button
278
- label="Cancel"
279
- size="md"
280
- kind="outline">
281
- </bd-button>
633
+ <bd-custom-input-clipboard
634
+ label="API Token"
635
+ kind="md"
636
+ value="sk-bd-live-4f8a2c1e9b3d7f6a0e5c8b2d4f1a9e7c"
637
+ tooltip="Click the icon to copy">
638
+ </bd-custom-input-clipboard>
639
+ </div>
640
+ `,
641
+ parameters: {
642
+ docs: {
643
+ description: {
644
+ story:
645
+ 'Two clipboard inputs — one empty and one pre-filled — shown together for a quick comparison of empty vs populated states.'
646
+ }
647
+ }
648
+ }
649
+ };
650
+
651
+ /**
652
+ * A complete, realistic sign-up form combining all three components.
653
+ */
654
+ export const FormExample = {
655
+ name : 'Complete Form Example',
656
+ render: () => html`
657
+ <div style="max-width: 500px; margin: 2rem auto; padding: 2rem; border: 1px solid #e0e0e0; border-radius: 8px;">
658
+ <h3 style="margin-top: 0;">Complete Form Example</h3>
659
+
660
+ <div style="display: grid; gap: 1.5rem;">
661
+ <bd-custom-input
662
+ label="Full Name"
663
+ placeholder="John Doe"
664
+ kind="md"
665
+ required>
666
+ </bd-custom-input>
667
+
668
+ <bd-custom-input
669
+ label="Email Address"
670
+ type="email"
671
+ placeholder="john@example.com"
672
+ kind="md"
673
+ required>
674
+ </bd-custom-input>
675
+
676
+ <bd-custom-input
677
+ label="Password"
678
+ type="password"
679
+ placeholder="Min. 8 characters"
680
+ kind="md"
681
+ required
682
+ tooltip="Must contain uppercase, lowercase, number and symbol">
683
+ </bd-custom-input>
684
+
685
+ <bd-custom-dropdown
686
+ label="Country"
687
+ kind="md"
688
+ options='["Select a country", "United States", "Canada", "United Kingdom", "Germany", "France", "Romania"]'>
689
+ </bd-custom-dropdown>
690
+
691
+ <bd-custom-input-clipboard
692
+ label="API Token"
693
+ kind="md"
694
+ placeholder="Click to paste your token"
695
+ tooltip="Copy your API token from your account settings">
696
+ </bd-custom-input-clipboard>
697
+
698
+ <div style="display: flex; gap: 1rem; margin-top: 1rem;">
699
+ <bd-button size="md" kind="primary" strong>Submit</bd-button>
700
+ <bd-button size="md" kind="outline">Cancel</bd-button>
701
+ </div>
282
702
  </div>
283
703
  </div>
284
- </div>
285
- `;
704
+ `,
705
+ parameters: {
706
+ docs: {
707
+ description: {
708
+ story:
709
+ 'A realistic sign-up form that combines all three components — Input (text, email, password), Dropdown, and InputClipboard — along with primary and outline action buttons. Demonstrates how the components compose together in a real-world layout.'
710
+ }
711
+ }
712
+ }
713
+ };
714
+
715
+ /**
716
+ * Mobile viewport (375px) — verifies all components render correctly at narrow width.
717
+ */
718
+ export const MobileForm = {
719
+ name : 'Mobile (375px)',
720
+ render: () => html`
721
+ <div style="padding: 1rem;">
722
+ <bd-custom-input
723
+ label="Full Name"
724
+ placeholder="John Doe"
725
+ kind="sm"
726
+ required>
727
+ </bd-custom-input>
728
+
729
+ <div style="margin-top: 1rem;">
730
+ <bd-custom-input
731
+ label="Email Address"
732
+ type="email"
733
+ placeholder="john@example.com"
734
+ kind="sm"
735
+ required>
736
+ </bd-custom-input>
737
+ </div>
738
+
739
+ <div style="margin-top: 1rem;">
740
+ <bd-custom-dropdown
741
+ label="Country"
742
+ kind="sm"
743
+ options='["Select a country", "United States", "Canada", "Romania"]'>
744
+ </bd-custom-dropdown>
745
+ </div>
746
+
747
+ <div style="margin-top: 1rem;">
748
+ <bd-custom-input-clipboard
749
+ label="API Token"
750
+ kind="sm"
751
+ placeholder="Paste your token">
752
+ </bd-custom-input-clipboard>
753
+ </div>
754
+ </div>
755
+ `,
756
+ parameters: {
757
+ viewport: { defaultViewport: 'mobile1' },
758
+ docs : {
759
+ description: {
760
+ story:
761
+ 'All three components rendered inside a 375px mobile viewport. Verifies that labels, icons, and interactive areas remain touch-friendly and do not overflow at narrow widths.'
762
+ }
763
+ }
764
+ }
765
+ };
766
+
767
+ /**
768
+ * Custom field labels, placeholders and options — demonstrates full content flexibility.
769
+ */
770
+ export const CustomContent = {
771
+ name : 'Custom Content',
772
+ render: () => html`
773
+ <div style="display: grid; gap: 1.5rem; max-width: 420px; margin: 2rem auto;">
774
+ <bd-custom-input
775
+ label="Company Registration Number"
776
+ placeholder="e.g. J40/12345/2024"
777
+ kind="md"
778
+ tooltip="As it appears on your trade registry certificate"
779
+ required>
780
+ </bd-custom-input>
781
+
782
+ <bd-custom-dropdown
783
+ label="Subscription Plan"
784
+ kind="md"
785
+ options='["Starter – Free", "Professional – €9 / mo", "Enterprise – Contact us"]'
786
+ tooltip="You can upgrade or downgrade at any time">
787
+ </bd-custom-dropdown>
788
+
789
+ <bd-custom-input-clipboard
790
+ label="Webhook Secret"
791
+ kind="md"
792
+ value="whsec_live_8d2f4b6a0c3e5f7d9b1a4c6e8f2d0b4a"
793
+ tooltip="Used to verify incoming webhook payloads">
794
+ </bd-custom-input-clipboard>
795
+ </div>
796
+ `,
797
+ parameters: {
798
+ docs: {
799
+ description: {
800
+ story:
801
+ 'All three components configured with domain-specific content. Demonstrates that labels, placeholders, option text, and tooltip copy can be freely customised without affecting layout or behaviour.'
802
+ }
803
+ }
804
+ }
805
+ };
806
+
807
+ /**
808
+ * Playground — all controls fully exposed for interactive exploration.
809
+ */
810
+ export const Playground = {
811
+ name : '🛝 Playground',
812
+ args : { ...defaultInputArgs },
813
+ render : renderInput,
814
+ parameters: {
815
+ docs: {
816
+ description: {
817
+ story:
818
+ 'Fully interactive story wired to the `bd-custom-input` component. Use the **Controls** panel below to modify every prop in real time: label, type, placeholder, kind, required, focused, invalid, validated, disabled, and tooltip.'
819
+ }
820
+ }
821
+ }
822
+ };