@discourser/design-system 0.3.1 → 0.5.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 (36) hide show
  1. package/README.md +12 -4
  2. package/dist/styles.css +5126 -0
  3. package/guidelines/Guidelines.md +92 -41
  4. package/guidelines/components/accordion.md +732 -0
  5. package/guidelines/components/avatar.md +1015 -0
  6. package/guidelines/components/badge.md +728 -0
  7. package/guidelines/components/button.md +75 -40
  8. package/guidelines/components/card.md +84 -25
  9. package/guidelines/components/checkbox.md +671 -0
  10. package/guidelines/components/dialog.md +619 -31
  11. package/guidelines/components/drawer.md +1616 -0
  12. package/guidelines/components/heading.md +576 -0
  13. package/guidelines/components/icon-button.md +92 -37
  14. package/guidelines/components/input-addon.md +685 -0
  15. package/guidelines/components/input-group.md +830 -0
  16. package/guidelines/components/input.md +92 -37
  17. package/guidelines/components/popover.md +1271 -0
  18. package/guidelines/components/progress.md +836 -0
  19. package/guidelines/components/radio-group.md +852 -0
  20. package/guidelines/components/select.md +1662 -0
  21. package/guidelines/components/skeleton.md +802 -0
  22. package/guidelines/components/slider.md +911 -0
  23. package/guidelines/components/spinner.md +783 -0
  24. package/guidelines/components/switch.md +105 -38
  25. package/guidelines/components/tabs.md +1488 -0
  26. package/guidelines/components/textarea.md +495 -0
  27. package/guidelines/components/toast.md +784 -0
  28. package/guidelines/components/tooltip.md +912 -0
  29. package/guidelines/design-tokens/colors.md +309 -72
  30. package/guidelines/design-tokens/elevation.md +615 -45
  31. package/guidelines/design-tokens/spacing.md +654 -74
  32. package/guidelines/design-tokens/typography.md +432 -50
  33. package/guidelines/overview-components.md +60 -8
  34. package/guidelines/overview-imports.md +314 -0
  35. package/guidelines/overview-patterns.md +3852 -0
  36. package/package.json +4 -2
@@ -4,22 +4,24 @@ The design system uses a consistent spacing scale based on an 8px grid system fo
4
4
 
5
5
  ## Spacing Scale
6
6
 
7
- | Token | Value | Usage |
8
- |-------|-------|-------|
9
- | `none` | 0px | No spacing, reset margins/padding |
10
- | `xxs` | 2px | Minimal gaps, icon spacing, borders |
11
- | `xs` | 4px | Very tight spacing, inline elements |
12
- | `sm` | 8px | Small gaps, compact layouts |
13
- | `md` | 16px | Default spacing, most common use |
14
- | `lg` | 24px | Larger sections, comfortable spacing |
15
- | `xl` | 32px | Major sections, page margins |
16
- | `xxl` | 48px | Large sections, page padding |
17
- | `xxxl` | 64px | Maximum spacing, hero sections |
7
+ | Token | Value | Usage |
8
+ | ------ | ----- | ------------------------------------ |
9
+ | `none` | 0px | No spacing, reset margins/padding |
10
+ | `xxs` | 2px | Minimal gaps, icon spacing, borders |
11
+ | `xs` | 4px | Very tight spacing, inline elements |
12
+ | `sm` | 8px | Small gaps, compact layouts |
13
+ | `md` | 16px | Default spacing, most common use |
14
+ | `lg` | 24px | Larger sections, comfortable spacing |
15
+ | `xl` | 32px | Major sections, page margins |
16
+ | `xxl` | 48px | Large sections, page padding |
17
+ | `xxxl` | 64px | Maximum spacing, hero sections |
18
18
 
19
19
  ## Usage Principles
20
20
 
21
21
  ### The 8px Grid
22
+
22
23
  All spacing values (except `xxs` and `xs`) are multiples of 8px. This creates:
24
+
23
25
  - Visual rhythm and consistency
24
26
  - Predictable alignment
25
27
  - Easier mental math for designers and developers
@@ -28,59 +30,62 @@ All spacing values (except `xxs` and `xs`) are multiples of 8px. This creates:
28
30
  ### Common Patterns
29
31
 
30
32
  #### Component Internal Spacing
33
+
31
34
  ```typescript
32
35
  import { css } from '@discourser/design-system/styled-system/css';
33
36
 
34
37
  // ✅ Button padding (handled by component)
35
38
  const button = css({
36
- px: 'md', // 16px horizontal
37
- py: 'sm' // 8px vertical
39
+ px: 'md', // 16px horizontal
40
+ py: 'sm', // 8px vertical
38
41
  });
39
42
 
40
43
  // ✅ Card padding
41
44
  const card = css({
42
- p: 'lg' // 24px all sides
45
+ p: 'lg', // 24px all sides
43
46
  });
44
47
 
45
48
  // ✅ Input field
46
49
  const input = css({
47
- px: 'md', // 16px horizontal
48
- py: 'sm' // 8px vertical
50
+ px: 'md', // 16px horizontal
51
+ py: 'sm', // 8px vertical
49
52
  });
50
53
  ```
