@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,139 +0,0 @@
1
- @reference "tailwindcss";
2
- @import "../theme.css";
3
- @reference "../box.css";
4
-
5
- /* A filled, edgeless, raised box you can press. `box` paints it; everything
6
- here is what makes it a button rather than some other box.
7
-
8
- The resting values are the published default: a button with no presentation
9
- class is solid and edgeless, and that is a decision written on three lines
10
- rather than a `var()` fallback buried in an expression. */
11
- @utility btn {
12
- --_d-fill: 100%;
13
- --_d-fg-on-fill: 100%;
14
- --_d-border: 0%;
15
- --_d-elevation: 1;
16
-
17
- @apply box box-hover box-active relative inline-flex w-fit cursor-pointer items-center justify-center gap-2 px-4 py-2 whitespace-nowrap no-underline select-none;
18
-
19
- min-height: var(--control-height);
20
- /* The vertical padding gives back the line `box` draws, so a default button
21
- is exactly `--control-height` tall like `.ipt` beside it, under any
22
- aesthetic's line width. At the default 16px/1.5 text the label and the
23
- padding fill it; the size and padding modifiers set their own. */
24
- padding-block: calc(0.5rem - var(--_width));
25
- /* The surrounding font, not the user agent's smaller button one, on every
26
- entry: `/components` carries no reset to say so, and a `.btn` link and a
27
- `.btn` button have to print the same label. `.sm` and `.lg` set their own
28
- size over this. */
29
- font-family: inherit;
30
- font-size: inherit;
31
- line-height: inherit;
32
- /* The label is material, shared with `.badge`: weight, tracking, case, and a
33
- text shadow, set by an aesthetic as tokens (`.chunky-tile`'s heavier,
34
- tracked label), and a consumer's own `font-*`, `tracking-*`, `uppercase`, or
35
- text-shadow utility still beats the aesthetic. Tracking has no fallback on
36
- purpose: undefined, the declaration is invalid at computed-value time and
37
- `letter-spacing` inherits, which is what it did before the slot existed.
38
- Case and shadow fall back to `none`, which is what a button already does:
39
- the user agent stops both inheriting into one. The shadow is written
40
- without a colour, so it takes the label's own and cannot lower its
41
- contrast. See docs/internal/model.md#cascade-layers. */
42
- font-weight: var(--ui-label-weight, var(--font-weight-semibold));
43
- letter-spacing: var(--ui-label-tracking);
44
- text-transform: var(--ui-label-case, none);
45
- text-shadow: var(--ui-label-shadow, none);
46
-
47
- &.sm {
48
- @apply min-h-8 px-3 py-1 text-sm;
49
-
50
- --_scale-size: 0.75;
51
- }
52
-
53
- &.lg {
54
- @apply min-h-12 px-5 py-2.5 text-[1.0625rem];
55
-
56
- --_scale-size: 1.25;
57
- }
58
-
59
- &.icon {
60
- @apply aspect-square p-2;
61
-
62
- min-width: var(--control-height);
63
- }
64
-
65
- /* The size steps for an icon button, square at each: `.sm`'s 2rem, with the
66
- padding giving back the line width the way the default button's does, and
67
- `.lg`'s 3rem. Each names its width as well as its height, because WebKit
68
- does not let `aspect-ratio` widen a box past its `min-width`. */
69
- &.icon.sm {
70
- min-width: 2rem;
71
- padding: calc(0.375rem - var(--_width));
72
- }
73
-
74
- &.icon.lg {
75
- min-width: 3rem;
76
- }
77
-
78
- /* Bare `sm`/`lg` are the size modifier's class names, so `p-` prefixes here.
79
- `.p-xs` is the tightest step, below `.p-sm`: a chip-sized button in a
80
- toolbar or a table cell.
81
-
82
- `.icon` drops both floors -- `min-width` from its own base rule above and
83
- `min-height` from `--control-height` -- at every padding tier; labeled
84
- buttons keep the height floor everywhere but `.p-xs`. `.icon` is already
85
- square: `aspect-square` ties its width to whatever height it lands on, so a
86
- surviving height floor would keep the button bigger than its own glyph
87
- however tight the padding asked to be. */
88
- &.p-xs {
89
- @apply px-2 py-0.5;
90
-
91
- --_scale-pad: 0.5;
92
-
93
- /* The one padding step that also drops the size floor for a labeled
94
- button. At this tier the button is a chip in a toolbar or a table
95
- cell, where `--control-height` is taller than the row it sits in;
96
- every other size and padding class keeps the floor, so a plain button
97
- stays a comfortable target. */
98
- min-height: 0;
99
-
100
- &.icon {
101
- @apply p-0.5;
102
-
103
- min-width: 0;
104
- }
105
- }
106
-
107
- &.p-sm {
108
- @apply px-2.5 py-1;
109
-
110
- --_scale-pad: 0.75;
111
-
112
- &.icon {
113
- @apply p-1;
114
-
115
- min-width: 0;
116
- min-height: 0;
117
- }
118
- }
119
-
120
- &.p-lg {
121
- @apply px-6 py-3;
122
-
123
- --_scale-pad: 1.25;
124
-
125
- &.icon {
126
- @apply p-3;
127
-
128
- min-width: 0;
129
- min-height: 0;
130
- }
131
- }
132
-
133
- /* A pill normally takes the round material ahead of the box radius. Sketch
134
- gives this token the button's own box outline; a bevel still cuts the full
135
- radius to points under cyber. */
136
- &.pill {
137
- border-radius: var(--ui-radius-pill, calc(infinity * 1px));
138
- }
139
- }
@@ -1,35 +0,0 @@
1
- /* The layer map, stated before any import uses a layer -- see `theme.css`.
2
- Tailwind's utilities are imported into `utilities` the way
3
- `tailwindcss/index.css` does it, so every component lands there on this
4
- entrypoint and on `/native` too, exactly where `.` already puts them. Without
5
- `layer(utilities)` the CLI emitted them unlayered here, and they beat every
6
- consumer rule on these two entries alone. */
7
- @layer theme, base, components, utilities;
8
-
9
- /* The theme before `@reference "tailwindcss"`, as `native.css` has it:
10
- Tailwind writes the theme's variables at the first `@theme` it meets, and
11
- after the reference that is Tailwind's own reference-only one. See
12
- docs/internal/model.md (Which files import the theme). */
13
- @import "../theme.css";
14
- @reference "tailwindcss";
15
- @import "tailwindcss/utilities.css" layer(utilities);
16
- /* Everything that is not `src/` -- see the note in `index.css`. Keeps a class
17
- name in a docs code fence from shipping as a real rule in `dist/components.css`. */
18
- @import "../typography.css";
19
- @import "../box.css";
20
- @import "./button.css";
21
- @import "./feedback.css";
22
- @import "./form.css";
23
- @import "./surface.css";
24
- @import "./tooltip.css";
25
-
26
- /* The composition utilities -- `box`, `box-hover`, `box-active`,
27
- `text-control`, `surface`, `input-group` -- are `@utility` rules whose bodies
28
- the content scan will not emit on its own. `box` and friends appear only as
29
- `@utility` blocks and `@apply` targets; `text-control`, `surface` and
30
- `input-group` appear only inside `:is()`/`:where()` argument lists in
31
- `intent.css` and `form.css`, never as a selector of their own. Safelisting
32
- all six makes the emission deliberate; the composition-body check in
33
- `exports.test.ts` fails the build if one is dropped. `text-control` and
34
- `surface` are also documented as consumer-usable on their own. */
35
- @source inline("box box-hover box-active text-control surface input-group unadorned text-display text-title-lg text-title text-title-sm text-label-lg text-label text-body btn field label hint ipt icon textarea select checkbox radio switch alert alert-icon badge skeleton progress tooltip tooltip-bubble tooltip-icon card panel interactive flush neutral solid soft ghost edged edgeless flat raised floating");
@@ -1,184 +0,0 @@
1
- @reference "tailwindcss";
2
- @import "../theme.css";
3
- @import "../surface.css";
4
- @reference "../box.css";
5
-
6
- /* A ghost, edged container that takes one unit when depth is supplied. */
7
- @utility card {
8
- @apply surface p-(--surface-padding,1.25rem);
9
-
10
- /* After the `@apply`, not before: `surface` inlines its own resting geometry
11
- at that point, so defaults written above it would be overridden by the very
12
- utility they are meant to specialise. */
13
- --_d-fill: 0%;
14
- --_d-fg-on-fill: 0%;
15
- --_d-border: 100%;
16
- --_d-elevation: 1;
17
-
18
- &.p-xs {
19
- --surface-padding: 0.5rem;
20
- --_scale-pad: 0.5;
21
- }
22
-
23
- &.p-sm {
24
- --surface-padding: 0.75rem;
25
- --_scale-pad: 0.75;
26
- }
27
-
28
- &.p-lg {
29
- --surface-padding: 2rem;
30
- --_scale-pad: 1.25;
31
- }
32
-
33
- &.flush {
34
- --surface-padding: 0;
35
- }
36
-
37
- /* `.soft` rests untinted for no named intent instead of mixing its 12%: 12%
38
- of `--color-text` onto any of `--color-background`, `--color-foreground`,
39
- or `--color-surface` lands within a few units of the others (a near-black
40
- ink dominates the result), so swapping the ground token alone does not read
41
- as quieter. A resting no-intent `.card.soft` is `--color-foreground` with
42
- no ink mixed in -- a plain step up from the page that marks a different
43
- container without drawing attention to it.
44
-
45
- A named intent keeps its ordinary 12% wash: 12% of an actual hue does not
46
- read as a slab the way 12% of near-black ink does (`.card.soft.destructive`
47
- is a gentle `249, 225, 225`), and untinting it would silence it rather than
48
- quiet it. `:not(...)` names every intent class for that reason; `.panel`'s
49
- carve-out below is scoped the same way.
50
-
51
- `--_fill-cap: 0%` (box.css's override slot, not `--ui-fill` directly -- see
52
- the comment there) composed with `box-hover`'s formula (`min(100%, resting
53
- + 14%)`) reveals the intent on hover with no second fill declaration for
54
- the no-intent case: resting at 0% means hover lands at exactly the hover
55
- step, 14%, in `--intent-hover`. The ground steps to `--color-surface` at
56
- the same moment, through `--_d-surface-ground`, the default `surface` reads
57
- beneath the public `--ui-surface-ground`, so a consumer's override, or
58
- glass's ground, wins over both states. Scoped to `.interactive` and
59
- `.hoverable`, the two classes that opt a card into `box-hover`: a plain
60
- `.card.soft` has no hover state to reveal into and stays at the quiet rest.
61
- A named intent needs neither special case: it rests tinted, so the generic
62
- `box-hover` formula deepens it on hover (12% to 26%). */
63
- &.soft:not(.primary, .secondary, .success, .warning, .destructive, .info) {
64
- --_fill-cap: 0%;
65
- --_d-surface-ground: var(--color-foreground);
66
-
67
- &.interactive:hover,
68
- &.hoverable:hover {
69
- --_d-surface-ground: var(--color-surface);
70
- }
71
- }
72
-
73
- /* Opt-in, because a card is only sometimes a control. Applications still owe
74
- it a real interactive element and an accessible name. Hover and press are
75
- the derived ones every other pressable box gets; there is nothing
76
- card-specific about either.
77
-
78
- `.interactive` is the whole opt-in and stays that way; `.hoverable` and
79
- `.pressable` are its halves, for a card that answers one gesture and not
80
- the other. A card with its own nested controls takes `.hoverable` for the
81
- hover warmth without the press-scale that reads as "you activated the
82
- card" when the click really landed on a nested button. `.hoverable` alone
83
- does not set the pointer cursor: that travels with being a click target,
84
- i.e. with `.pressable` / `.interactive`. */
85
- &.interactive,
86
- &.hoverable {
87
- @apply box-hover;
88
- }
89
-
90
- &.interactive,
91
- &.pressable {
92
- @apply box-active cursor-pointer;
93
- }
94
- }
95
-
96
- /* A panel is the flush, unelevated sibling: sidebars, toolbars, and wells that
97
- sit flat against the layout rather than floating above it. Soft and edgeless
98
- is what makes it read as a well without drawing a line to say so. */
99
- @utility panel {
100
- @apply surface p-(--surface-padding,1rem);
101
-
102
- --_d-fill: 12%;
103
- --_d-fg-on-fill: 0%;
104
- --_d-border: 0%;
105
- --_d-elevation: 0;
106
-
107
- &.p-xs {
108
- --surface-padding: 0.25rem;
109
- --_scale-pad: 0.5;
110
- }
111
-
112
- &.p-sm {
113
- --surface-padding: 0.5rem;
114
- --_scale-pad: 0.75;
115
- }
116
-
117
- &.p-lg {
118
- --surface-padding: 1.5rem;
119
- --_scale-pad: 1.25;
120
- }
121
-
122
- &.flush {
123
- --surface-padding: 0;
124
- }
125
-
126
- /* Neutral panels are the common case -- layout wells, sidebars, toolbars with
127
- no named intent -- and 12% of `--color-text` (near-black) mixed onto the
128
- page is far more assertive than 12% of a hue (`217, 217, 217` against a
129
- `250, 250, 250` page): the same "neutral ink reads louder" effect
130
- `.card.soft` answers, and the reason `--intent-fill-max` stops neutral's
131
- fill short everywhere else.
132
-
133
- Scoped to no named intent rather than untinted unconditionally, as
134
- `data-table` is: a panel is not interactive, so there is no hover to reveal
135
- a colored intent into, and it is edgeless by default, so the fill is the
136
- only channel a `.primary` bulk-actions bar or a `.destructive` danger-zone
137
- panel has to say what it is (a resting `.panel.destructive` is a gentle
138
- `249, 225, 225` wash). `.card.soft` carries the same scoping. `:not(...)`
139
- names every intent class, plus `.solid`/`.ghost` so an explicit
140
- presentation on the element is never clamped to a cap it did not ask for --
141
- the guard `data-table`'s `:not(.solid, .ghost)` also uses.
142
-
143
- Grounds on `--color-foreground` through `--_d-surface-ground`, the default
144
- `.card.soft` rests on, so a bare `.panel` rests at exactly the plate a
145
- `.card.soft` does, and a consumer's `--ui-surface-ground` or glass's
146
- translucent ground wins over it: a neutral panel under `.glass` is glass.
147
- Permanent rather than hover-revealed: neither a panel nor `data-table` has
148
- an interaction state to reveal a tint into. */
149
- &:not(.primary, .secondary, .success, .warning, .destructive, .info, .solid, .ghost) {
150
- --_fill-cap: 0%;
151
- --_d-surface-ground: var(--color-foreground);
152
- }
153
- }
154
-
155
- /* The user agent already promises both of these for a native `<dialog>` --
156
- `dialog:not([open]) { display: none }` and a centred `margin: auto` on the
157
- open box -- but both are user-agent origin, which loses to any author rule
158
- at all. `.card`'s own `display: block` beats the first outright, so a
159
- `<dialog class="card">` rendered open with no `open` attribute and no
160
- `.showModal()` call, and a margin reset beats the second, so an opened one
161
- pinned to the top-left. The registry has no dialog component, and these
162
- three are the containers a consumer reaches for.
163
-
164
- Here rather than in the reset, so every entrypoint that ships `.card` ships
165
- the fix, `/components` included, and scoped to the package's own containers,
166
- so a dialog the package does not style keeps whatever margin its author
167
- gives it.
168
-
169
- The two halves sit in different places. Hiding a closed dialog is
170
- behaviour, so it is unlayered and beats any layered rule whatever its
171
- specificity. Centring an open one is a default, so it is in `utilities` at
172
- zero specificity: it beats a reset in `base`, and a consumer's own margin
173
- -- a utility, or unlayered CSS -- beats it. Unlayered at 0-2-1 it overruled
174
- `mt-8` and `.my-dialog { margin-top: 2rem }` alike, and a dialog could not
175
- be placed. */
176
- dialog:is(.card, .panel, .surface):not([open]) {
177
- display: none;
178
- }
179
-
180
- @layer utilities {
181
- :where(dialog:is(.card, .panel, .surface)[open]) {
182
- margin: auto;
183
- }
184
- }
@@ -1,229 +0,0 @@
1
- /* Imported into the `components` layer by `theme.css`, below every utility, so
2
- a consumer's own utility or unlayered CSS beats these classes. See
3
- docs/internal/model.md#cascade-layers. */
4
-
5
- /* An intent maps one colour family onto seven shared slots and nothing else.
6
- It does not cascade: the reset at the bottom redeclares the neutral defaults
7
- at every component's own root, so a `.success` container cannot recolour a
8
- nested destructive button while `.btn.success` still wins. Every intent writes
9
- every slot, `--intent-fill-max` included -- omitting it inherits the reset's
10
- neutral cap, and `tests/integration/registry.test.ts` fails the build on one
11
- that does. Neutral maps `--intent-subtle` to `--color-surface` (the tone
12
- tooltips, key caps, code and table heads sit on) and `--intent-border` to
13
- `--ui-ink` (how an aesthetic restates the neutral line without naming one). */
14
-
15
- /* The same neutral values, at the root. This is the floor: an element that
16
- carries no intent class and matches none of the resets below -- a component
17
- `@apply`-ed onto a selector the package does not name, a bare `<code>` with
18
- no native stylesheet loaded -- still composes against a real colour instead
19
- of an undefined one that collapses its `color-mix()` to nothing. It is not
20
- the barrier. `.neutral` and both resets below still write these slots on the
21
- element itself, which is a matching rule and so beats this inherited value --
22
- that is what stops a `.success` container's intent reaching a component
23
- nested under it. An intent class on the element beats both. Values track
24
- `.neutral` slot for slot; `registry.test.ts` fails the build on drift. */
25
- :root {
26
- --intent-color: var(--color-text);
27
- --intent-contrast: var(--color-text-contrast);
28
- --intent-hover: var(--color-text-hover);
29
- --intent-strong: var(--color-text-strong);
30
- --intent-subtle: var(--color-surface);
31
- --intent-border: var(--ui-ink, var(--color-border));
32
- --intent-fill-max: 20%;
33
- }
34
-
35
- /* Neutral stops its fill short: its colour is the page's ink, so a full fill is
36
- a slab and `.neutral.solid` would be pixel-for-pixel `.primary.solid`. 20% is
37
- chosen against `.soft`'s 12% -- a step past the tint, not a repeat.
38
- `--intent-contrast` stays the page colour; a `.neutral.solid` badge's ink is
39
- `box`'s question, answered by the same `--ui-fg-on-fill` cap. Pointing this
40
- slot at `--color-text` renders a checked neutral checkbox black-on-black. */
41
- .neutral {
42
- --intent-color: var(--color-text);
43
- --intent-contrast: var(--color-text-contrast);
44
- --intent-hover: var(--color-text-hover);
45
- --intent-strong: var(--color-text-strong);
46
- --intent-subtle: var(--color-surface);
47
- --intent-border: var(--ui-ink, var(--color-border));
48
- --intent-fill-max: 20%;
49
- }
50
-
51
- .primary {
52
- --intent-color: var(--color-primary);
53
- --intent-contrast: var(--color-primary-contrast);
54
- --intent-hover: var(--color-primary-hover);
55
- --intent-strong: var(--color-primary-strong);
56
- --intent-subtle: var(--color-primary-subtle);
57
- --intent-border: var(--color-primary);
58
- --intent-fill-max: 100%;
59
- }
60
-
61
- .secondary {
62
- --intent-color: var(--color-accent);
63
- --intent-contrast: var(--color-accent-contrast);
64
- --intent-hover: var(--color-accent-hover);
65
- --intent-strong: var(--color-accent-strong);
66
- --intent-subtle: var(--color-accent-subtle);
67
- --intent-border: var(--color-accent);
68
- --intent-fill-max: 100%;
69
- }
70
-
71
- .success {
72
- --intent-color: var(--color-success);
73
- --intent-contrast: var(--color-success-contrast);
74
- --intent-hover: var(--color-success-hover);
75
- --intent-strong: var(--color-success-strong);
76
- --intent-subtle: var(--color-success-subtle);
77
- --intent-border: var(--color-success);
78
- --intent-fill-max: 100%;
79
- }
80
-
81
- .warning {
82
- --intent-color: var(--color-warning);
83
- --intent-contrast: var(--color-warning-contrast);
84
- --intent-hover: var(--color-warning-hover);
85
- --intent-strong: var(--color-warning-strong);
86
- --intent-subtle: var(--color-warning-subtle);
87
- --intent-border: var(--color-warning);
88
- --intent-fill-max: 100%;
89
- }
90
-
91
- .destructive {
92
- --intent-color: var(--color-destructive);
93
- --intent-contrast: var(--color-destructive-contrast);
94
- --intent-hover: var(--color-destructive-hover);
95
- --intent-strong: var(--color-destructive-strong);
96
- --intent-subtle: var(--color-destructive-subtle);
97
- --intent-border: var(--color-destructive);
98
- --intent-fill-max: 100%;
99
- }
100
-
101
- .info {
102
- --intent-color: var(--color-info);
103
- --intent-contrast: var(--color-info-contrast);
104
- --intent-hover: var(--color-info-hover);
105
- --intent-strong: var(--color-info-strong);
106
- --intent-subtle: var(--color-info-subtle);
107
- --intent-border: var(--color-info);
108
- --intent-fill-max: 100%;
109
- }
110
-
111
- /* Every component resolves the neutral defaults at its own root, at zero
112
- specificity, so an intent class on the element wins while an inherited value
113
- loses -- the one rule that lets every component drop its per-intent branches.
114
- This list and the one in `native.css` are the package's only hand-maintained
115
- selector lists; `tests/integration/registry.test.ts` fails the build on a
116
- registry component missing from either. `.text-control` and `.surface` are on
117
- it though they are not components: both are documented as typeable on their
118
- own, and a bare `<div class="surface">` with no intent resolved computes a
119
- transparent background and a zero-width border -- `box` collapses. */
120
- :where(
121
- .btn,
122
- .ipt,
123
- .text-control,
124
- .surface,
125
- .textarea,
126
- .select,
127
- .input-group,
128
- .checkbox,
129
- .radio,
130
- .switch,
131
- .card,
132
- .panel,
133
- .alert,
134
- .data-table,
135
- .pre,
136
- .quote,
137
- .tooltip-bubble,
138
- .tooltip-icon,
139
- .badge,
140
- .kbd,
141
- .code,
142
- .skeleton,
143
- .progress,
144
- .divider
145
- ) {
146
- --intent-color: var(--color-text);
147
- --intent-contrast: var(--color-text-contrast);
148
- --intent-hover: var(--color-text-hover);
149
- --intent-strong: var(--color-text-strong);
150
- --intent-subtle: var(--color-surface);
151
- --intent-border: var(--ui-ink, var(--color-border));
152
- --intent-fill-max: 20%;
153
- }
154
-
155
- /* The six text controls take a heavier line than everything else that rests on
156
- the shared neutral. A card, a table or a divider sits on a filled surface or
157
- separates content that identifies itself; a text control at rest is a
158
- transparent box whose only mark is its border, and WCAG 1.4.11 asks that
159
- border for 3:1. `--color-border` gives it 1.42:1.
160
-
161
- Declared here at zero specificity for the same reason the indicators below
162
- are: written inside `@utility text-control` it would land in `utilities`,
163
- above every intent class in `components`, and overrule `.primary` on the
164
- element. Written as a plain class list it would carry 0-1-0 and, being later
165
- in the stylesheet, beat `.primary` the same way. Either would make every
166
- colored control draw a grey line; `:where()` keeps it under both.
167
-
168
- An aesthetic reaches this line through `--ui-control-ink` first, then its
169
- `--ui-ink`: the theme keeps a control border apart from a surface border, and
170
- an aesthetic whose neutral line suits a pane but not a control's boundary --
171
- `.glass`'s white hairline, `.chunky-tile`'s tile grey -- names a control line
172
- of its own. See docs/internal/model.md#presentation.
173
-
174
- The second selector is the tooltip bubble's below, for the same reason:
175
- `.neutral` carries 0-1-0 and beat `:where()`, so a `.neutral` field under
176
- `.glass` drew the pane's hairline while an unclassed one drew the control
177
- line, and writing the intent out changed the box. */
178
- :where(.text-control, .ipt, .textarea, .select, .input-group, .checkbox, .radio, .switch),
179
- :is(.text-control, .ipt, .textarea, .select, .input-group, .checkbox, .radio, .switch).neutral {
180
- --intent-border: var(--ui-control-ink, var(--ui-ink, var(--color-control-border)));
181
- }
182
-
183
- /* A table's lines -- its frame, head rule, and row rules -- are drawn on a
184
- plate, not at a pane's edge against the backdrop, so an aesthetic whose
185
- neutral line is a highlight names a rule line of its own: glass's white
186
- hairline vanishes on the table's light plate. Neutral only, and `.neutral`
187
- included, the way the control line above is, and a `.neutral` row in a
188
- table of another intent, which draws its rules as a neutral table does. */
189
- :where(.data-table),
190
- .data-table.neutral,
191
- .data-table tr.neutral {
192
- --intent-border: var(--ui-rule-ink, var(--ui-ink, var(--color-border)));
193
- }
194
-
195
- /* The bubble a tooltip draws is the one plate in the package that is chosen
196
- rather than composed, so it resolves the no-intent case onto its own pair
197
- instead of the shared neutral -- see `--color-tooltip` in `theme.css`.
198
-
199
- The cap goes with it. Neutral stops its fill at 20% because its colour is the
200
- page's ink; `--color-tooltip` is a plate rather than an ink, so a full fill
201
- of it is the plate and there is nothing to stop short of. `--intent-subtle`
202
- stays the surface token, the tone every other unclassed component sits on.
203
- `.tooltip-icon` is a separate element that never fills past `0%`, so the
204
- generic neutral reset above is enough for it.
205
-
206
- Two selectors, so `none` and `neutral` agree. `:where()` loses to any intent
207
- class, so `.tooltip-bubble.primary` still floods with primary;
208
- `.tooltip-bubble.neutral` carries 0-2-0 and beats `.neutral`, so writing the
209
- intent out gives the same bubble as writing nothing. */
210
- :where(.tooltip-bubble),
211
- .tooltip-bubble.neutral {
212
- --intent-color: var(--color-tooltip);
213
- --intent-contrast: var(--color-tooltip-contrast);
214
- --intent-hover: var(--color-tooltip);
215
- --intent-strong: var(--color-tooltip-contrast);
216
- --intent-subtle: var(--color-surface);
217
- --intent-border: var(--ui-ink, var(--color-border));
218
- --intent-fill-max: 100%;
219
- }
220
-
221
- /* Indicators take the color they sit in rather than the shared neutral, so a
222
- skeleton inside filled or colored content still matches it. It has to be
223
- declared here at zero specificity: written in the component's own block it
224
- would carry 0-1-0 and, being later in the stylesheet, beat `.success` --
225
- which silently makes every indicator ignore every intent class. */
226
- :where(.skeleton, .progress, .divider) {
227
- --intent-color: currentColor;
228
- --intent-border: currentColor;
229
- }