@codenhub/styles 0.7.0 → 0.8.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 (121) hide show
  1. package/README.es.md +8 -7
  2. package/README.md +7 -6
  3. package/README.pt-BR.md +8 -7
  4. package/dist/aesthetics/chunky-tile.css +1 -1
  5. package/dist/aesthetics/cyber.css +1 -1
  6. package/dist/aesthetics/glass.css +1 -1
  7. package/dist/aesthetics/index.css +2 -2
  8. package/dist/aesthetics/neobrutalism.css +1 -1
  9. package/dist/aesthetics/sketch.css +1 -1
  10. package/dist/cli.js +189 -0
  11. package/dist/components.css +2 -2
  12. package/dist/index.css +2 -2
  13. package/dist/index.d.ts +1 -0
  14. package/dist/native.css +2 -2
  15. package/dist/palette.css +1 -1
  16. package/dist/theme.css +2 -2
  17. package/docs/accessibility.md +46 -27
  18. package/docs/changelog/0.8.0.md +70 -0
  19. package/docs/changelog/index.md +1 -0
  20. package/docs/es/accessibility.md +47 -28
  21. package/docs/es/index.md +3 -2
  22. package/docs/es/integrating/index.md +38 -10
  23. package/docs/es/integrating/tailwind.md +78 -8
  24. package/docs/es/integrating/without-a-bundler.md +128 -5
  25. package/docs/es/setup.md +42 -34
  26. package/docs/es/usage/aesthetics.md +19 -13
  27. package/docs/es/usage/buttons.md +6 -2
  28. package/docs/es/usage/composing.md +6 -2
  29. package/docs/es/usage/content-and-layout.md +8 -4
  30. package/docs/es/usage/customizing.md +19 -13
  31. package/docs/es/usage/feedback.md +5 -1
  32. package/docs/es/usage/forms.md +29 -4
  33. package/docs/es/usage/index.md +6 -2
  34. package/docs/es/usage/presets.md +92 -0
  35. package/docs/es/usage/solo.md +4 -2
  36. package/docs/es/usage/theming.md +28 -15
  37. package/docs/index.md +2 -1
  38. package/docs/integrating/index.md +38 -10
  39. package/docs/integrating/tailwind.md +77 -7
  40. package/docs/integrating/without-a-bundler.md +127 -4
  41. package/docs/pt-BR/accessibility.md +47 -28
  42. package/docs/pt-BR/index.md +3 -2
  43. package/docs/pt-BR/integrating/index.md +38 -10
  44. package/docs/pt-BR/integrating/tailwind.md +78 -8
  45. package/docs/pt-BR/integrating/without-a-bundler.md +128 -5
  46. package/docs/pt-BR/setup.md +42 -34
  47. package/docs/pt-BR/usage/aesthetics.md +19 -13
  48. package/docs/pt-BR/usage/buttons.md +6 -2
  49. package/docs/pt-BR/usage/composing.md +6 -2
  50. package/docs/pt-BR/usage/content-and-layout.md +8 -4
  51. package/docs/pt-BR/usage/customizing.md +19 -13
  52. package/docs/pt-BR/usage/feedback.md +5 -1
  53. package/docs/pt-BR/usage/forms.md +29 -4
  54. package/docs/pt-BR/usage/index.md +6 -2
  55. package/docs/pt-BR/usage/presets.md +92 -0
  56. package/docs/pt-BR/usage/solo.md +4 -2
  57. package/docs/pt-BR/usage/theming.md +21 -8
  58. package/docs/setup.md +30 -22
  59. package/docs/usage/aesthetics.md +18 -12
  60. package/docs/usage/buttons.md +5 -1
  61. package/docs/usage/composing.md +5 -1
  62. package/docs/usage/content-and-layout.md +7 -3
  63. package/docs/usage/customizing.md +18 -12
  64. package/docs/usage/feedback.md +4 -0
  65. package/docs/usage/forms.md +28 -3
  66. package/docs/usage/index.md +5 -1
  67. package/docs/usage/presets.md +91 -0
  68. package/docs/usage/solo.md +3 -1
  69. package/docs/usage/theming.md +20 -7
  70. package/llms-full.txt +592 -115
  71. package/package.json +113 -63
  72. package/{dist/tw → tw}/aesthetics/chunky-tile.css +39 -19
  73. package/{dist/tw → tw}/aesthetics/cyber.css +15 -24
  74. package/{dist/tw → tw}/aesthetics/glass.css +105 -36
  75. package/{dist/tw → tw}/aesthetics/neobrutalism.css +37 -20
  76. package/{dist/tw → tw}/aesthetics/sketch.css +152 -133
  77. package/{dist/tw → tw}/box.css +89 -12
  78. package/tw/components/button.css +11 -0
  79. package/tw/components/button.rules.css +187 -0
  80. package/tw/components/feedback.css +11 -0
  81. package/{dist/tw/components/feedback.css → tw/components/feedback.rules.css} +134 -30
  82. package/tw/components/form.css +11 -0
  83. package/{dist/tw/components/form.css → tw/components/form.rules.css} +524 -111
  84. package/tw/components/index.css +16 -0
  85. package/tw/components/rules.css +41 -0
  86. package/tw/components/surface.css +11 -0
  87. package/tw/components/surface.rules.css +222 -0
  88. package/tw/components/tooltip.css +11 -0
  89. package/{dist/tw/components/tooltip.css → tw/components/tooltip.rules.css} +43 -27
  90. package/{dist/tw → tw}/corner.css +18 -12
  91. package/{dist/tw → tw}/elevation.css +23 -17
  92. package/{dist/tw → tw}/index.css +11 -9
  93. package/tw/index.d.ts +1 -0
  94. package/tw/intent.css +312 -0
  95. package/tw/modifiers.css +127 -0
  96. package/tw/native.css +320 -0
  97. package/tw/presentation.css +139 -0
  98. package/tw/reset.css +10 -0
  99. package/{dist/tw/reset.css → tw/reset.rules.css} +7 -8
  100. package/tw/size.css +34 -0
  101. package/tw/surface.css +9 -0
  102. package/tw/surface.rules.css +212 -0
  103. package/{dist/tw → tw}/theme.css +92 -28
  104. package/tw/typography.css +8 -0
  105. package/{dist/tw/typography.css → tw/typography.rules.css} +0 -3
  106. package/{dist/tw → tw}/utilities/content.css +183 -63
  107. package/tw/utilities/index.css +11 -0
  108. package/tw/utilities/layout.css +208 -0
  109. package/tw/utilities/rules.css +8 -0
  110. package/dist/tw/components/button.css +0 -139
  111. package/dist/tw/components/index.css +0 -35
  112. package/dist/tw/components/surface.css +0 -184
  113. package/dist/tw/intent.css +0 -229
  114. package/dist/tw/native.css +0 -203
  115. package/dist/tw/palette.css +0 -460
  116. package/dist/tw/presentation.css +0 -68
  117. package/dist/tw/surface.css +0 -61
  118. package/dist/tw/utilities/index.css +0 -6
  119. package/dist/tw/utilities/layout.css +0 -144
  120. /package/{dist/tw → tw}/aesthetics/index.css +0 -0
  121. /package/{dist/tw → tw}/aesthetics/pixel.css +0 -0
