@codenhub/styles 0.7.0 → 0.9.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 (130) hide show
  1. package/README.es.md +9 -8
  2. package/README.md +8 -7
  3. package/README.pt-BR.md +9 -8
  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/pixel.css +1 -1
  10. package/dist/aesthetics/sketch.css +1 -1
  11. package/dist/cli.js +358 -0
  12. package/dist/components.css +50 -2
  13. package/dist/index.css +50 -2
  14. package/dist/index.d.ts +1 -0
  15. package/dist/native.css +50 -2
  16. package/dist/palette.css +1 -1
  17. package/dist/purge/classes.json +1 -0
  18. package/dist/purge/index.css +50 -0
  19. package/dist/theme.css +2 -2
  20. package/docs/accessibility.md +46 -27
  21. package/docs/changelog/0.8.0.md +70 -0
  22. package/docs/changelog/0.9.0.md +40 -0
  23. package/docs/changelog/index.md +2 -0
  24. package/docs/es/accessibility.md +47 -28
  25. package/docs/es/index.md +4 -3
  26. package/docs/es/integrating/index.md +38 -10
  27. package/docs/es/integrating/tailwind.md +79 -8
  28. package/docs/es/integrating/without-a-bundler.md +157 -5
  29. package/docs/es/setup.md +43 -34
  30. package/docs/es/usage/aesthetics.md +20 -14
  31. package/docs/es/usage/buttons.md +6 -2
  32. package/docs/es/usage/composing.md +6 -2
  33. package/docs/es/usage/content-and-layout.md +10 -4
  34. package/docs/es/usage/customizing.md +46 -26
  35. package/docs/es/usage/feedback.md +5 -1
  36. package/docs/es/usage/forms.md +30 -5
  37. package/docs/es/usage/index.md +7 -3
  38. package/docs/es/usage/presets.md +92 -0
  39. package/docs/es/usage/solo.md +4 -2
  40. package/docs/es/usage/theming.md +29 -16
  41. package/docs/es/usage/tooltips.md +2 -2
  42. package/docs/index.md +3 -2
  43. package/docs/integrating/index.md +38 -10
  44. package/docs/integrating/tailwind.md +78 -7
  45. package/docs/integrating/without-a-bundler.md +156 -4
  46. package/docs/pt-BR/accessibility.md +47 -28
  47. package/docs/pt-BR/index.md +4 -3
  48. package/docs/pt-BR/integrating/index.md +38 -10
  49. package/docs/pt-BR/integrating/tailwind.md +79 -8
  50. package/docs/pt-BR/integrating/without-a-bundler.md +157 -5
  51. package/docs/pt-BR/setup.md +43 -34
  52. package/docs/pt-BR/usage/aesthetics.md +20 -14
  53. package/docs/pt-BR/usage/buttons.md +6 -2
  54. package/docs/pt-BR/usage/composing.md +6 -2
  55. package/docs/pt-BR/usage/content-and-layout.md +10 -4
  56. package/docs/pt-BR/usage/customizing.md +46 -26
  57. package/docs/pt-BR/usage/feedback.md +5 -1
  58. package/docs/pt-BR/usage/forms.md +30 -5
  59. package/docs/pt-BR/usage/index.md +7 -3
  60. package/docs/pt-BR/usage/presets.md +92 -0
  61. package/docs/pt-BR/usage/solo.md +4 -2
  62. package/docs/pt-BR/usage/theming.md +22 -9
  63. package/docs/pt-BR/usage/tooltips.md +2 -2
  64. package/docs/setup.md +31 -22
  65. package/docs/usage/aesthetics.md +19 -13
  66. package/docs/usage/buttons.md +5 -1
  67. package/docs/usage/composing.md +5 -1
  68. package/docs/usage/content-and-layout.md +9 -3
  69. package/docs/usage/customizing.md +45 -25
  70. package/docs/usage/feedback.md +4 -0
  71. package/docs/usage/forms.md +29 -4
  72. package/docs/usage/index.md +6 -2
  73. package/docs/usage/presets.md +91 -0
  74. package/docs/usage/solo.md +3 -1
  75. package/docs/usage/theming.md +21 -8
  76. package/docs/usage/tooltips.md +1 -1
  77. package/llms-full.txt +695 -134
  78. package/llms.txt +3 -2
  79. package/package.json +117 -65
  80. package/{dist/tw → tw}/aesthetics/chunky-tile.css +43 -20
  81. package/{dist/tw → tw}/aesthetics/cyber.css +19 -25
  82. package/{dist/tw → tw}/aesthetics/glass.css +110 -36
  83. package/{dist/tw → tw}/aesthetics/neobrutalism.css +41 -21
  84. package/{dist/tw → tw}/aesthetics/pixel.css +3 -0
  85. package/tw/aesthetics/sketch.css +435 -0
  86. package/{dist/tw → tw}/box.css +109 -26
  87. package/tw/components/button.css +11 -0
  88. package/tw/components/button.rules.css +187 -0
  89. package/tw/components/feedback.css +11 -0
  90. package/{dist/tw/components/feedback.css → tw/components/feedback.rules.css} +156 -33
  91. package/tw/components/form.css +11 -0
  92. package/{dist/tw/components/form.css → tw/components/form.rules.css} +584 -141
  93. package/tw/components/index.css +16 -0
  94. package/tw/components/rules.css +41 -0
  95. package/tw/components/surface.css +11 -0
  96. package/tw/components/surface.rules.css +225 -0
  97. package/tw/components/tooltip.css +11 -0
  98. package/{dist/tw/components/tooltip.css → tw/components/tooltip.rules.css} +82 -61
  99. package/{dist/tw → tw}/corner.css +18 -12
  100. package/{dist/tw → tw}/elevation.css +27 -21
  101. package/{dist/tw → tw}/index.css +11 -9
  102. package/tw/index.d.ts +1 -0
  103. package/tw/intent.css +312 -0
  104. package/tw/modifiers.css +127 -0
  105. package/tw/native.css +323 -0
  106. package/tw/presentation.css +139 -0
  107. package/tw/reset.css +10 -0
  108. package/{dist/tw/reset.css → tw/reset.rules.css} +7 -8
  109. package/tw/size.css +34 -0
  110. package/tw/surface.css +9 -0
  111. package/tw/surface.rules.css +212 -0
  112. package/{dist/tw → tw}/theme.css +93 -29
  113. package/tw/typography.css +8 -0
  114. package/{dist/tw/typography.css → tw/typography.rules.css} +0 -3
  115. package/{dist/tw → tw}/utilities/content.css +248 -108
  116. package/tw/utilities/index.css +11 -0
  117. package/tw/utilities/layout.css +210 -0
  118. package/tw/utilities/rules.css +8 -0
  119. package/dist/tw/aesthetics/sketch.css +0 -398
  120. package/dist/tw/components/button.css +0 -139
  121. package/dist/tw/components/index.css +0 -35
  122. package/dist/tw/components/surface.css +0 -184
  123. package/dist/tw/intent.css +0 -229
  124. package/dist/tw/native.css +0 -203
  125. package/dist/tw/palette.css +0 -460
  126. package/dist/tw/presentation.css +0 -68
  127. package/dist/tw/surface.css +0 -61
  128. package/dist/tw/utilities/index.css +0 -6
  129. package/dist/tw/utilities/layout.css +0 -144
  130. /package/{dist/tw → tw}/aesthetics/index.css +0 -0