51
54
 
52
55
  #### Layout Spacing
56
+
53
57
  ```typescript
54
58
  // ✅ Stack of elements
55
59
  const stack = css({
56
60
  display: 'flex',
57
61
  flexDirection: 'column',
58
- gap: 'md' // 16px between items
62
+ gap: 'md', // 16px between items
59
63
  });
60
64
 
61
65
  // ✅ Grid layout
62
66
  const grid = css({
63
67
  display: 'grid',
64
- gap: 'lg' // 24px between grid items
68
+ gap: 'lg', // 24px between grid items
65
69
  });
66
70
 
67
71
  // ✅ Container with padding
68
72
  const container = css({
69
- px: { base: 'md', lg: 'xl' }, // Responsive: 16px mobile, 32px desktop
70
- py: 'lg' // 24px vertical
73
+ px: { base: 'md', lg: 'xl' }, // Responsive: 16px mobile, 32px desktop
74
+ py: 'lg', // 24px vertical
71
75
  });
72
76
  ```
73
77
 
74
78
  #### Margin Between Sections
79
+
75
80
  ```typescript
76
81
  // ✅ Section spacing
77
82
  const section = css({
78
- mb: 'xxl' // 48px bottom margin
83
+ mb: 'xxl', // 48px bottom margin
79
84
  });
80
85
 
81
86
  // ✅ Page-level spacing
82
87
  const page = css({
83
- p: { base: 'lg', lg: 'xxl' } // 24px mobile, 48px desktop
88
+ p: { base: 'lg', lg: 'xxl' }, // 24px mobile, 48px desktop
84
89
  });
85
90
  ```
86
91
 
