@hubspot/cms-component-library 0.1.0-alpha.1

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 (37) hide show
  1. package/README.md +3 -0
  2. package/cli/commands/customize.ts +145 -0
  3. package/cli/commands/help.ts +56 -0
  4. package/cli/commands/version.ts +12 -0
  5. package/cli/index.ts +42 -0
  6. package/cli/tests/commands.test.ts +128 -0
  7. package/cli/tests/get-file.test.ts +82 -0
  8. package/cli/tests/version-integration.test.ts +39 -0
  9. package/cli/utils/cli-metadata.ts +9 -0
  10. package/cli/utils/component-naming.ts +76 -0
  11. package/cli/utils/components.ts +74 -0
  12. package/cli/utils/file-operations.ts +158 -0
  13. package/cli/utils/logging.ts +13 -0
  14. package/cli/utils/prompts.ts +80 -0
  15. package/cli/utils/version.ts +33 -0
  16. package/components/componentLibrary/Button/index.module.scss +9 -0
  17. package/components/componentLibrary/Button/index.tsx +83 -0
  18. package/components/componentLibrary/Button/scaffolds/fields.tsx.template +70 -0
  19. package/components/componentLibrary/Button/scaffolds/index.ts.template +95 -0
  20. package/components/componentLibrary/Heading/index.module.scss +9 -0
  21. package/components/componentLibrary/Heading/index.tsx +34 -0
  22. package/components/componentLibrary/Heading/scaffolds/fields.tsx.template +62 -0
  23. package/components/componentLibrary/Heading/scaffolds/index.ts.template +46 -0
  24. package/components/componentLibrary/index.ts +1 -0
  25. package/components/componentLibrary/styles/_component-base.scss +246 -0
  26. package/components/componentLibrary/types/index.ts +308 -0
  27. package/components/componentLibrary/utils/chainApi/choiceFieldGenerator.tsx +64 -0
  28. package/components/componentLibrary/utils/chainApi/index.ts +115 -0
  29. package/components/componentLibrary/utils/chainApi/labelGenerator.ts +76 -0
  30. package/components/componentLibrary/utils/chainApi/stateManager.ts +178 -0
  31. package/components/componentLibrary/utils/classname.ts +40 -0
  32. package/components/componentLibrary/utils/createConditionalClasses.ts +44 -0
  33. package/components/componentLibrary/utils/createHsclComponent.tsx +167 -0
  34. package/components/componentLibrary/utils/propResolution/createCssVariables.ts +58 -0
  35. package/components/componentLibrary/utils/propResolution/propResolutionUtils.ts +113 -0
  36. package/components/componentLibrary/utils/storybook/standardArgs.ts +607 -0
  37. package/package.json +62 -0