@@ -0,0 +1,210 @@
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
+ /* Public, read with their defaults, so a value set on any ancestor reaches
161
+ the line. The colour stands in front of the intent. */
162
+ --_divider-color: var(--divider-color, var(--intent-color));
163
+ --_divider-width: var(--divider-width, var(--ui-border-width, var(--border-width)));
164
+
165
+ @apply m-0 border-0;
166
+
167
+ /* Across unless `vertical`, which turns the line to the inline-start edge
168
+ and stretches it down its row. */
169
+ --_vertical-width: var(--_m-vertical) 0px;
170
+ --_vertical-self: var(--_m-vertical) stretch;
171
+ --_vertical-line: var(--_m-vertical) var(--_divider-width);
172
+
173
+ width: var(--_vertical-width, 100%);
174
+ align-self: var(--_vertical-self, auto);
175
+ border-color: var(--_divider-color);
176
+ border-style: var(--ui-rule-style, var(--ui-line-style, solid));
177
+ border-top-width: var(--_vertical-width, var(--_divider-width));
178
+ border-inline-start-width: var(--_vertical-line, 0px);
179
+ }
180
+
181
+ @utility selection-contrast {
182
+ &::selection,
183
+ & *::selection {
184
+ background: var(--color-primary-contrast);
185
+ color: var(--color-primary);
186
+ }
187
+ }
188
+
189
+ /* `.visually-hidden`, the standard clip-based recipe. Tailwind's `sr-only` does
190
+ nothing on the vanilla entries (`.`, `/native`), which compile real CSS from
191
+ a scan of `src/` alone with no Tailwind utility layer to reach, so the
192
+ package publishes its own.
193
+
194
+ It is not named `.sr-only`: on a `/tw` entry the consumer's own Tailwind
195
+ build supplies that utility, and two same-named utilities in one cascade
196
+ collide silently -- the collision `registry.test.ts` polices (see
197
+ `data-table`'s `renamedFrom` in `registry.json`). `@source
198
+ inline("visually-hidden")` in `utilities/index.css` force-emits it on the
199
+ entries with no scannable markup of their own. */
200
+ @utility visually-hidden {
201
+ position: absolute;
202
+ width: 1px;
203
+ height: 1px;
204
+ padding: 0;
205
+ margin: -1px;
206
+ overflow: hidden;
207
+ clip: rect(0, 0, 0, 0);
208
+ white-space: nowrap;
209
+ border-width: 0;
210
+ }
@@ -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`. */
@@ -1,398 +0,0 @@
1
- /* Sketch: uneven elliptical corners, a solid ink edge, and a small hard shadow.
2
- The handwriting face is consumer-supplied, so this file has no font asset or
3
- network side effect. */
4
-
5
- /* The layer map, stated before anything uses a layer -- see `theme.css`. The
6
- aesthetic's token class sits in `components`, below every utility, so a
7
- consumer's own utility or unlayered CSS beats it; the solo class stays
8
- unlayered, because it has to beat a foreign component's unlayered CSS. See
9
- docs/internal/model.md#cascade-layers. */
10
- @layer theme, base, components, utilities;
11
-
12
- @layer components {
13
- .sketch {
14
- /* Complete radii are taken as written, without the size step or corner
15
- pattern. Chips use a smaller version of the same irregular outline.
16
- Surfaces use sharp, hand-drawn square contours tailored for container
17
- dimensions to avoid interior padding encroachment. Knobs follow R8. */
18
- --ui-corner: initial;
19
- --ui-corner-surface: initial;
20
- --ui-corner-tl: initial;
21
- --ui-corner-tr: initial;
22
- --ui-corner-br: initial;
23
- --ui-corner-bl: initial;
24
- --ui-radius: var(--sketch-radius, 255px 15px 225px 15px / 15px 225px 15px 255px);
25
- --ui-radius-surface: var(--sketch-radius-surface, 80px 4px 75px 5px / 3px 70px 4px 80px);
26
- --ui-radius-pill: var(--sketch-radius-pill, 20px 22px 21px 19px / 20px 22px 21px 19px);
27
- --ui-radius-tight: 11px 1px 7px 2px / 2px 7px 1px 11px;
28
- --ui-corner-shape: round;
29
-
30
- --ui-ink: light-dark(var(--color-neutral-950), var(--color-neutral-50));
31
- /* Controls take the theme's control border rather than the ink, which is the
32
- primary colour in both themes; see `neobrutalism.css`. */
33
- --ui-control-ink: var(--color-control-border);
34
- --ui-rule-ink: initial;
35
- --ui-border-width: 1px;
36
- --ui-border-max: 100px;
37
- --ui-line-style: solid;
38
- --ui-rule-style: initial;
39
-
40
- --ui-shadow-ink: 0%;
41
- /* The foundation depth colour is restated so a sketch region nested inside
42
- cyber does not inherit cyber's transparent depth. */
43
- --elevation-color: light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55));
44
- --ui-shadow-x: 2px;
45
- --ui-shadow-y: 2px;
46
- --ui-shadow-blur: 0px;
47
- --ui-shadow-spread: 0px;
48
- --ui-shadow-inset: ;
49
- --ui-shadow-edge: initial;
50
- --ui-halo-blur: initial;
51
- --ui-halo-spread: initial;
52
- --ui-halo-ink: initial;
53
- --ui-focus-inset: initial;
54
-
55
- --ui-active-shadow-x: initial;
56
- --ui-active-shadow-y: initial;
57
- --ui-active-transform: scale(0.97);
58
- --ui-active-translate-x: initial;
59
- --ui-active-translate-y: initial;
60
- --ui-hover-transform: none;
61
- --ui-clip: none;
62
- --ui-clip-tight: none;
63
- --ui-backdrop: none;
64
- --ui-surface-image: initial;
65
- --ui-surface-ground: initial;
66
- --ui-surface-shadow: initial;
67
- --ui-bg-alpha: 1;
68
- --ui-label-weight: initial;
69
- --ui-label-tracking: initial;
70
- --ui-label-case: initial;
71
- --ui-label-shadow: initial;
72
-
73
- font-family: var(--font-sketch, cursive);
74
- }
75
-
76
- @media (prefers-reduced-motion: reduce) {
77
- .sketch {
78
- --ui-active-transform: none;
79
- }
80
- }
81
-
82
- /* Rounded variant: bounded elliptical corners, so the top and bottom edges of
83
- a wide element stay straight instead of bulging into an egg. On the region
84
- with `.sketch`, or on one component inside it. Knobs follow R8.
85
-
86
- Never on a solo element, here or in the rotation below:
87
- `.sketch-solo.sketch-rounded` paints its own outline, and a complete
88
- radius declared on it would inherit into whatever it holds -- a `.btn`
89
- inside a solo toast took a sketch outline on a page with no sketch in
90
- scope. */
91
- .sketch-rounded:not(.sketch-solo) {
92
- --ui-radius: var(--sketch-radius-rounded, 26px 10px 24px 11px / 12px 23px 11px 20px);
93
- --ui-radius-surface: var(--sketch-radius-surface-rounded, 38px 16px 36px 17px / 16px 34px 17px 32px);
94
- --ui-radius-pill: var(--sketch-radius-pill, 24px 16px 23px 17px / 17px 21px 16px 20px);
95
- --ui-radius-tight: 9px 3px 8px 4px / 4px 8px 3px 7px;
96
- }
97
-
98
- /* One region token gives every element the same outline, so the rotation and
99
- the dashed accents are written on components, which the registry records.
100
- The root is a component carrying either class, or one inside either region
101
- and not inside another aesthetic nested there, which keeps its own
102
- material. The list below is the one place other aesthetics are named, and
103
- `registry.test.ts` fails when one is missing from it.
104
-
105
- Rotation is by sibling position, and a field's control takes its field's
106
- position instead of its own, so stacked rows alternate. It is stable for a
107
- given DOM order. A knob, when set, is one outline for every position. */
108
- :is(
109
- .sketch,
110
- .sketch-rounded:not(.sketch-solo),
111
- :is(.sketch, .sketch-rounded:not(.sketch-solo))
112
- :not(
113
- :is(.sketch, .sketch-rounded:not(.sketch-solo)) :is(.neobrutalism, .glass, .pixel, .chunky-tile, .cyber),
114
- :is(.sketch, .sketch-rounded:not(.sketch-solo)) :is(.neobrutalism, .glass, .pixel, .chunky-tile, .cyber) *
115
- )
116
- ) {
117
- /* The pointed outlines: controls, fields, surfaces, and chips. */
118
- &:is(.sketch, .sketch *):not(.sketch-rounded:not(.sketch-solo), .sketch-rounded:not(.sketch-solo) *) {
119
- &:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble) {
120
- &:nth-child(4n + 2) {
121
- --ui-radius: var(--sketch-radius, 18px 240px 15px 255px / 240px 15px 255px 18px);
122
- }
123
-
124
- &:nth-child(4n + 3) {
125
- --ui-radius: var(--sketch-radius, 245px 220px 15px 18px / 18px 15px 245px 235px);
126
- }
127
-
128
- &:nth-child(4n) {
129
- --ui-radius: var(--sketch-radius, 18px 250px 225px 15px / 245px 15px 18px 235px);
130
- }
131
- }
132
-
133
- &:is(.ipt, .textarea, .select, .input-group) {
134
- .field:nth-child(4n + 1) & {
135
- --ui-radius: var(--sketch-radius, 255px 15px 225px 15px / 15px 225px 15px 255px);
136
- }
137
-
138
- .field:nth-child(4n + 2) & {
139
- --ui-radius: var(--sketch-radius, 18px 240px 15px 255px / 240px 15px 255px 18px);
140
- }
141
-
142
- .field:nth-child(4n + 3) & {
143
- --ui-radius: var(--sketch-radius, 245px 220px 15px 18px / 18px 15px 245px 235px);
144
- }
145
-
146
- .field:nth-child(4n) & {
147
- --ui-radius: var(--sketch-radius, 18px 250px 225px 15px / 245px 15px 18px 235px);
148
- }
149
- }
150
-
151
- &:is(.card, .panel, .alert, .data-table) {
152
- &:nth-child(4n + 2) {
153
- --ui-radius-surface: var(--sketch-radius-surface, 4px 75px 5px 80px / 75px 3px 80px 4px);
154
- }
155
-
156
- &:nth-child(4n + 3) {
157
- --ui-radius-surface: var(--sketch-radius-surface, 75px 70px 4px 5px / 4px 3px 75px 70px);
158
- }
159
-
160
- &:nth-child(4n) {
161
- --ui-radius-surface: var(--sketch-radius-surface, 5px 80px 75px 4px / 75px 4px 5px 70px);
162
- }
163
- }
164
-
165
- &:is(.badge, .kbd, .code, .checkbox, .switch, .progress) {
166
- &:nth-child(4n + 2) {
167
- --ui-radius-tight: 2px 8px 1px 10px / 8px 2px 10px 1px;
168
- }
169
-
170
- &:nth-child(4n + 3) {
171
- --ui-radius-tight: 8px 2px 10px 1px / 1px 9px 2px 8px;
172
- }
173
-
174
- &:nth-child(4n) {
175
- --ui-radius-tight: 1px 10px 2px 7px / 9px 1px 8px 2px;
176
- }
177
- }
178
- }
179
-
180
- /* The rounded outlines, in the same four places. */
181
- &:is(.sketch-rounded:not(.sketch-solo), .sketch-rounded:not(.sketch-solo) *) {
182
- &:is(.btn, .ipt, .textarea, .select, .input-group, .pre, .tooltip-bubble) {
183
- &:nth-child(4n + 2) {
184
- --ui-radius: var(--sketch-radius-rounded, 11px 25px 12px 24px / 23px 11px 22px 12px);
185
- }
186
-
187
- &:nth-child(4n + 3) {
188
- --ui-radius: var(--sketch-radius-rounded, 24px 12px 26px 10px / 11px 23px 12px 22px);
189
- }
190
-
191
- &:nth-child(4n) {
192
- --ui-radius: var(--sketch-radius-rounded, 12px 24px 10px 25px / 22px 12px 23px 11px);
193
- }
194
- }
195
-
196
- &:is(.ipt, .textarea, .select, .input-group) {
197
- .field:nth-child(4n + 1) & {
198
- --ui-radius: var(--sketch-radius-rounded, 26px 10px 24px 11px / 12px 23px 11px 20px);
199
- }
200
-
201
- .field:nth-child(4n + 2) & {
202
- --ui-radius: var(--sketch-radius-rounded, 11px 25px 12px 24px / 23px 11px 22px 12px);
203
- }
204
-
205
- .field:nth-child(4n + 3) & {
206
- --ui-radius: var(--sketch-radius-rounded, 24px 12px 26px 10px / 11px 23px 12px 22px);
207
- }
208
-
209
- .field:nth-child(4n) & {
210
- --ui-radius: var(--sketch-radius-rounded, 12px 24px 10px 25px / 22px 12px 23px 11px);
211
- }
212
- }
213
-
214
- &:is(.card, .panel, .alert, .data-table) {
215
- &:nth-child(4n + 2) {
216
- --ui-radius-surface: var(--sketch-radius-surface-rounded, 17px 36px 18px 34px / 33px 16px 32px 17px);
217
- }
218
-
219
- &:nth-child(4n + 3) {
220
- --ui-radius-surface: var(--sketch-radius-surface-rounded, 35px 18px 38px 15px / 17px 32px 16px 34px);
221
- }
222
-
223
- &:nth-child(4n) {
224
- --ui-radius-surface: var(--sketch-radius-surface-rounded, 18px 35px 16px 37px / 31px 17px 34px 16px);
225
- }
226
- }
227
-
228
- &:is(.badge, .kbd, .code, .checkbox, .switch, .progress) {
229
- &:nth-child(4n + 2) {
230
- --ui-radius-tight: 4px 8px 3px 9px / 8px 3px 8px 4px;
231
- }
232
-
233
- &:nth-child(4n + 3) {
234
- --ui-radius-tight: 8px 4px 9px 3px / 3px 9px 4px 8px;
235
- }
236
-
237
- &:nth-child(4n) {
238
- --ui-radius-tight: 3px 9px 4px 8px / 9px 4px 8px 3px;
239
- }
240
- }
241
- }
242
-
243
- /* A pill button keeps a rounded pill in either variant, bounded to the
244
- button's half-height so a wide one keeps flat top and bottom edges. */
245
- &.btn.pill {
246
- --ui-radius-pill: var(--sketch-radius-pill, 24px 16px 23px 17px / 17px 21px 16px 20px);
247
-
248
- &:nth-child(4n + 2) {
249
- --ui-radius-pill: var(--sketch-radius-pill, 17px 23px 16px 24px / 21px 16px 20px 17px);
250
- }
251
-
252
- &:nth-child(4n + 3) {
253
- --ui-radius-pill: var(--sketch-radius-pill, 23px 17px 24px 16px / 16px 20px 17px 21px);
254
- }
255
-
256
- &:nth-child(4n) {
257
- --ui-radius-pill: var(--sketch-radius-pill, 16px 24px 17px 23px / 20px 17px 21px 16px);
258
- }
259
- }
260
-
261
- /* Badges, progress bars, and switches take their chip outline where they
262
- would be fully round. */
263
- &:is(.badge, .progress, .switch) {
264
- --ui-radius-pill: var(--ui-radius-tight);
265
- }
266
-
267
- /* Radios and the tooltip trigger stay circles, slightly uneven, so a radio
268
- is never mistaken for a checkbox. */
269
- &:is(.radio, .tooltip-icon) {
270
- --ui-radius-pill: 48% 52% 46% 54% / 53% 46% 54% 47%;
271
- }
272
-
273
- /* The dashed accents; every other line stays solid. */
274
- &:is(.sketch, .sketch *) {
275
- &.checkbox {
276
- --ui-line-style: dashed;
277
- }
278
-
279
- &:is(.divider, .data-table) {
280
- --ui-rule-style: dashed;
281
- }
282
- }
283
- }
284
- }
285
-
286
- /* Solo: the same look painted onto the one element carrying the class, for an
287
- element the package does not style. See docs/internal/model.md#solo-classes and
288
- the note on `.glass-solo`: it composes with the element's presentation,
289
- intent, and elevation, and reads its material from its own knobs and
290
- foundation tokens with literal fallbacks, never a shared material `--ui-*`
291
- or `--elevation-color` token. Unlayered, and not for this package's own
292
- components. */
293
- .sketch-solo {
294
- /* The composition, the same in every solo class; `registry.test.ts` holds
295
- the copies together. See the note on `.glass-solo`. */
296
- --_solo-intent-color: initial;
297
- --_solo-intent-contrast: initial;
298
- --_solo-intent-strong: initial;
299
- --_solo-intent-border: initial;
300
- --_solo-intent-fill-max: initial;
301
- --_solo-color: var(--_solo-intent-color, var(--color-text, light-dark(oklch(14.5% 0 0), oklch(98.5% 0 0))));
302
- --_solo-contrast: var(
303
- --_solo-intent-contrast,
304
- var(--color-text-contrast, light-dark(oklch(98.5% 0 0), oklch(14.5% 0 0)))
305
- );
306
- --_solo-strong: var(--_solo-intent-strong, var(--color-text-strong, light-dark(oklch(20.5% 0 0), oklch(97% 0 0))));
307
- --_solo-capped: min(var(--ui-fill, 0%), var(--_solo-intent-fill-max, 20%));
308
- --_solo-fill: color-mix(in oklab, var(--_solo-color) var(--_solo-capped), transparent);
309
- --_solo-on-fill: min(var(--ui-fg-on-fill, 0%), max(0%, calc(var(--_solo-capped) * 2 - 100%)));
310
- --_solo-fg: color-mix(in oklab, var(--_solo-contrast) var(--_solo-on-fill), var(--_solo-strong));
311
- /* The line with no intent on the element: this aesthetic's own ink. */
312
- --_solo-ink: var(
313
- --_solo-intent-border,
314
- light-dark(var(--color-neutral-950, oklch(14.5% 0 0)), var(--color-neutral-50, oklch(98.5% 0 0)))
315
- );
316
- --_solo-edge: color-mix(in oklab, var(--_solo-ink) var(--ui-border, 100%), var(--_solo-fill));
317
- --_solo-depth: calc(2px * var(--ui-elevation, 1));
318
-
319
- border: 1px solid var(--_solo-edge);
320
- /* The surface shape: the element this exists for is usually a pane. An action
321
- takes the control shape below. */
322
- border-radius: var(--sketch-radius-surface, 80px 4px 75px 5px / 3px 70px 4px 80px);
323
- /* The aesthetic's neutral depth cue, not the ink: the class casts its 2px
324
- offset in the depth colour, and casting a solo pane in full ink would read
325
- as a heavier, neobrutalist slab. The depth colour is a literal, for the reason
326
- `.glass-solo` gives. */
327
- box-shadow:
328
- var(--_solo-depth) var(--_solo-depth) 0 0 light-dark(rgb(15 23 42 / 0.08), rgb(0 0 0 / 0.55)),
329
- inset 0 0 0 100vmax var(--_solo-fill);
330
- font-family: var(--font-sketch, cursive);
331
- }
332
-
333
- /* An intent class on the element colours it, as on a component. Named rather
334
- than read from `--intent-*` alone: those slots inherit, so a `.success`
335
- container would colour a solo element where it leaves a component neutral. */
336
- .sketch-solo:is(.primary, .secondary, .success, .warning, .destructive, .info) {
337
- --_solo-intent-color: var(--intent-color);
338
- --_solo-intent-contrast: var(--intent-contrast);
339
- --_solo-intent-strong: var(--intent-strong);
340
- --_solo-intent-border: var(--intent-border);
341
- --_solo-intent-fill-max: var(--intent-fill-max);
342
- }
343
-
344
- /* The text colour is written only where a fill or an intent is asked for, on
345
- the element or by a container's fill class. Anywhere else the element keeps
346
- its own: a dark toast keeps its light text. */
347
- .sketch-solo:is(
348
- .solid,
349
- .soft,
350
- .ghost,
351
- .primary,
352
- .secondary,
353
- .success,
354
- .warning,
355
- .destructive,
356
- .info,
357
- :is(.solid, .soft, .ghost) *
358
- ) {
359
- color: var(--_solo-fg);
360
- }
361
-
362
- /* An action takes the expressive control shape. */
363
- .sketch-solo:is(
364
- button,
365
- a[href],
366
- [role="button"],
367
- summary,
368
- input[type="button"],
369
- input[type="submit"],
370
- input[type="reset"]
371
- ) {
372
- border-radius: var(--sketch-radius, 255px 15px 225px 15px / 15px 225px 15px 255px);
373
- }
374
-
375
- /* With `.sketch-rounded`, the rounded outlines, through their own knobs. */
376
- .sketch-solo.sketch-rounded {
377
- border-radius: var(--sketch-radius-surface-rounded, 38px 16px 36px 17px / 16px 34px 17px 32px);
378
- }
379
-
380
- .sketch-solo.sketch-rounded:is(
381
- button,
382
- a[href],
383
- [role="button"],
384
- summary,
385
- input[type="button"],
386
- input[type="submit"],
387
- input[type="reset"]
388
- ) {
389
- border-radius: var(--sketch-radius-rounded, 26px 10px 24px 11px / 12px 23px 11px 20px);
390
- }
391
-
392
- /* This entrypoint may be the only package stylesheet loaded, so it cannot rely
393
- on theme.css's forced-colors material reset. */
394
- @media (forced-colors: active) {
395
- .sketch-solo {
396
- border-style: solid;
397
- }
398
- }