@@ -1,5 +1,3 @@
1
- @reference "../box.css";
2
-
3
1
  /* A scroll box clips whatever paints outside it, and `overflow-x` takes the
4
2
  vertical overflow with it, so an aesthetic's halo around the table -- cyber's
5
3
  glow -- would be cut flush on every side. The wrapper makes room for the halo
@@ -40,6 +38,19 @@
40
38
  instead (below), which every engine draws on the rows. Recorded in
41
39
  `registry.json` beside the decision. */
42
40
  @utility data-table {
41
+ /* The neutral reset, carried so `@apply data-table` gets it, as `btn` carries its own. */
42
+ @layer families {
43
+ :where(&:not(.data-table, .primary, .secondary, .success, .warning, .destructive, .info)) {
44
+ --intent-color: var(--color-text);
45
+ --intent-contrast: var(--color-text-contrast);
46
+ --intent-hover: var(--color-text-hover);
47
+ --intent-strong: var(--color-text-strong);
48
+ --intent-subtle: var(--color-surface);
49
+ --intent-border: var(--ui-rule-ink, var(--ui-ink, var(--color-border)));
50
+ --intent-fill-max: 20%;
51
+ }
52
+ }
53
+
43
54
  @apply box text-body w-full border-separate text-start;
44
55
 
45
56
  --_d-fill: 12%;
@@ -54,7 +65,6 @@
54
65
  /* Capped the way `box` caps, because the head is a fill of the intent like any
55
66
  other and a neutral table head is otherwise a slab of the page's ink with
56
67
  ink printed on it. */
57
- --table-fill: calc(min(var(--ui-fill, var(--_d-fill)), var(--intent-fill-max, 100%)) * var(--ui-bg-alpha, 1));
58
68
  /* The head's plate is the tint, so a table carrying no fill has no head
59
69
  plate. `.ghost` means no tint here the way it means no fill everywhere
60
70
  else, and a ghost table is boundaries and type and nothing else -- which is
@@ -75,7 +85,6 @@
75
85
  than over `--table-fill`'s own `calc()`/`min()` chain, which matters for
76
86
  the reason `--table-rule-plated` below records. */
77
87
  --table-ground: min(100%, calc(var(--ui-fill, var(--_d-fill)) * 5));
78
- --table-head-plate: color-mix(in oklab, var(--intent-subtle) var(--table-ground), transparent);
79
88
  --table-head-bg: color-mix(in oklab, var(--intent-color) var(--table-fill), var(--table-head-plate));
80
89
  --table-head-fg: color-mix(in oklab, var(--intent-contrast) var(--_on-fill), var(--intent-strong));
81
90
  /* The table's own contrast ink, resolved here so a row with its own intent
@@ -101,25 +110,45 @@
101
110
  element, so nothing here fights `.soft` for `--ui-fill`. `.ghost` is left
102
111
  at box's default (`--_d-ground: transparent`), so it stays the fully bare
103
112
  boundaries-only table; `.soft` differs from it by keeping an opaque,
104
- untinted plate and a head label strip.
105
-
106
- `:not(.solid, .ghost)` rather than `.soft`: the published resting fill is
107
- `soft`, so a bare `<table class="data-table">` with no fill class at all is
108
- the common case this has to reach. */
113
+ untinted plate and a head label strip. */
114
+ /* Whether the table rests on the quiet plate, as 0% or 100%: a resolved
115
+ fill above nothing and below full. Stepped from the resolved fill, as
116
+ `surface`'s `--_quiet` is, not keyed on `:not(.solid, .ghost)` here:
117
+ presentation cascades, and keyed on the class a container's `.solid`
118
+ filled the head and dropped the frame while the body kept this plate. */
119
+ --_table-quiet: min(
120
+ clamp(0%, calc(var(--ui-fill, var(--_d-fill)) * 1000), 100%),
121
+ clamp(0%, calc((100% - var(--ui-fill, var(--_d-fill))) * 1000), 100%)
122
+ );
123
+ /* A table is a pane of content, so under an aesthetic whose surfaces are
124
+ glass it is glass too: the plate is the aesthetic's surface ground when
125
+ one is named. Head and body share the plate, as they do on the page. Only
126
+ the quiet rest reads it: a `.solid` table is opaque, like every `.solid`,
127
+ and a `.ghost` one is boundaries and type. */
128
+ --table-ground-plate: var(--ui-surface-ground, var(--color-foreground));
129
+ --table-fill: min(
130
+ calc(min(var(--ui-fill, var(--_d-fill)), var(--intent-fill-max, 100%)) * var(--ui-bg-alpha, 1)),
131
+ calc(100% - var(--_table-quiet))
132
+ );
133
+ --table-head-plate: color-mix(
134
+ in oklab,
135
+ var(--table-ground-plate) var(--_table-quiet),
136
+ color-mix(in oklab, var(--intent-subtle) var(--table-ground), transparent)
137
+ );
138
+ --_fill-cap: calc(100% - var(--_table-quiet));
139
+ --_d-ground: color-mix(in oklab, var(--table-ground-plate) var(--_table-quiet), transparent);
140
+
141
+ /* A table rests on a plate of its own at every fill but `.ghost`, so no
142
+ ink from above passes through it, as on `surface`. A ghost table on a
143
+ filled parent therefore prints the page's ink on that fill: a toggle
144
+ cannot be stepped from the fill. */
145
+ --_held-ink: var(--_fg-own);
146
+ --_held-on: var(--_own-hold);
147
+
148
+ /* The blur behind the glass plate. A filter cannot be stepped from a
149
+ percentage, so this one part stays keyed on the class: a table under a
150
+ container's `.ghost` in a glass region still blurs what is behind it. */
109
151
  &:not(.solid, .ghost) {
110
- --table-fill: 0%;
111
- --table-head-plate: var(--table-ground-plate);
112
- --_fill-cap: 0%;
113
- --_d-ground: var(--table-ground-plate);
114
-
115
- /* A table is a pane of content, so under an aesthetic whose surfaces are
116
- glass it is glass too: the plate is the aesthetic's surface ground when
117
- one is named, and the blur behind it is the one surfaces take. Head and
118
- body share the plate, as they do on the page. Only this arm reads them:
119
- a `.solid` table is opaque, like every `.solid`, and a `.ghost` one is
120
- boundaries and type with nothing behind them to blur. */
121
- --table-ground-plate: var(--ui-surface-ground, var(--color-foreground));
122
-
123
152
  -webkit-backdrop-filter: var(--ui-backdrop, none);
124
153
  backdrop-filter: var(--ui-backdrop, none);
125
154
  }
@@ -163,7 +192,11 @@
163
192
  something every engine can carry. `--table-row-hover` below is written the
164
193
  same way, for the same reason. */
165
194
  --table-rule-plated: color-mix(in oklab, currentColor 20%, transparent);
166
- --table-rule-tone: color-mix(in oklab, var(--table-rule-plated) var(--ui-fill, var(--_d-fill)), var(--intent-border));
195
+ --table-rule-tone: color-mix(
196
+ in oklab,
197
+ var(--table-rule-plated) var(--ui-fill, var(--_d-fill)),
198
+ var(--intent-border, var(--ui-rule-ink, var(--ui-ink, var(--color-border))))
199
+ );
167
200
  --table-rule: color-mix(in oklab, var(--table-rule-tone) var(--table-rule-amount), transparent);
168
201
  --table-boundary: color-mix(in oklab, var(--table-rule-tone) var(--table-boundary-amount), transparent);
169
202
  /* A hovered row is a step from the table it is in, not from a tone the page
@@ -275,8 +308,9 @@
275
308
  `th` centers unless its parent names an alignment, and `start` is the
276
309
  initial value, which counts as naming none. */
277
310
  --_table-rule-width: var(--ui-border-width, var(--border-width));
278
- & th,
279
- & td {
311
+ /* In `:where()`: these are the cells' defaults, and at the 0-1-1 the plain
312
+ selector carried, `p-0` or `text-center` on a cell lost to them. */
313
+ :where(& :is(th, td)) {
280
314
  @apply px-4 py-3 text-start align-top;
281
315
 
282
316
  border-bottom-style: var(--ui-rule-style, var(--ui-line-style, solid));
@@ -303,18 +337,7 @@
303
337
  border-top-color: var(--table-boundary);
304
338
  }
305
339
 
306
- /* Rules between body rows, on request -- and every line off, on the opposite
307
- request. `.ruleless` is declared second so it wins the nonsense combination
308
- rather than leaving it to whichever class the author typed first. */
309
- &.ruled {
310
- --ui-rule: 100%;
311
- }
312
-
313
- &.ruleless {
314
- --ui-rule: 0%;
315
- }
316
-
317
- & th {
340
+ :where(& th) {
318
341
  @apply text-label font-semibold;
319
342
  }
320
343
 
@@ -342,20 +365,21 @@
342
365
  --table-hover-tone: color-mix(in oklab, currentColor var(--ui-fill, var(--_d-fill)), var(--intent-hover));
343
366
  --table-row-hover: color-mix(in oklab, var(--table-hover-tone) 12%, transparent);
344
367
 
345
- color: color-mix(in oklab, var(--_table-contrast) var(--_on-fill), var(--intent-strong));
346
- }
347
-
348
- /* A neutral solid table caps its fill at 20%, so its plate is a light grey
349
- and the ramp keeps `--_on-fill` low: the row's ink is then mostly the
350
- row's `--intent-strong`, which is chosen against the row's own subtle
351
- ground rather than a grey one, and success, warning and destructive fall
352
- under 4.5:1 on it. Those rows print the table's own ink, `--_fg`,
353
- inherited already resolved against the table, and keep their intent in
354
- the rule and the hover. */
355
- &.solid:not(.primary, .secondary, .success, .warning, .destructive, .info)
356
- tbody
357
- tr:is(.neutral, .primary, .secondary, .success, .warning, .destructive, .info) {
358
- color: var(--_fg);
368
+ /* A neutral solid table caps its fill at 20%, so its plate is a light grey
369
+ and the ramp keeps `--_on-fill` low: the row's ink is then mostly the
370
+ row's `--intent-strong`, which is chosen against the row's own subtle
371
+ ground rather than a grey one, and success, warning and destructive fall
372
+ under 4.5:1 on it. Those rows print the table's own ink, `--_fg`,
373
+ inherited already resolved against the table, and keep their intent in
374
+ the rule and the hover.
375
+ `--_plate` is the table's too: 100% where the intent's cap stopped its
376
+ fill, read rather than a `.solid` class on the table, which a
377
+ container's `.solid` does not put there. */
378
+ color: color-mix(
379
+ in oklab,
380
+ var(--_fg) var(--_plate, 0%),
381
+ color-mix(in oklab, var(--_table-contrast) var(--_on-fill), var(--intent-strong))
382
+ );
359
383
  }
360
384
 
361
385
  & tbody tr > * {
@@ -413,9 +437,23 @@
413
437
  separate from, so it alone drops the extra ink. The ground itself is not
414
438
  moved the way `.panel`'s is: `--intent-subtle` already resolves to
415
439
  `--color-surface` for neutral, a real, visible step past the page on its
416
- own, so only the wash on top of it goes. `:not(.solid)` so an explicit
417
- `.solid` chip is never clamped to a cap it did not ask for. */
440
+ own, so only the wash on top of it goes. The cap is stepped from the
441
+ resolved fill, so a full fill -- the chip's own `.solid` or a container's --
442
+ is never clamped to a cap it did not ask for. */
418
443
  @utility kbd {
444
+ /* The neutral reset, carried so `@apply kbd` gets it, as `btn` carries its own. */
445
+ @layer families {
446
+ :where(&:not(.kbd, .primary, .secondary, .success, .warning, .destructive, .info)) {
447
+ --intent-color: var(--color-text);
448
+ --intent-contrast: var(--color-text-contrast);
449
+ --intent-hover: var(--color-text-hover);
450
+ --intent-strong: var(--color-text-strong);
451
+ --intent-subtle: var(--color-surface);
452
+ --intent-border: var(--ui-ink, var(--color-border));
453
+ --intent-fill-max: 20%;
454
+ }
455
+ }
456
+
419
457
  @apply box inline-flex items-center px-1.5 py-0.5 font-mono text-xs font-medium;
420
458
 
421
459
  --_d-fill: 12%;
@@ -424,6 +462,10 @@
424
462
  --_d-elevation: 0;
425
463
  --_d-ground: var(--intent-subtle);
426
464
 
465
+ /* A ground of its own, so no ink from above passes through, as on `surface`. */
466
+ --_held-ink: var(--_fg-own);
467
+ --_held-on: var(--_own-hold);
468
+
427
469
  /* A small default remains when no aesthetic asks for a complete chip shape. */
428
470
  border-radius: var(
429
471
  --ui-radius-tight,
@@ -431,13 +473,35 @@
431
473
  );
432
474
  clip-path: var(--ui-clip-tight, var(--ui-clip, none));
433
475
 
434
- &:not(.primary, .secondary, .success, .warning, .destructive, .info, .solid) {
435
- --_fill-cap: 0%;
436
- }
476
+ /* The neutral wash goes, and only that: a neutral intent (its cap is below
477
+ 100%) asking for less than its cap. Stepped from the resolved fill, as
478
+ `surface`'s `--_quiet` is, not keyed on a class here: presentation
479
+ cascades, and keyed on the class a container's `.solid` reached the ink
480
+ and the line while the plate stayed capped. */
481
+ --_fill-cap: calc(
482
+ 100% -
483
+ min(
484
+ clamp(0%, calc((100% - var(--intent-fill-max, 100%)) * 1000), 100%),
485
+ clamp(0%, calc((var(--intent-fill-max, 100%) - var(--ui-fill, var(--_d-fill))) * 1000), 100%)
486
+ )
487
+ );
437
488
  }
438
489
 
439
490
  /* The same plate with no line around it. */
440
491
  @utility code {
492
+ /* The neutral reset, carried so `@apply code` gets it, as `btn` carries its own. */
493
+ @layer families {
494
+ :where(&:not(.code, .primary, .secondary, .success, .warning, .destructive, .info)) {
495
+ --intent-color: var(--color-text);
496
+ --intent-contrast: var(--color-text-contrast);
497
+ --intent-hover: var(--color-text-hover);
498
+ --intent-strong: var(--color-text-strong);
499
+ --intent-subtle: var(--color-surface);
500
+ --intent-border: var(--ui-ink, var(--color-border));
501
+ --intent-fill-max: 20%;
502
+ }
503
+ }
504
+
441
505
  @apply box px-1.25 py-0.75 font-mono;
442
506
 
443
507
  --_d-fill: 12%;
@@ -446,19 +510,45 @@
446
510
  --_d-elevation: 0;
447
511
  --_d-ground: var(--intent-subtle);
448
512
 
513
+ /* A ground of its own, so no ink from above passes through, as on `surface`. */
514
+ --_held-ink: var(--_fg-own);
515
+ --_held-on: var(--_own-hold);
516
+
449
517
  border-radius: var(
450
518
  --ui-radius-tight,
451
519
  min(var(--ui-radius, var(--ui-corner, var(--radius-small))), var(--radius-small))
452
520
  );
453
521
  clip-path: var(--ui-clip-tight, var(--ui-clip, none));
454
522
 
455
- &:not(.primary, .secondary, .success, .warning, .destructive, .info, .solid) {
456
- --_fill-cap: 0%;
457
- }
523
+ /* The neutral wash goes, and only that: a neutral intent (its cap is below
524
+ 100%) asking for less than its cap. Stepped from the resolved fill, as
525
+ `surface`'s `--_quiet` is, not keyed on a class here: presentation
526
+ cascades, and keyed on the class a container's `.solid` reached the ink
527
+ and the line while the plate stayed capped. */
528
+ --_fill-cap: calc(
529
+ 100% -
530
+ min(
531
+ clamp(0%, calc((100% - var(--intent-fill-max, 100%)) * 1000), 100%),
532
+ clamp(0%, calc((var(--intent-fill-max, 100%) - var(--ui-fill, var(--_d-fill))) * 1000), 100%)
533
+ )
534
+ );
458
535
  }
459
536
 
460
537
  /* And at block scale, where the radius is a control's rather than a chip's. */
461
538
  @utility pre {
539
+ /* The neutral reset, carried so `@apply pre` gets it, as `btn` carries its own. */
540
+ @layer families {
541
+ :where(&:not(.pre, .primary, .secondary, .success, .warning, .destructive, .info)) {
542
+ --intent-color: var(--color-text);
543
+ --intent-contrast: var(--color-text-contrast);
544
+ --intent-hover: var(--color-text-hover);
545
+ --intent-strong: var(--color-text-strong);
546
+ --intent-subtle: var(--color-surface);
547
+ --intent-border: var(--ui-ink, var(--color-border));
548
+ --intent-fill-max: 20%;
549
+ }
550
+ }
551
+
462
552
  @apply box block overflow-x-auto px-2.5 py-1.5 font-mono;
463
553
 
464
554
  --_d-fill: 12%;
@@ -467,9 +557,22 @@
467
557
  --_d-elevation: 0;
468
558
  --_d-ground: var(--intent-subtle);
469
559
 
470
- &:not(.primary, .secondary, .success, .warning, .destructive, .info, .solid) {
471
- --_fill-cap: 0%;
472
- }
560
+ /* A ground of its own, so no ink from above passes through, as on `surface`. */
561
+ --_held-ink: var(--_fg-own);
562
+ --_held-on: var(--_own-hold);
563
+
564
+ /* The neutral wash goes, and only that: a neutral intent (its cap is below
565
+ 100%) asking for less than its cap. Stepped from the resolved fill, as
566
+ `surface`'s `--_quiet` is, not keyed on a class here: presentation
567
+ cascades, and keyed on the class a container's `.solid` reached the ink
568
+ and the line while the plate stayed capped. */
569
+ --_fill-cap: calc(
570
+ 100% -
571
+ min(
572
+ clamp(0%, calc((100% - var(--intent-fill-max, 100%)) * 1000), 100%),
573
+ clamp(0%, calc((var(--intent-fill-max, 100%) - var(--ui-fill, var(--_d-fill))) * 1000), 100%)
574
+ )
575
+ );
473
576
  }
474
577
 
475
578
  /* Typography wearing a component's name, so it composes none of `box`: `box`
@@ -487,6 +590,19 @@
487
590
  what makes the bar read as a bar at the default hairline: doubling 1px gives
488
591
  2px, and a quotation mark needs more presence than a table rule. */
489
592
  @utility quote {
593
+ /* The neutral reset, carried so `@apply quote` gets it, as `btn` carries its own. */
594
+ @layer families {
595
+ :where(&:not(.quote, .primary, .secondary, .success, .warning, .destructive, .info)) {
596
+ --intent-color: var(--color-text);
597
+ --intent-contrast: var(--color-text-contrast);
598
+ --intent-hover: var(--color-text-hover);
599
+ --intent-strong: var(--color-text-strong);
600
+ --intent-subtle: var(--color-surface);
601
+ --intent-border: var(--ui-ink, var(--color-border));
602
+ --intent-fill-max: 20%;
603
+ }
604
+ }
605
+
490
606
  --_d-fill: 0%;
491
607
  --_d-fg-on-fill: 0%;
492
608
  --_d-border: 100%;
@@ -517,7 +633,11 @@
517
633
  A quotation draws its own edge instead of taking `box`'s, so an edge change
518
634
  is made in `box`, `.quote`, and `.progress`. Recorded in `registry.json`
519
635
  beside the decision to compose none of `box`. */
520
- --quote-line: color-mix(in oklab, transparent var(--ui-fill, var(--_d-fill)), var(--intent-border));
636
+ --quote-line: color-mix(
637
+ in oklab,
638
+ transparent var(--ui-fill, var(--_d-fill)),
639
+ var(--intent-border, var(--ui-ink, var(--color-border)))
640
+ );
521
641
  --quote-edge: color-mix(in oklab, var(--quote-line) var(--ui-border, var(--_d-border)), transparent);
522
642
  --quote-width: calc(var(--ui-border-width, var(--border-width)) * 2 + 1px);
523
643
 
@@ -0,0 +1,11 @@
1
+ @import "../theme.css";
2
+ @import "../typography.css";
3
+ @reference "../box.css";
4
+
5
+ /* The focused entry: what the rules in `rules.css` need to compile on their
6
+ own, then the rules. An aggregate entry imports the rules file directly and
7
+ supplies those needs once -- Tailwind stacks a `@utility` each time a file
8
+ that defines it is imported or referenced, so a second route to `box.css`
9
+ doubles every `@apply box`. See docs/internal/model.md (One route to each
10
+ utility). */
11
+ @import "./rules.css";
@@ -0,0 +1,208 @@
1
+ /* The gap is a private each layout declares from `--layout-gap`, and the
2
+ density modifiers step it: `tight` and `loose` raise a flag
3
+ (`modifiers.css`) and the layout reads it, so `@apply stack tight` carries
4
+ the step. A container's `--layout-gap` still reaches every layout inside
5
+ it, because each one reads the token afresh; a `.tight` or `.loose` stays
6
+ on its own element, the way `.p-xs` stays on a card, because the layout
7
+ inside restates the flags at zero specificity in `families`, where one on
8
+ the element itself still wins. */
9
+ @utility view {
10
+ @layer families {
11
+ :where(&:not(.tight)) {
12
+ --_m-tight: initial;
13
+ }
14
+
15
+ :where(&:not(.loose)) {
16
+ --_m-loose: initial;
17
+ }
18
+
19
+ :where(&:not(.vertical)) {
20
+ --_m-vertical: initial;
21
+ }
22
+
23
+ :where(&:not(.horizontal)) {
24
+ --_m-horizontal: initial;
25
+ }
26
+ }
27
+
28
+ @apply flex gap-(--_gap);
29
+
30
+ --_tight-gap: var(--_m-tight) 0.5rem;
31
+ --_loose-gap: var(--_m-loose) 1.5rem;
32
+ --_gap: var(--_loose-gap, var(--_tight-gap, var(--layout-gap)));
33
+
34
+ /* A row unless asked: `vertical` stacks, and `horizontal` is a row that
35
+ wraps and centres its items. */
36
+ --_vertical-direction: var(--_m-vertical) column;
37
+ --_horizontal-direction: var(--_m-horizontal) row;
38
+ --_horizontal-wrap: var(--_m-horizontal) wrap;
39
+ --_horizontal-align: var(--_m-horizontal) center;
40
+
41
+ flex-direction: var(--_horizontal-direction, var(--_vertical-direction, row));
42
+ flex-wrap: var(--_horizontal-wrap, nowrap);
43
+ align-items: var(--_horizontal-align, normal);
44
+ }
45
+
46
+ @utility stack {
47
+ @layer families {
48
+ :where(&:not(.tight)) {
49
+ --_m-tight: initial;
50
+ }
51
+
52
+ :where(&:not(.loose)) {
53
+ --_m-loose: initial;
54
+ }
55
+ }
56
+
57
+ @apply flex flex-col gap-(--_gap);
58
+
59
+ --_tight-gap: var(--_m-tight) 0.5rem;
60
+ --_loose-gap: var(--_m-loose) 1.5rem;
61
+ --_gap: var(--_loose-gap, var(--_tight-gap, var(--layout-gap)));
62
+ }
63
+
64
+ @utility cluster {
65
+ @layer families {
66
+ :where(&:not(.tight)) {
67
+ --_m-tight: initial;
68
+ }
69
+
70
+ :where(&:not(.loose)) {
71
+ --_m-loose: initial;
72
+ }
73
+
74
+ :where(&:not(.between)) {
75
+ --_m-between: initial;
76
+ }
77
+ }
78
+
79
+ @apply flex flex-wrap items-center gap-(--_gap);
80
+
81
+ --_tight-gap: var(--_m-tight) 0.5rem;
82
+ --_loose-gap: var(--_m-loose) 1.5rem;
83
+ --_gap: var(--_loose-gap, var(--_tight-gap, var(--layout-gap)));
84
+
85
+ --_between-justify: var(--_m-between) space-between;
86
+
87
+ justify-content: var(--_between-justify, normal);
88
+ }
89
+
90
+ @utility auto-grid {
91
+ @layer families {
92
+ :where(&:not(.tight)) {
93
+ --_m-tight: initial;
94
+ }
95
+
96
+ :where(&:not(.loose)) {
97
+ --_m-loose: initial;
98
+ }
99
+ }
100
+
101
+ @apply grid gap-(--_gap);
102
+
103
+ --_tight-gap: var(--_m-tight) 0.5rem;
104
+ --_loose-gap: var(--_m-loose) 1.5rem;
105
+ --_gap: var(--_loose-gap, var(--_tight-gap, var(--layout-gap)));
106
+
107
+ grid-template-columns: repeat(auto-fit, minmax(min(var(--layout-grid-min), 100%), 1fr));
108
+ }
109
+
110
+ @utility section {
111
+ @apply px-(--layout-gutter) py-(--layout-section-block);
112
+ }
113
+
114
+ @utility section-content {
115
+ @layer families {
116
+ :where(&:not(.narrow)) {
117
+ --_m-narrow: initial;
118
+ }
119
+
120
+ :where(&:not(.wide)) {
121
+ --_m-wide: initial;
122
+ }
123
+ }
124
+
125
+ @apply mx-auto w-full;
126
+
127
+ --_narrow-max: var(--_m-narrow) var(--container-narrow);
128
+ --_wide-max: var(--_m-wide) var(--container-wide);
129
+
130
+ max-width: var(--_wide-max, var(--_narrow-max, var(--container-max)));
131
+ }
132
+
133
+ /* An indicator: intent only, and no presentation token at all. A rule is a
134
+ line, and neither a fill class nor an edge class has anything to say about
135
+ one -- a container's `.ghost.edgeless` must not make every `<hr>` inside it
136
+ invisible. The width is the aesthetic's line width, unscaled. */
137
+ @utility divider {
138
+ /* The indicator reset, carried so `@apply divider` gets it, as `btn` carries
139
+ its own: the neutral slots, with the two an indicator takes from the
140
+ colour it sits in. Without it an applied one read an undefined
141
+ `--intent-border`. */
142
+ @layer families {
143
+ :where(&:not(.divider, .primary, .secondary, .success, .warning, .destructive, .info)) {
144
+ --intent-color: currentColor;
145
+ --intent-contrast: var(--color-text-contrast);
146
+ --intent-hover: var(--color-text-hover);
147
+ --intent-strong: var(--color-text-strong);
148
+ --intent-subtle: var(--color-surface);
149
+ --intent-border: currentColor;
150
+ --intent-fill-max: 20%;
151
+ }
152
+ }
153
+
154
+ @layer families {
155
+ :where(&:not(.vertical)) {
156
+ --_m-vertical: initial;
157
+ }
158
+ }
159
+
160
+ --divider-color: var(--intent-color);
161
+ --divider-width: var(--ui-border-width, var(--border-width));
162
+
163
+ @apply m-0 border-0;
164
+
165
+ /* Across unless `vertical`, which turns the line to the inline-start edge
166
+ and stretches it down its row. */
167
+ --_vertical-width: var(--_m-vertical) 0px;
168
+ --_vertical-self: var(--_m-vertical) stretch;
169
+ --_vertical-line: var(--_m-vertical) var(--divider-width);
170
+
171
+ width: var(--_vertical-width, 100%);
172
+ align-self: var(--_vertical-self, auto);
173
+ border-color: var(--divider-color);
174
+ border-style: var(--ui-rule-style, var(--ui-line-style, solid));
175
+ border-top-width: var(--_vertical-width, var(--divider-width));
176
+ border-inline-start-width: var(--_vertical-line, 0px);
177
+ }
178
+
179
+ @utility selection-contrast {
180
+ &::selection,
181
+ & *::selection {
182
+ background: var(--color-primary-contrast);
183
+ color: var(--color-primary);
184
+ }
185
+ }
186
+
187
+ /* `.visually-hidden`, the standard clip-based recipe. Tailwind's `sr-only` does
188
+ nothing on the vanilla entries (`.`, `/native`), which compile real CSS from
189
+ a scan of `src/` alone with no Tailwind utility layer to reach, so the
190
+ package publishes its own.
191
+
192
+ It is not named `.sr-only`: on a `/tw` entry the consumer's own Tailwind
193
+ build supplies that utility, and two same-named utilities in one cascade
194
+ collide silently -- the collision `registry.test.ts` polices (see
195
+ `data-table`'s `renamedFrom` in `registry.json`). `@source
196
+ inline("visually-hidden")` in `utilities/index.css` force-emits it on the
197
+ entries with no scannable markup of their own. */
198
+ @utility visually-hidden {
199
+ position: absolute;
200
+ width: 1px;
201
+ height: 1px;
202
+ padding: 0;
203
+ margin: -1px;
204
+ overflow: hidden;
205
+ clip: rect(0, 0, 0, 0);
206
+ white-space: nowrap;
207
+ border-width: 0;
208
+ }
@@ -0,0 +1,8 @@
1
+ /* Every utility, with nothing they need: `content.css` applies `box`, which
2
+ the importing entry supplies once. See `index.css` beside this file. */
3
+ @import "./layout.css";
4
+ @import "./content.css";
5
+
6
+ /* Safelists the utilities for the compiled build, which has no markup to scan.
7
+ `scripts/build-tw.mjs` strips it from the `tw/` copy -- see the note in
8
+ `components/index.css`. */