@@ -0,0 +1,113 @@
1
+ import {
2
+ BaseComponentProps,
3
+ BASE_COMPONENT_PROP_KEYS,
4
+ DimensionConfiguration,
5
+ } from '../../types/index.js';
6
+ import { createStateManager } from '../chainApi/stateManager.js';
7
+ import cx from '../classname.js';
8
+
9
+ const isValidDimension = (
10
+ dimension: unknown
11
+ ): dimension is {
12
+ options: Record<string, { props: Record<string, unknown> }>;
13
+ } => {
14
+ return (
15
+ dimension != null &&
16
+ typeof dimension === 'object' &&
17
+ 'options' in dimension &&
18
+ dimension.options != null
19
+ );
20
+ };
21
+
22
+ const getSelectedDimensionProps = (
23
+ dimension: { options: Record<string, { props: Record<string, unknown> }> },
24
+ selectedValue: string
25
+ ): Record<string, unknown> | null => {
26
+ const selectedOption = dimension.options[selectedValue];
27
+ return selectedOption?.props || null;
28
+ };
29
+
30
+ const MergeDimensionProp = (
31
+ dimensionProps: Record<string, unknown>,
32
+ passedProps: Record<string, unknown>
33
+ ): Record<string, unknown> => {
34
+ const {
35
+ className: dimensionClassName,
36
+ style: dimensionStyle,
37
+ ...dimensionRest
38
+ } = dimensionProps;
39
+ const mergedProps = { ...passedProps, ...dimensionRest };
40
+
41
+ if (dimensionClassName) {
42
+ mergedProps.className = cx(dimensionClassName, passedProps.className);
43
+ } else if (dimensionStyle) {
44
+ mergedProps.style = {
45
+ ...(dimensionStyle as React.CSSProperties),
46
+ ...(passedProps.style as React.CSSProperties),
47
+ };
48
+ }
49
+
50
+ return mergedProps;
51
+ };
52
+
53
+ export const extractDimensionPropsFromConfig = <ExistingPropsShape>(
54
+ config: DimensionConfiguration,
55
+ allProps: ExistingPropsShape
56
+ ): Record<string, unknown> => {
57
+ let dimensionProps: Record<string, unknown> = {};
58
+
59
+ for (const [dimensionKey, dimension] of Object.entries(config)) {
60
+ if (!isValidDimension(dimension)) {
61
+ continue;
62
+ }
63
+
64
+ const selectedValue = allProps[dimensionKey] as string;
65
+ if (!selectedValue) {
66
+ continue;
67
+ }
68
+
69
+ const selectedProps = getSelectedDimensionProps(dimension, selectedValue);
70
+ if (selectedProps) {
71
+ dimensionProps = MergeDimensionProp(selectedProps, dimensionProps);
72
+ }
73
+ }
74
+
75
+ return dimensionProps;
76
+ };
77
+
78
+ export const separateAllPropTypes = <ExistingPropsShape>(
79
+ allProps: ExistingPropsShape & Record<string, unknown>
80
+ ) => {
81
+ const baseResolvedProps: Partial<BaseComponentProps> = {};
82
+ const remainingProps: Record<string, unknown> = {};
83
+
84
+ for (const [propKey, propValue] of Object.entries(allProps)) {
85
+ if (BASE_COMPONENT_PROP_KEYS.has(propKey as keyof BaseComponentProps)) {
86
+ // If prop is custom to component or unknown just add to kitchen sink props (remainingProps)
87
+ baseResolvedProps[propKey] = propValue;
88
+ continue;
89
+ }
90
+
91
+ remainingProps[propKey] = propValue;
92
+ }
93
+
94
+ return {
95
+ baseResolvedProps,
96
+ remainingProps,
97
+ };
98
+ };
99
+
100
+ export const resolveAllProps = <ExistingPropsShape>(
101
+ stateManager: ReturnType<typeof createStateManager>,
102
+ props: ExistingPropsShape & Record<string, unknown>
103
+ ) => {
104
+ const activeConfiguration = stateManager.getActiveConfiguration();
105
+ const dimensionProps = extractDimensionPropsFromConfig(
106
+ activeConfiguration,
107
+ props
108
+ );
109
+
110
+ const mergedProps = MergeDimensionProp(dimensionProps, props);
111
+
112
+ return separateAllPropTypes(mergedProps);
113
+ };
@@ -0,0 +1,607 @@
1
+ import type { ArgTypes } from '@storybook/react';
2
+
3
+ // =============================================================================
4
+ // Typography Args
5
+ // =============================================================================
6
+
7
+ export const TYPOGRAPHY_ARGS: ArgTypes = {
8
+ // Font Properties
9
+ fontSize: {
10
+ control: { type: 'text' },
11
+ description: 'Font size (e.g., "16px", "1rem", "large")',
12
+ table: { category: 'Typography' },
13
+ },
14
+ fontFamily: {
15
+ control: { type: 'text' },
16
+ description: 'Font family stack',
17
+ table: { category: 'Typography' },
18
+ },
19
+ fontWeight: {
20
+ control: { type: 'select' },
21
+ options: [
22
+ 'lighter',
23
+ 'normal',
24
+ 'bold',
25
+ 'bolder',
26
+ 100,
27
+ 200,
28
+ 300,
29
+ 400,
30
+ 500,
31
+ 600,
32
+ 700,
33
+ 800,
34
+ 900,
35
+ ],
36
+ description: 'Font weight',
37
+ table: { category: 'Typography' },
38
+ },
39
+ fontStyle: {
40
+ control: { type: 'select' },
41
+ options: ['normal', 'italic', 'oblique'],
42
+ description: 'Font style',
43
+ table: { category: 'Typography' },
44
+ },
45
+ lineHeight: {
46
+ control: { type: 'text' },
47
+ description: 'Line height (e.g., "1.5", "24px")',
48
+ table: { category: 'Typography' },
49
+ },
50
+ letterSpacing: {
51
+ control: { type: 'text' },
52
+ description: 'Letter spacing (e.g., "0.1em", "2px")',
53
+ table: { category: 'Typography' },
54
+ },
55
+
56
+ // Text Alignment & Transformation
57
+ textAlign: {
58
+ control: { type: 'select' },
59
+ options: ['left', 'center', 'right', 'justify'],
60
+ description: 'Text alignment',
61
+ table: { category: 'Typography' },
62
+ },
63
+ textTransform: {
64
+ control: { type: 'select' },
65
+ options: ['none', 'uppercase', 'lowercase', 'capitalize'],
66
+ description: 'Text transformation',
67
+ table: { category: 'Typography' },
68
+ },
69
+ textDecoration: {
70
+ control: { type: 'text' },
71
+ description: 'Text decoration (e.g., "underline", "line-through")',
72
+ table: { category: 'Typography' },
73
+ },
74
+
75
+ // Text Flow & Breaking
76
+ whiteSpace: {
77
+ control: { type: 'select' },
78
+ options: [
79
+ 'normal',
80
+ 'nowrap',
81
+ 'pre',
82
+ 'pre-line',
83
+ 'pre-wrap',
84
+ 'break-spaces',
85
+ ],
86
+ description: 'White space handling',
87
+ table: { category: 'Typography' },
88
+ },
89
+ wordBreak: {
90
+ control: { type: 'select' },
91
+ options: ['normal', 'break-all', 'keep-all', 'break-word'],
92
+ description: 'Word breaking behavior',
93
+ table: { category: 'Typography' },
94
+ },
95
+ textWrap: {
96
+ control: { type: 'select' },
97
+ options: ['wrap', 'nowrap', 'balance', 'pretty', 'stable'],
98
+ description: 'Text wrapping behavior',
99
+ table: { category: 'Typography' },
100
+ },
101
+ overflowWrap: {
102
+ control: { type: 'select' },
103
+ options: ['normal', 'anywhere', 'break-word'],
104
+ description: 'Overflow wrapping behavior',
105
+ table: { category: 'Typography' },
106
+ },
107
+ textOverflow: {
108
+ control: { type: 'select' },
109
+ options: ['clip', 'ellipsis'],
110
+ description: 'Text overflow behavior',
111
+ table: { category: 'Typography' },
112
+ },
113
+ wordWrap: {
114
+ control: { type: 'select' },
115
+ options: ['normal', 'break-word', 'anywhere'],
116
+ description: 'Word wrapping behavior',
117
+ table: { category: 'Typography' },
118
+ },
119
+ };
120
+
121
+ // =============================================================================
122
+ // Layout Args
123
+ // =============================================================================
124
+
125
+ export const LAYOUT_ARGS: ArgTypes = {
126
+ // Display
127
+ display: {
128
+ control: { type: 'select' },
129
+ options: [
130
+ 'block',
131
+ 'inline',
132
+ 'inline-block',
133
+ 'flex',
134
+ 'inline-flex',
135
+ 'grid',
136
+ 'none',
137
+ ],
138
+ description: 'Display type',
139
+ table: { category: 'Layout' },
140
+ },
141
+ visibility: {
142
+ control: { type: 'select' },
143
+ options: ['visible', 'hidden', 'collapse'],
144
+ description: 'Element visibility',
145
+ table: { category: 'Layout' },
146
+ },
147
+ overflow: {
148
+ control: { type: 'select' },
149
+ options: ['visible', 'hidden', 'scroll', 'auto'],
150
+ description: 'Overflow behavior',
151
+ table: { category: 'Layout' },
152
+ },
153
+
154
+ // Size
155
+ width: {
156
+ control: { type: 'text' },
157
+ description: 'Width (e.g., "100px", "50%", "auto")',
158
+ table: { category: 'Layout' },
159
+ },
160
+ height: {
161
+ control: { type: 'text' },
162
+ description: 'Height (e.g., "100px", "50vh", "auto")',
163
+ table: { category: 'Layout' },
164
+ },
165
+ minWidth: {
166
+ control: { type: 'text' },
167
+ description: 'Minimum width',
168
+ table: { category: 'Layout' },
169
+ },
170
+ minHeight: {
171
+ control: { type: 'text' },
172
+ description: 'Minimum height',
173
+ table: { category: 'Layout' },
174
+ },
175
+ maxWidth: {
176
+ control: { type: 'text' },
177
+ description: 'Maximum width',
178
+ table: { category: 'Layout' },
179
+ },
180
+ maxHeight: {
181
+ control: { type: 'text' },
182
+ description: 'Maximum height',
183
+ table: { category: 'Layout' },
184
+ },
185
+
186
+ // Media/Object Properties
187
+ objectFit: {
188
+ control: { type: 'select' },
189
+ options: ['fill', 'contain', 'cover', 'none', 'scale-down'],
190
+ description: 'How content fits within container',
191
+ table: { category: 'Layout' },
192
+ },
193
+ aspectRatio: {
194
+ control: { type: 'text' },
195
+ description: 'Aspect ratio (e.g., "16/9", "1", "auto")',
196
+ table: { category: 'Layout' },
197
+ },
198
+ };
199
+
200
+ // =============================================================================
201
+ // Flexbox Args
202
+ // =============================================================================
203
+
204
+ export const FLEXBOX_ARGS: ArgTypes = {
205
+ // Flex Container Properties
206
+ justifyContent: {
207
+ control: { type: 'select' },
208
+ options: [
209
+ 'flex-start',
210
+ 'center',
211
+ 'flex-end',
212
+ 'space-between',
213
+ 'space-around',
214
+ 'space-evenly',
215
+ 'start',
216
+ 'end',
217
+ ],
218
+ description: 'Horizontal alignment of flex items',
219
+ table: { category: 'Flexbox' },
220
+ },
221
+ alignItems: {
222
+ control: { type: 'select' },
223
+ options: [
224
+ 'stretch',
225
+ 'flex-start',
226
+ 'center',
227
+ 'flex-end',
228
+ 'baseline',
229
+ 'start',
230
+ 'end',
231
+ ],
232
+ description: 'Vertical alignment of flex items',
233
+ table: { category: 'Flexbox' },
234
+ },
235
+ flexDirection: {
236
+ control: { type: 'select' },
237
+ options: ['row', 'column'],
238
+ description: 'Direction of flex items',
239
+ table: { category: 'Flexbox' },
240
+ },
241
+ gap: {
242
+ control: { type: 'text' },
243
+ description: 'Gap between flex items (e.g., "16px", "1rem")',
244
+ table: { category: 'Flexbox' },
245
+ },
246
+
247
+ // Flex Item Properties
248
+ alignSelf: {
249
+ control: { type: 'select' },
250
+ options: [
251
+ 'auto',
252
+ 'stretch',
253
+ 'flex-start',
254
+ 'center',
255
+ 'flex-end',
256
+ 'baseline',
257
+ 'start',
258
+ 'end',
259
+ ],
260
+ description: 'Individual item alignment (overrides alignItems)',
261
+ table: { category: 'Flexbox' },
262
+ },
263
+ flex: {
264
+ control: { type: 'number' },
265
+ description: 'Flex grow/shrink/basis shorthand',
266
+ table: { category: 'Flexbox' },
267
+ },
268
+ flexGrow: {
269
+ control: { type: 'number' },
270
+ description: 'How much item should grow',
271
+ table: { category: 'Flexbox' },
272
+ },
273
+ flexShrink: {
274
+ control: { type: 'number' },
275
+ description: 'How much item should shrink',
276
+ table: { category: 'Flexbox' },
277
+ },
278
+ flexBasis: {
279
+ control: { type: 'text' },
280
+ description: 'Initial size before free space is distributed',
281
+ table: { category: 'Flexbox' },
282
+ },
283
+ order: {
284
+ control: { type: 'number' },
285
+ description: 'Order of flex item',
286
+ table: { category: 'Flexbox' },
287
+ },
288
+ };
289
+
290
+ // =============================================================================
291
+ // Spacing Args
292
+ // =============================================================================
293
+
294
+ export const SPACING_ARGS: ArgTypes = {
295
+ // Margin
296
+ marginInline: {
297
+ control: { type: 'text' },
298
+ description: 'Margin shorthand (e.g., "16px", "1rem 2rem")',
299
+ table: { category: 'Spacing' },
300
+ },
301
+ marginBlock: {
302
+ control: { type: 'text' },
303
+ description: 'Bottom margin',
304
+ table: { category: 'Spacing' },
305
+ },
306
+
307
+ // Padding
308
+ paddingInline: {
309
+ control: { type: 'text' },
310
+ description: 'Padding shorthand (e.g., "16px", "1rem 2rem")',
311
+ table: { category: 'Spacing' },
312
+ },
313
+ paddingBlock: {
314
+ control: { type: 'text' },
315
+ description: 'Bottom padding',
316
+ table: { category: 'Spacing' },
317
+ },
318
+ };
319
+
320
+ // =============================================================================
321
+ // Visual Args
322
+ // =============================================================================
323
+
324
+ export const VISUAL_ARGS: ArgTypes = {
325
+ // Colors
326
+ color: {
327
+ control: { type: 'color' },
328
+ description: 'Text color',
329
+ table: { category: 'Visual' },
330
+ },
331
+ background: {
332
+ control: { type: 'text' },
333
+ description: 'Background shorthand (images, gradients, etc.)',
334
+ table: { category: 'Visual' },
335
+ },
336
+
337
+ // Borders
338
+
339
+ borderRadius: {
340
+ control: { type: 'text' },
341
+ description: 'Border radius (e.g., "8px", "50%")',
342
+ table: { category: 'Visual' },
343
+ },
344
+ borderBlockStart: {
345
+ control: { type: 'text' },
346
+ description: 'Border block start (e.g., "2px solid blue")',
347
+ table: { category: 'Visual' },
348
+ },
349
+ borderBlockEnd: {
350
+ control: { type: 'text' },
351
+ description: 'Border block end (e.g., "2px solid blue")',
352
+ table: { category: 'Visual' },
353
+ },
354
+ borderInlineStart: {
355
+ control: { type: 'text' },
356
+ description: 'Border inline start (e.g., "2px solid blue")',
357
+ table: { category: 'Visual' },
358
+ },
359
+ borderInlineEnd: {
360
+ control: { type: 'text' },
361
+ description: 'Border inline end (e.g., "2px solid blue")',
362
+ table: { category: 'Visual' },
363
+ },
364
+ outline: {
365
+ control: { type: 'text' },
366
+ description: 'Outline (e.g., "2px solid blue")',
367
+ table: { category: 'Visual' },
368
+ },
369
+
370
+ // Effects
371
+ opacity: {
372
+ control: { type: 'range', min: 0, max: 1, step: 0.1 },
373
+ description: 'Opacity (0-1)',
374
+ table: { category: 'Visual' },
375
+ },
376
+ boxShadow: {
377
+ control: { type: 'text' },
378
+ description: 'Box shadow (e.g., "0 2px 4px rgba(0,0,0,0.1)")',
379
+ table: { category: 'Visual' },
380
+ },
381
+ cursor: {
382
+ control: { type: 'select' },
383
+ options: [
384
+ 'auto',
385
+ 'pointer',
386
+ 'default',
387
+ 'text',
388
+ 'move',
389
+ 'not-allowed',
390
+ 'grab',
391
+ 'grabbing',
392
+ ],
393
+ description: 'Cursor style',
394
+ table: { category: 'Visual' },
395
+ },
396
+ };
397
+
398
+ // =============================================================================
399
+ // Position Args
400
+ // =============================================================================
401
+
402
+ export const POSITION_ARGS: ArgTypes = {
403
+ position: {
404
+ control: { type: 'select' },
405
+ options: ['static', 'relative', 'absolute', 'fixed', 'sticky'],
406
+ description: 'Position type',
407
+ table: { category: 'Position' },
408
+ },
409
+ top: {
410
+ control: { type: 'text' },
411
+ description: 'Top offset (e.g., "10px", "50%")',
412
+ table: { category: 'Position' },
413
+ },
414
+ right: {
415
+ control: { type: 'text' },
416
+ description: 'Right offset',
417
+ table: { category: 'Position' },
418
+ },
419
+ bottom: {
420
+ control: { type: 'text' },
421
+ description: 'Bottom offset',
422
+ table: { category: 'Position' },
423
+ },
424
+ left: {
425
+ control: { type: 'text' },
426
+ description: 'Left offset',
427
+ table: { category: 'Position' },
428
+ },
429
+ zIndex: {
430
+ control: { type: 'number' },
431
+ description: 'Z-index stacking order',
432
+ table: { category: 'Position' },
433
+ },
434
+ };
435
+
436
+ // =============================================================================
437
+ // Transform Args
438
+ // =============================================================================
439
+
440
+ export const TRANSFORM_ARGS: ArgTypes = {
441
+ transform: {
442
+ control: { type: 'text' },
443
+ description: 'CSS transform (e.g., "rotate(45deg)", "scale(1.2)")',
444
+ table: { category: 'Transform' },
445
+ },
446
+ transformOrigin: {
447
+ control: { type: 'text' },
448
+ description: 'Transform origin (e.g., "center", "top left")',
449
+ table: { category: 'Transform' },
450
+ },
451
+ transition: {
452
+ control: { type: 'text' },
453
+ description: 'Transition shorthand (e.g., "all 0.3s ease")',
454
+ table: { category: 'Transform' },
455
+ },
456
+ transitionProperty: {
457
+ control: { type: 'text' },
458
+ description: 'Properties to transition',
459
+ table: { category: 'Transform' },
460
+ },
461
+ transitionDuration: {
462
+ control: { type: 'text' },
463
+ description: 'Transition duration (e.g., "0.3s", "300ms")',
464
+ table: { category: 'Transform' },
465
+ },
466
+ transitionTimingFunction: {
467
+ control: { type: 'select' },
468
+ options: ['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear'],
469
+ description: 'Transition timing function',
470
+ table: { category: 'Transform' },
471
+ },
472
+ transitionDelay: {
473
+ control: { type: 'text' },
474
+ description: 'Transition delay',
475
+ table: { category: 'Transform' },
476
+ },
477
+ };
478
+
479
+ // =============================================================================
480
+ // Interaction Args
481
+ // =============================================================================
482
+
483
+ export const INTERACTION_ARGS: ArgTypes = {
484
+ pointerEvents: {
485
+ control: { type: 'select' },
486
+ options: [
487
+ 'auto',
488
+ 'none',
489
+ 'visiblePainted',
490
+ 'visibleFill',
491
+ 'visibleStroke',
492
+ 'visible',
493
+ 'painted',
494
+ 'fill',
495
+ 'stroke',
496
+ 'all',
497
+ ],
498
+ description: 'Pointer event handling',
499
+ table: { category: 'Interaction' },
500
+ },
501
+ };
502
+
503
+ // =============================================================================
504
+ // Hover Args
505
+ // =============================================================================
506
+
507
+ export const HOVER_ARGS: ArgTypes = {
508
+ hoverColor: {
509
+ control: { type: 'color' },
510
+ description: 'Text color on hover',
511
+ table: { category: 'Hover' },
512
+ },
513
+ hoverBackground: {
514
+ control: { type: 'text' },
515
+ description: 'Background on hover',
516
+ table: { category: 'Hover' },
517
+ },
518
+ hoverOpacity: {
519
+ control: { type: 'range', min: 0, max: 1, step: 0.1 },
520
+ description: 'Opacity on hover (0-1)',
521
+ table: { category: 'Hover' },
522
+ },
523
+ hoverTransform: {
524
+ control: { type: 'text' },
525
+ description: 'Transform on hover',
526
+ table: { category: 'Hover' },
527
+ },
528
+ hoverBoxShadow: {
529
+ control: { type: 'text' },
530
+ description: 'Box shadow on hover',
531
+ table: { category: 'Hover' },
532
+ },
533
+ hoverBorderBlockStart: {
534
+ control: { type: 'text' },
535
+ description: 'Border block start on hover',
536
+ table: { category: 'Hover' },
537
+ },
538
+ hoverBorderBlockEnd: {
539
+ control: { type: 'text' },
540
+ description: 'Border block end on hover',
541
+ table: { category: 'Hover' },
542
+ },
543
+ hoverBorderInlineStart: {
544
+ control: { type: 'text' },
545
+ description: 'Border inline start on hover',
546
+ table: { category: 'Hover' },
547
+ },
548
+ hoverBorderInlineEnd: {
549
+ control: { type: 'text' },
550
+ description: 'Border inline end on hover',
551
+ table: { category: 'Hover' },
552
+ },
553
+ };
554
+
555
+ // =============================================================================
556
+ // Accessibility Args
557
+ // =============================================================================
558
+
559
+ export const ACCESSIBILITY_ARGS: ArgTypes = {
560
+ role: {
561
+ control: { type: 'text' },
562
+ description: 'ARIA role',
563
+ table: { category: 'Accessibility' },
564
+ },
565
+ 'aria-label': {
566
+ control: { type: 'text' },
567
+ description: 'Accessible label',
568
+ table: { category: 'Accessibility' },
569
+ },
570
+ 'aria-labelledby': {
571
+ control: { type: 'text' },
572
+ description: 'ID of labeling element',
573
+ table: { category: 'Accessibility' },
574
+ },
575
+ 'aria-describedby': {
576
+ control: { type: 'text' },
577
+ description: 'ID of describing element',
578
+ table: { category: 'Accessibility' },
579
+ },
580
+ 'data-test-id': {
581
+ control: { type: 'text' },
582
+ description: 'Test identifier',
583
+ table: { category: 'Accessibility' },
584
+ },
585
+ };
586
+
587
+ // =============================================================================
588
+ // Combined Args Collections
589
+ // =============================================================================
590
+
591
+ export const STANDARD_ARGS: ArgTypes = {
592
+ className: {
593
+ control: { type: 'text' },
594
+ description: 'CSS class names',
595
+ table: { category: 'Basic' },
596
+ },
597
+ ...VISUAL_ARGS,
598
+ ...SPACING_ARGS,
599
+ ...TYPOGRAPHY_ARGS,
600
+ ...HOVER_ARGS,
601
+ ...LAYOUT_ARGS,
602
+ ...FLEXBOX_ARGS,
603
+ ...POSITION_ARGS,
604
+ ...TRANSFORM_ARGS,
605
+ ...INTERACTION_ARGS,
606
+ ...ACCESSIBILITY_ARGS,
607
+ };