@@ -88,33 +93,33 @@ const page = css({
88
93
 
89
94
  ### Component Spacing
90
95
 
91
- | Use Case | Token | Example |
92
- |----------|-------|---------|
93
- | Button padding (horizontal) | `md` | 16px |
94
- | Button padding (vertical) | `sm` | 8px |
95
- | Input padding | `md` | 16px |
96
- | Card padding | `lg` or `xl` | 24-32px |
97
- | Dialog padding | `lg` or `xl` | 24-32px |
98
- | Icon margins | `xs` or `sm` | 4-8px |
96
+ | Use Case | Token | Example |
97
+ | --------------------------- | ------------ | ------- |
98
+ | Button padding (horizontal) | `md` | 16px |
99
+ | Button padding (vertical) | `sm` | 8px |
100
+ | Input padding | `md` | 16px |
101
+ | Card padding | `lg` or `xl` | 24-32px |
102
+ | Dialog padding | `lg` or `xl` | 24-32px |
103
+ | Icon margins | `xs` or `sm` | 4-8px |
99
104
 
100
105
  ### Layout Spacing
101
106
 
102
- | Use Case | Token | Example |
103
- |----------|-------|---------|
104
- | Gap between form fields | `md` | 16px |
105
- | Gap between cards | `lg` | 24px |
106
- | Section margins | `xl` or `xxl` | 32-48px |
107
- | Page margins | `xl` or `xxl` | 32-48px |
108
- | Hero section padding | `xxxl` | 64px |
107
+ | Use Case | Token | Example |
108
+ | ----------------------- | ------------- | ------- |
109
+ | Gap between form fields | `md` | 16px |
110
+ | Gap between cards | `lg` | 24px |
111
+ | Section margins | `xl` or `xxl` | 32-48px |
112
+ | Page margins | `xl` or `xxl` | 32-48px |
113
+ | Hero section padding | `xxxl` | 64px |
109
114
 
110
115
  ### Content Spacing
111
116
 
112
- | Use Case | Token | Example |
113
- |----------|-------|---------|
114
- | Paragraph margins | `md` | 16px |
115
- | List item spacing | `sm` or `md` | 8-16px |
116
- | Icon-text gap | `xs` or `sm` | 4-8px |
117
- | Button group gap | `sm` | 8px |
117
+ | Use Case | Token | Example |
118
+ | ----------------- | ------------ | ------- |
119
+ | Paragraph margins | `md` | 16px |
120
+ | List item spacing | `sm` or `md` | 8-16px |
121
+ | Icon-text gap | `xs` or `sm` | 4-8px |
122
+ | Button group gap | `sm` | 8px |
118
123
 
119
124
  ## Usage in Code
120
125
 
@@ -124,20 +129,20 @@ const page = css({
124
129
  import { css } from '@discourser/design-system/styled-system/css';
125
130
 
126
131
  // All sides
127
- const box = css({ p: 'md' }); // 16px all sides
132
+ const box = css({ p: 'md' }); // 16px all sides
128
133
 
129
134
  // Individual sides
130
135
  const box = css({
131
- pt: 'lg', // padding-top: 24px
132
- pr: 'md', // padding-right: 16px
133
- pb: 'lg', // padding-bottom: 24px
134
- pl: 'md' // padding-left: 16px
136
+ pt: 'lg', // padding-top: 24px
137
+ pr: 'md', // padding-right: 16px
138
+ pb: 'lg', // padding-bottom: 24px
139
+ pl: 'md', // padding-left: 16px
135
140
  });
136
141
 
137
142
  // Horizontal/Vertical
138
143
  const box = css({
139
- px: 'md', // padding-left + padding-right: 16px
140
- py: 'sm' // padding-top + padding-bottom: 8px
144
+ px: 'md', // padding-left + padding-right: 16px
145
+ py: 'sm', // padding-top + padding-bottom: 8px
141
146
  });
142
147
  ```
143
148
 
@@ -145,20 +150,20 @@ const box = css({
145
150
 
146
151
  ```typescript
147
152
  // All sides
148
- const box = css({ m: 'md' }); // 16px all sides
153
+ const box = css({ m: 'md' }); // 16px all sides
149
154
 
150
155
  // Individual sides
151
156
  const box = css({
152
- mt: 'lg', // margin-top: 24px
153
- mr: 'md', // margin-right: 16px
154
- mb: 'lg', // margin-bottom: 24px
155
- ml: 'md' // margin-left: 16px
157
+ mt: 'lg', // margin-top: 24px
158
+ mr: 'md', // margin-right: 16px
159
+ mb: 'lg', // margin-bottom: 24px
160
+ ml: 'md', // margin-left: 16px
156
161
  });
157
162
 
158
163
  // Horizontal/Vertical
159
164
  const box = css({
160
- mx: 'auto', // margin-left + margin-right: auto (centering)
161
- my: 'lg' // margin-top + margin-bottom: 24px
165
+ mx: 'auto', // margin-left + margin-right: auto (centering)
166
+ my: 'lg', // margin-top + margin-bottom: 24px
162
167
  });
163
168
  ```
164
169
 
@@ -169,14 +174,14 @@ const box = css({
169
174
  const stack = css({
170
175
  display: 'flex',
171
176
  flexDirection: 'column',
172
- gap: 'md' // 16px between all children
177
+ gap: 'md', // 16px between all children
173
178
  });
174
179
 
175
180
  // Different horizontal/vertical gaps
176
181
  const grid = css({
177
182
  display: 'grid',
178
- rowGap: 'lg', // 24px between rows
179
- columnGap: 'md' // 16px between columns
183
+ rowGap: 'lg', // 24px between rows
184
+ columnGap: 'md', // 16px between columns
180
185
  });
181
186
  ```
182
187
 
@@ -188,13 +193,13 @@ Use different spacing values at different breakpoints:
188
193
  const container = css({
189
194
  // Mobile: 16px padding
190
195
  // Desktop: 32px padding
191
- p: { base: 'md', lg: 'xl' }
196
+ p: { base: 'md', lg: 'xl' },
192
197
  });
193
198
 
194
199
  const section = css({
195
200
  // Mobile: 24px margin
196
201
  // Desktop: 48px margin
197
- mb: { base: 'lg', lg: 'xxl' }
202
+ mb: { base: 'lg', lg: 'xxl' },
198
203
  });
199
204
  ```
200
205
 
@@ -218,35 +223,610 @@ const correct = css({ p: 'md', gap: 'lg' });
218
223
  ## Special Cases
219
224
 
220
225
  ### Zero Spacing
226
+
221
227
  ```typescript
222
228
  // Reset spacing
223
229
  const reset = css({
224
- m: 'none', // margin: 0
225
- p: 'none' // padding: 0
230
+ m: 'none', // margin: 0
231
+ p: 'none', // padding: 0
226
232
  });
227
233
  ```
228
234
 
229
235
  ### Negative Margins
236
+
230
237
  ```typescript
231
238
  // Negative margins (use sparingly)
232
239
  const overlap = css({
233
- mt: 'calc(var(--spacing-md) * -1)' // -16px
240
+ mt: 'calc(var(--spacing-md) * -1)', // -16px
234
241
  });
235
242
  ```
236
243
 
237
244
  ### Custom Spacing (Rare)
245
+
238
246
  Only use custom spacing when absolutely necessary and none of the tokens fit:
239
247
 
240
248
  ```typescript
241
249
  // Last resort - custom spacing
242
250
  const custom = css({
243
- padding: 'calc(var(--spacing-sm) + var(--spacing-xs))' // 8px + 4px = 12px
251
+ padding: 'calc(var(--spacing-sm) + var(--spacing-xs))', // 8px + 4px = 12px
244
252
  });
245
253
  ```
246
254
 
255
+ ## How Spacing Tokens Work With Other Tokens
256
+
257
+ Spacing tokens are rarely used in isolation. Here are real-world examples showing how spacing creates rhythm and hierarchy when combined with color, typography, and elevation tokens:
258
+
259
+ ### Card Grid Layout
260
+
261
+ ```typescript
262
+ import { Card } from '@discourser/design-system';
263
+ import { css } from '@discourser/design-system/styled-system/css';
264
+
265
+ <div className={css({
266
+ display: 'grid',
267
+ gridTemplateColumns: { base: '1fr', md: 'repeat(2, 1fr)', lg: 'repeat(3, 1fr)' },
268
+ gap: 'lg', // Spacing - 24px between cards
269
+ p: { base: 'md', lg: 'xl' } // Spacing - 16px mobile, 32px desktop padding
270
+ })}>
271
+ {items.map(item => (
272
+ <Card variant="elevated" key={item.id}>
273
+ {/* Card combines: */}
274
+ {/* bg: 'surfaceContainerLow' - Color token */}
275
+ {/* boxShadow: 'level1' - Elevation token */}
276
+
277
+ <div className={css({
278
+ p: 'lg', // Spacing - 24px internal padding
279
+ display: 'flex',
280
+ flexDirection: 'column',
281
+ gap: 'md' // Spacing - 16px between content sections
282
+ })}>
283
+
284
+ <h3 className={css({
285
+ textStyle: 'titleLarge', // Typography - 22px/28px
286
+ color: 'onSurface', // Color - primary text
287
+ mb: 'sm' // Spacing - 8px bottom margin
288
+ })}>
289
+ {item.title}
290
+ </h3>
291
+
292
+ <p className={css({
293
+ textStyle: 'bodyMedium', // Typography - 14px/20px
294
+ color: 'onSurfaceVariant', // Color - secondary text
295
+ mb: 'md' // Spacing - 16px bottom margin
296
+ })}>
297
+ {item.description}
298
+ </p>
299
+
300
+ <div className={css({
301
+ display: 'flex',
302
+ gap: 'sm', // Spacing - 8px between chips
303
+ mt: 'auto' // Push to bottom
304
+ })}>
305
+ {item.tags.map(tag => (
306
+ <span key={tag} className={css({
307
+ bg: 'secondaryContainer', // Color - chip background
308
+ color: 'onSecondaryContainer', // Color - chip text
309
+ textStyle: 'labelSmall', // Typography - 11px/16px
310
+ px: 'sm', // Spacing - 8px horizontal padding
311
+ py: 'xs', // Spacing - 4px vertical padding
312
+ borderRadius: 'full' // Border radius - pill shape
313
+ })}>
314
+ {tag}
315
+ </span>
316
+ ))}
317
+ </div>
318
+ </div>
319
+ </Card>
320
+ ))}
321
+ </div>
322
+ ```
323
+
324
+ ### Form Layout with Field Grouping
325
+
326
+ ```typescript
327
+ import { Input, Button, Select } from '@discourser/design-system';
328
+ import { css } from '@discourser/design-system/styled-system/css';
329
+
330
+ <form className={css({
331
+ maxWidth: '600px',
332
+ p: { base: 'lg', lg: 'xl' }, // Spacing - 24px mobile, 32px desktop padding
333
+ bg: 'surface', // Color - background
334
+ borderRadius: 'l3', // Border radius - 12px
335
+ boxShadow: 'level1' // Elevation - subtle shadow
336
+ })}>
337
+
338
+ <h2 className={css({
339
+ textStyle: 'headlineSmall', // Typography - 24px/32px
340
+ color: 'onSurface', // Color - primary text
341
+ mb: 'lg' // Spacing - 24px bottom margin
342
+ })}>
343
+ Contact Information
344
+ </h2>
345
+
346
+ <div className={css({
347
+ display: 'flex',
348
+ flexDirection: 'column',
349
+ gap: 'lg' // Spacing - 24px between form fields
350
+ })}>
351
+
352
+ <Input
353
+ label="Full Name"
354
+ {/* Input internally uses: */}
355
+ {/* textStyle: 'bodyLarge' - Typography (16px/24px) */}
356
+ {/* px: 'md', py: 'sm' - Spacing (16px horizontal, 8px vertical) */}
357
+ {/* borderColor: 'outline' - Color token */}
358
+ {/* color: 'onSurface' - Color for text */}
359
+ />
360
+
361
+ <div className={css({
362
+ display: 'grid',
363
+ gridTemplateColumns: { base: '1fr', md: '1fr 1fr' },
364
+ gap: 'md' // Spacing - 16px between email/phone
365
+ })}>
366
+ <Input label="Email" type="email" />
367
+ <Input label="Phone" type="tel" />
368
+ </div>
369
+
370
+ <Select label="Country">
371
+ {/* Select uses: */}
372
+ {/* px: 'md', py: 'sm' - Spacing for padding */}
373
+ {/* textStyle: 'bodyLarge' - Typography */}
374
+ </Select>
375
+
376
+ <div className={css({
377
+ mt: 'xl', // Spacing - 32px top margin (section break)
378
+ pt: 'lg', // Spacing - 24px top padding
379
+ borderTopWidth: '1px',
380
+ borderTopColor: 'outlineVariant' // Color - subtle divider
381
+ })}>
382
+ <h3 className={css({
383
+ textStyle: 'titleMedium', // Typography - 16px/24px
384
+ color: 'onSurface', // Color - primary text
385
+ mb: 'md' // Spacing - 16px bottom margin
386
+ })}>
387
+ Additional Details
388
+ </h3>
389
+
390
+ <Input
391
+ label="Message"
392
+ multiline
393
+ rows={4}
394
+ {/* Multiline input uses: */}
395
+ {/* p: 'md' - Spacing (16px all sides) */}
396
+ />
397
+ </div>
398
+
399
+ <div className={css({
400
+ display: 'flex',
401
+ gap: 'sm', // Spacing - 8px between buttons
402
+ justifyContent: 'flex-end',
403
+ mt: 'lg' // Spacing - 24px top margin
404
+ })}>
405
+ <Button variant="text">
406
+ {/* px: 'lg' - Spacing (24px horizontal) */}
407
+ {/* textStyle: 'labelLarge' - Typography */}
408
+ Cancel
409
+ </Button>
410
+ <Button variant="filled">
411
+ {/* px: 'lg', height: '40px' - Spacing/size */}
412
+ {/* bg: 'primary', color: 'onPrimary' - Color tokens */}
413
+ Submit
414
+ </Button>
415
+ </div>
416
+ </div>
417
+ </form>
418
+ ```
419
+
420
+ ### Navigation Menu with Hierarchical Spacing
421
+
422
+ ```typescript
423
+ import { css } from '@discourser/design-system/styled-system/css';
424
+
425
+ <nav className={css({
426
+ bg: 'surfaceContainerLow', // Color - elevated surface
427
+ borderRadius: 'l2', // Border radius - 8px
428
+ p: 'sm', // Spacing - 8px outer padding
429
+ boxShadow: 'level2' // Elevation - menu shadow
430
+ })}>
431
+
432
+ <ul className={css({
433
+ display: 'flex',
434
+ flexDirection: 'column',
435
+ gap: 'xxs' // Spacing - 2px between menu items (minimal)
436
+ })}>
437
+
438
+ <li>
439
+ <a className={css({
440
+ display: 'flex',
441
+ alignItems: 'center',
442
+ gap: 'md', // Spacing - 16px between icon and text
443
+ px: 'md', // Spacing - 16px horizontal padding
444
+ py: 'sm', // Spacing - 8px vertical padding
445
+ borderRadius: 'l1', // Border radius - 4px
446
+ textStyle: 'labelLarge', // Typography - 14px/20px
447
+ color: 'onSurface', // Color - primary text
448
+ _hover: {
449
+ bg: 'surfaceContainerHighest' // Color - hover background
450
+ }
451
+ })}>
452
+ <Icon /> {/* Icon size: 24px */}
453
+ Dashboard
454
+ </a>
455
+ </li>
456
+
457
+ <li>
458
+ <a className={css({
459
+ display: 'flex',
460
+ alignItems: 'center',
461
+ gap: 'md', // Spacing - consistent with above
462
+ px: 'md',
463
+ py: 'sm',
464
+ borderRadius: 'l1',
465
+ textStyle: 'labelLarge',
466
+ color: 'onSurface',
467
+ bg: 'secondaryContainer', // Color - active state background
468
+ _hover: {
469
+ bg: 'secondaryContainer'
470
+ }
471
+ })}>
472
+ <Icon />
473
+ Projects
474
+ </a>
475
+
476
+ {/* Nested submenu */}
477
+ <ul className={css({
478
+ mt: 'xxs', // Spacing - 2px top margin
479
+ ml: 'xl', // Spacing - 32px left margin (indent)
480
+ display: 'flex',
481
+ flexDirection: 'column',
482
+ gap: 'xxs' // Spacing - 2px between subitems
483
+ })}>
484
+ <li>
485
+ <a className={css({
486
+ display: 'block',
487
+ px: 'md', // Spacing - 16px horizontal
488
+ py: 'xs', // Spacing - 4px vertical (smaller than parent)
489
+ borderRadius: 'l1',
490
+ textStyle: 'bodyMedium', // Typography - 14px/20px
491
+ color: 'onSurfaceVariant', // Color - secondary text
492
+ _hover: {
493
+ bg: 'surfaceContainerHighest'
494
+ }
495
+ })}>
496
+ My Projects
497
+ </a>
498
+ </li>
499
+ </ul>
500
+ </li>
501
+
502
+ <li className={css({
503
+ mt: 'sm', // Spacing - 8px top margin (section break)
504
+ pt: 'sm', // Spacing - 8px top padding
505
+ borderTopWidth: '1px',
506
+ borderTopColor: 'outlineVariant' // Color - divider
507
+ })}>
508
+ <a className={css({
509
+ display: 'flex',
510
+ alignItems: 'center',
511
+ gap: 'md',
512
+ px: 'md',
513
+ py: 'sm',
514
+ borderRadius: 'l1',
515
+ textStyle: 'labelLarge',
516
+ color: 'onSurface'
517
+ })}>
518
+ <Icon />
519
+ Settings
520
+ </a>
521
+ </li>
522
+ </ul>
523
+ </nav>
524
+ ```
525
+
526
+ ### Dialog with Structured Content Spacing
527
+
528
+ ```typescript
529
+ import { Dialog, Button } from '@discourser/design-system';
530
+ import { css } from '@discourser/design-system/styled-system/css';
531
+
532
+ <Dialog.Root>
533
+ <Dialog.Backdrop
534
+ bg: 'scrim' // Color - overlay background
535
+ opacity: 0.32
536
+ />
537
+
538
+ <Dialog.Content className={css({
539
+ bg: 'surfaceContainerHigh', // Color - high elevation surface
540
+ borderRadius: 'l4', // Border radius - 28px
541
+ boxShadow: 'level3', // Elevation - dialog shadow
542
+ p: 'xl', // Spacing - 32px padding
543
+ maxWidth: '560px',
544
+ display: 'flex',
545
+ flexDirection: 'column',
546
+ gap: 'lg' // Spacing - 24px between major sections
547
+ })}>
548
+
549
+ <div>
550
+ <Dialog.Title className={css({
551
+ textStyle: 'headlineSmall', // Typography - 24px/32px
552
+ color: 'onSurface', // Color - primary text
553
+ mb: 'md' // Spacing - 16px bottom margin
554
+ })}>
555
+ Confirm Changes
556
+ </Dialog.Title>
557
+
558
+ <Dialog.Description className={css({
559
+ textStyle: 'bodyMedium', // Typography - 14px/20px
560
+ color: 'onSurfaceVariant' // Color - secondary text
561
+ })}>
562
+ The following changes will be applied to your account:
563
+ </Dialog.Description>
564
+ </div>
565
+
566
+ <div className={css({
567
+ bg: 'surfaceContainerHighest', // Color - nested surface
568
+ borderRadius: 'l2', // Border radius - 8px
569
+ p: 'md' // Spacing - 16px padding
570
+ })}>
571
+ <ul className={css({
572
+ display: 'flex',
573
+ flexDirection: 'column',
574
+ gap: 'sm' // Spacing - 8px between list items
575
+ })}>
576
+ {changes.map((change, index) => (
577
+ <li key={index} className={css({
578
+ display: 'flex',
579
+ alignItems: 'center',
580
+ gap: 'xs', // Spacing - 4px between icon and text
581
+ textStyle: 'bodySmall', // Typography - 12px/16px
582
+ color: 'onSurface' // Color - primary text
583
+ })}>
584
+ <CheckIcon size="16px" />
585
+ {change}
586
+ </li>
587
+ ))}
588
+ </ul>
589
+ </div>
590
+
591
+ <div className={css({
592
+ bg: 'primaryContainer', // Color - info background
593
+ borderRadius: 'l2', // Border radius - 8px
594
+ p: 'md', // Spacing - 16px padding
595
+ display: 'flex',
596
+ gap: 'sm' // Spacing - 8px between icon and text
597
+ })}>
598
+ <InfoIcon className={css({
599
+ color: 'onPrimaryContainer', // Color - icon color
600
+ flexShrink: 0
601
+ })} />
602
+ <p className={css({
603
+ textStyle: 'bodySmall', // Typography - 12px/16px
604
+ color: 'onPrimaryContainer' // Color - text color
605
+ })}>
606
+ This action can be reverted within 30 days.
607
+ </p>
608
+ </div>
609
+
610
+ <div className={css({
611
+ display: 'flex',
612
+ gap: 'sm', // Spacing - 8px between action buttons
613
+ justifyContent: 'flex-end',
614
+ mt: 'md' // Spacing - 16px top margin
615
+ })}>
616
+ <Button variant="text">
617
+ {/* px: 'lg' - Spacing (24px) */}
618
+ {/* textStyle: 'labelLarge' - Typography */}
619
+ Cancel
620
+ </Button>
621
+ <Button variant="filled">
622
+ {/* px: 'lg' - Spacing (24px) */}
623
+ {/* bg: 'primary', color: 'onPrimary' - Color */}
624
+ Confirm
625
+ </Button>
626
+ </div>
627
+ </Dialog.Content>
628
+ </Dialog.Root>
629
+ ```
630
+
631
+ ### Button Group with Icon Spacing
632
+
633
+ ```typescript
634
+ import { Button } from '@discourser/design-system';
635
+ import { css } from '@discourser/design-system/styled-system/css';
636
+
637
+ <div className={css({
638
+ display: 'flex',
639
+ gap: 'sm', // Spacing - 8px between buttons
640
+ flexWrap: 'wrap'
641
+ })}>
642
+ <Button variant="filled">
643
+ {/* Internal button structure: */}
644
+ <span className={css({
645
+ display: 'flex',
646
+ alignItems: 'center',
647
+ gap: 'xs', // Spacing - 4px between icon and text
648
+ px: 'lg', // Spacing - 24px horizontal padding
649
+ height: '40px' // Size - md variant
650
+ })}>
651
+ <SaveIcon /> {/* Icon size: 18px */}
652
+ <span className={css({
653
+ textStyle: 'labelLarge', // Typography - 14px/20px
654
+ color: 'onPrimary' // Color - button text
655
+ })}>
656
+ Save
657
+ </span>
658
+ </span>
659
+ </Button>
660
+
661
+ <Button variant="outlined">
662
+ {/* bg: transparent - Color */}
663
+ {/* borderColor: 'outline' - Color */}
664
+ {/* px: 'lg' - Spacing */}
665
+ <span className={css({
666
+ display: 'flex',
667
+ alignItems: 'center',
668
+ gap: 'xs' // Spacing - consistent icon-text gap
669
+ })}>
670
+ <DownloadIcon />
671
+ <span>Download</span>
672
+ </span>
673
+ </Button>
674
+
675
+ <Button variant="text">
676
+ {/* color: 'primary' - Color */}
677
+ {/* px: 'lg' - Spacing */}
678
+ Preview
679
+ </Button>
680
+ </div>
681
+ ```
682
+
683
+ ### List Item with Avatar and Actions
684
+
685
+ ```typescript
686
+ import { Avatar, IconButton } from '@discourser/design-system';
687
+ import { css } from '@discourser/design-system/styled-system/css';
688
+
689
+ <li className={css({
690
+ display: 'flex',
691
+ alignItems: 'center',
692
+ gap: 'md', // Spacing - 16px between major sections
693
+ p: 'md', // Spacing - 16px padding
694
+ borderRadius: 'l2', // Border radius - 8px
695
+ bg: 'surface', // Color - background
696
+ _hover: {
697
+ bg: 'surfaceContainerHighest' // Color - hover state
698
+ }
699
+ })}>
700
+
701
+ <Avatar.Root size="md">
702
+ {/* Avatar size: 40px */}
703
+ {/* Avatar has built-in bg: 'primary', color: 'onPrimary' */}
704
+ <Avatar.Image src="/avatar.jpg" />
705
+ <Avatar.Fallback>JD</Avatar.Fallback>
706
+ </Avatar.Root>
707
+
708
+ <div className={css({ flex: 1 })}>
709
+ <div className={css({
710
+ display: 'flex',
711
+ alignItems: 'center',
712
+ gap: 'xs', // Spacing - 4px between name and badge
713
+ mb: 'xxs' // Spacing - 2px bottom margin
714
+ })}>
715
+ <h4 className={css({
716
+ textStyle: 'titleMedium', // Typography - 16px/24px
717
+ color: 'onSurface' // Color - primary text
718
+ })}>
719
+ Jane Doe
720
+ </h4>
721
+ <span className={css({
722
+ bg: 'tertiaryContainer', // Color - badge background
723
+ color: 'onTertiaryContainer', // Color - badge text
724
+ textStyle: 'labelSmall', // Typography - 11px/16px
725
+ px: 'xs', // Spacing - 4px horizontal padding
726
+ py: '2px', // Spacing - minimal vertical
727
+ borderRadius: 'full' // Border radius - pill
728
+ })}>
729
+ Pro
730
+ </span>
731
+ </div>
732
+
733
+ <p className={css({
734
+ textStyle: 'bodySmall', // Typography - 12px/16px
735
+ color: 'onSurfaceVariant', // Color - secondary text
736
+ mb: 'xs' // Spacing - 4px bottom margin
737
+ })}>
738
+ jane.doe@example.com
739
+ </p>
740
+
741
+ <span className={css({
742
+ textStyle: 'labelSmall', // Typography - 11px/16px
743
+ color: 'onSurfaceVariant' // Color - tertiary text
744
+ })}>
745
+ Last active 2 hours ago
746
+ </span>
747
+ </div>
748
+
749
+ <div className={css({
750
+ display: 'flex',
751
+ gap: 'xs' // Spacing - 4px between icon buttons
752
+ })}>
753
+ <IconButton variant="ghost" size="sm">
754
+ {/* IconButton uses: */}
755
+ {/* p: 'sm' - Spacing (8px padding) */}
756
+ {/* size: '32px' - Size token */}
757
+ {/* borderRadius: 'full' - Border radius */}
758
+ <EditIcon />
759
+ </IconButton>
760
+ <IconButton variant="ghost" size="sm">
761
+ <DeleteIcon className={css({
762
+ color: 'error' // Color - error icon
763
+ })} />
764
+ </IconButton>
765
+ </div>
766
+ </li>
767
+ ```
768
+
769
+ ### Multi-Token Spacing Pattern Summary
770
+
771
+ When creating layouts, spacing tokens combine with other tokens in these patterns:
772
+
773
+ **Container Pattern:**
774
+
775
+ ```typescript
776
+ {
777
+ p: 'md-xxl', // Spacing - internal padding
778
+ gap: 'sm-lg', // Spacing - between children
779
+ bg: 'surface*', // Color - background
780
+ borderRadius: 'l1-l4', // Border radius
781
+ boxShadow: 'level*' // Elevation (if needed)
782
+ }
783
+ ```
784
+
785
+ **Content Flow Pattern:**
786
+
787
+ ```typescript
788
+ {
789
+ display: 'flex|grid',
790
+ flexDirection: 'column',
791
+ gap: 'md-lg', // Spacing - primary content flow
792
+ mb: 'xl-xxl' // Spacing - section separation
793
+ }
794
+ ```
795
+
796
+ **Interactive Element Pattern:**
797
+
798
+ ```typescript
799
+ {
800
+ px: 'md-lg', // Spacing - horizontal padding
801
+ py: 'xs-sm', // Spacing - vertical padding (usually smaller)
802
+ gap: 'xs-sm', // Spacing - icon-text gap
803
+ textStyle: 'label*', // Typography
804
+ borderRadius: 'full|l1', // Border radius
805
+ _hover: {
806
+ bg: 'surface*' // Color - hover state
807
+ }
808
+ }
809
+ ```
810
+
811
+ **Hierarchical Text Pattern:**
812
+
813
+ ```typescript
814
+ {
815
+ textStyle: 'headline*|title*', // Typography - heading
816
+ color: 'onSurface', // Color - primary text
817
+ mb: 'sm-md', // Spacing - heading-to-content gap
818
+
819
+ // Followed by:
820
+ textStyle: 'body*', // Typography - body text
821
+ color: 'onSurfaceVariant', // Color - secondary text
822
+ mb: 'md-lg' // Spacing - paragraph separation
823
+ }
824
+ ```
825
+
247
826
  ## Accessibility
248
827
 
249
828
  Proper spacing improves:
829
+
250
830
  - **Touch targets**: Minimum 44x44px (use appropriate padding)
251
831
  - **Readability**: Adequate spacing between text blocks
252
832
  - **Scannability**: Clear visual separation between sections
@@ -259,13 +839,13 @@ Proper spacing improves:
259
839
  const button = css({
260
840
  minHeight: '44px',
261
841
  px: 'md',
262
- py: 'sm'
842
+ py: 'sm',
263
843
  });
264
844
 
265
845
  // ✅ Spacing between interactive elements
266
846
  const buttonGroup = css({
267
847
  display: 'flex',
268
- gap: 'sm' // Minimum 8px between buttons
848
+ gap: 'sm', // Minimum 8px between buttons
269
849
  });
270
850
  ```
271
851
 
@@ -280,10 +860,10 @@ const buttonGroup = css({
280
860
 
281
861
  ## Common Spacing Mistakes
282
862
 
283
- | ❌ Wrong | ✅ Right | Why |
284
- |---------|---------|-----|
285
- | `gap: 'xs'` for cards | `gap: 'lg'` | Cards need breathing room |
286
- | `p: 'xxxl'` for button | `px: 'md', py: 'sm'` | Too much padding overwhelms |
287
- | `mb: 'sm'` for sections | `mb: 'xl'` or `'xxl'` | Sections need clear separation |
288
- | `padding: '20px'` | `p: 'lg'` | Use tokens, not arbitrary values |
863
+ | ❌ Wrong | ✅ Right | Why |
864
+ | ------------------------- | --------------------- | -------------------------------- |
865
+ | `gap: 'xs'` for cards | `gap: 'lg'` | Cards need breathing room |
866
+ | `p: 'xxxl'` for button | `px: 'md', py: 'sm'` | Too much padding overwhelms |
867
+ | `mb: 'sm'` for sections | `mb: 'xl'` or `'xxl'` | Sections need clear separation |
868
+ | `padding: '20px'` | `p: 'lg'` | Use tokens, not arbitrary values |
289
869
  | `gap: 'lg'` between icons | `gap: 'xs'` or `'sm'` | Icons are small, need less space |