actual-css 0.2.0 → 0.3.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 (214) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +24 -9
  3. package/dist/actual-themes.min.css +1 -0
  4. package/dist/actual.css +1244 -915
  5. package/dist/actual.js +1 -3
  6. package/dist/actual.min.css +1 -1
  7. package/dist/optional.css +1048 -0
  8. package/dist/optional.min.css +1 -0
  9. package/docs/design-notes/browser-support.md +94 -14
  10. package/docs/design-notes/cascade-layer.md +1 -1
  11. package/docs/design-notes/enhancement-contract.md +11 -14
  12. package/docs/design-notes/forced-colors.md +105 -0
  13. package/docs/design-notes/naming.md +2 -1
  14. package/docs/design-notes/platform-alignment.md +492 -0
  15. package/docs/design-notes/references.md +8 -0
  16. package/docs/design-notes/widget-primitives.md +37 -1
  17. package/docs/navigation.json +135 -0
  18. package/docs/pages/components/accordion.md +80 -0
  19. package/docs/pages/components/alert.md +203 -0
  20. package/docs/pages/components/aura.md +35 -0
  21. package/docs/pages/components/avatar.md +95 -0
  22. package/docs/pages/components/badge.md +102 -0
  23. package/docs/pages/components/breadcrumb.md +19 -0
  24. package/docs/pages/components/button.md +205 -0
  25. package/docs/pages/components/card.md +183 -0
  26. package/docs/pages/components/chat.md +50 -0
  27. package/docs/pages/components/dialog.md +367 -0
  28. package/docs/pages/components/drawer.md +113 -0
  29. package/docs/pages/components/fab.md +118 -0
  30. package/docs/pages/components/key.md +33 -0
  31. package/docs/pages/components/meter.md +23 -0
  32. package/docs/pages/components/navbar.md +92 -0
  33. package/docs/pages/components/pagination.md +55 -0
  34. package/docs/pages/components/progress.md +29 -0
  35. package/docs/pages/components/skeleton.md +38 -0
  36. package/docs/pages/components/spinner.md +93 -0
  37. package/docs/pages/components/table.md +102 -0
  38. package/docs/pages/enhancements/flyout.md +391 -0
  39. package/docs/pages/enhancements/overview.md +36 -0
  40. package/docs/pages/enhancements/scrollspy.md +71 -0
  41. package/docs/pages/enhancements/status-bar.md +72 -0
  42. package/docs/pages/enhancements/tabs.md +80 -0
  43. package/docs/pages/enhancements/tooltip.md +130 -0
  44. package/docs/pages/examples/overview.md +41 -0
  45. package/docs/pages/forms/choice-cards.md +102 -0
  46. package/docs/pages/forms/controls.md +32 -0
  47. package/docs/pages/forms/detached-actions.md +59 -0
  48. package/docs/pages/forms/floating-field.md +88 -0
  49. package/docs/pages/forms/form-actions.md +56 -0
  50. package/docs/pages/forms/input-policy.md +91 -0
  51. package/docs/pages/forms/joined-controls.md +37 -0
  52. package/docs/pages/forms/labels.md +42 -0
  53. package/docs/pages/forms/otp.md +50 -0
  54. package/docs/pages/forms/overview.md +188 -0
  55. package/docs/pages/forms/password.md +40 -0
  56. package/docs/pages/forms/range.md +17 -0
  57. package/docs/pages/forms/states-and-sizes.md +321 -0
  58. package/docs/pages/forms/sticky-actions.md +187 -0
  59. package/docs/pages/forms/switch.md +31 -0
  60. package/docs/pages/forms/validation.md +241 -0
  61. package/docs/{mental-model.md → pages/foundations/philosophy.md} +33 -18
  62. package/docs/pages/foundations/theming.md +92 -0
  63. package/docs/pages/foundations/tokens.md +421 -0
  64. package/docs/{typography.md → pages/foundations/typography.md} +27 -9
  65. package/docs/pages/guides/bootstrap.md +438 -0
  66. package/docs/pages/guides/introduction.md +157 -0
  67. package/docs/pages/guides/optional-components.md +33 -0
  68. package/docs/pages/guides/progressive-enhancement.md +686 -0
  69. package/docs/pages/guides/tailwind.md +455 -0
  70. package/docs/pages/layout/app-shell.md +25 -0
  71. package/docs/pages/layout/center.md +29 -0
  72. package/docs/pages/layout/cluster.md +57 -0
  73. package/docs/pages/layout/frame.md +30 -0
  74. package/docs/pages/layout/grid.md +142 -0
  75. package/docs/pages/layout/list.md +41 -0
  76. package/docs/pages/layout/media.md +21 -0
  77. package/docs/pages/layout/overview.md +37 -0
  78. package/docs/pages/layout/scroll-snap.md +54 -0
  79. package/docs/pages/layout/sidebar-layout.md +27 -0
  80. package/docs/pages/layout/stack.md +18 -0
  81. package/docs/pages/layout/switcher.md +36 -0
  82. package/docs/pages/layout/topbar.md +23 -0
  83. package/docs/pages/patterns/actions.md +52 -0
  84. package/docs/pages/patterns/code-block.md +36 -0
  85. package/docs/pages/patterns/exclusive-accordion.md +16 -0
  86. package/docs/pages/patterns/hierarchical-nav.md +26 -0
  87. package/docs/pages/patterns/icon-input.md +25 -0
  88. package/docs/pages/patterns/intent-nesting.md +3 -0
  89. package/docs/pages/patterns/navigation-list.md +235 -0
  90. package/docs/pages/patterns/overview.md +58 -0
  91. package/docs/pages/patterns/structured-lists.md +47 -0
  92. package/docs/pages/utilities/accessibility.md +34 -0
  93. package/docs/pages/utilities/flex.md +105 -0
  94. package/docs/pages/utilities/links.md +18 -0
  95. package/docs/pages/utilities/list.md +31 -0
  96. package/docs/pages/utilities/overflow.md +43 -0
  97. package/docs/pages/utilities/overview.md +18 -0
  98. package/docs/pages/utilities/shape.md +25 -0
  99. package/docs/pages/utilities/sizing-wrapping.md +115 -0
  100. package/docs/pages/utilities/spacing.md +79 -0
  101. package/docs/pages/utilities/text.md +43 -0
  102. package/llms.txt +4 -4
  103. package/package.json +20 -12
  104. package/src/css/actual.css +12 -1
  105. package/src/css/base.css +3 -5
  106. package/src/css/components/accordion.css +18 -30
  107. package/src/css/components/actions.css +4 -1
  108. package/src/css/components/alert.css +126 -99
  109. package/src/css/components/avatar.css +16 -10
  110. package/src/css/components/badge.css +55 -35
  111. package/src/css/components/breadcrumb.css +7 -15
  112. package/src/css/components/busy.css +6 -0
  113. package/src/css/components/button.css +78 -32
  114. package/src/css/components/card.css +17 -37
  115. package/src/css/components/drawer.css +30 -13
  116. package/src/css/components/flyout.css +39 -109
  117. package/src/css/components/index.css +1 -0
  118. package/src/css/components/join.css +14 -2
  119. package/src/css/components/key.css +2 -0
  120. package/src/css/components/menu.css +125 -0
  121. package/src/css/components/meter.css +0 -23
  122. package/src/css/components/modal.css +162 -7
  123. package/src/css/components/navbar.css +17 -18
  124. package/src/css/components/overline.css +0 -7
  125. package/src/css/components/pagination.css +1 -1
  126. package/src/css/components/progress.css +8 -26
  127. package/src/css/components/skeleton.css +7 -0
  128. package/src/css/components/spinner.css +6 -7
  129. package/src/css/components/status-bar.css +15 -24
  130. package/src/css/components/surface.css +2 -8
  131. package/src/css/components/tab.css +19 -48
  132. package/src/css/components/table.css +7 -5
  133. package/src/css/components/tooltip.css +14 -7
  134. package/src/css/focus.css +14 -38
  135. package/src/css/forms/choice-card.css +13 -14
  136. package/src/css/forms/choice.css +21 -27
  137. package/src/css/forms/control.css +16 -17
  138. package/src/css/forms/custom-select.css +9 -11
  139. package/src/css/forms/form-actions.css +14 -3
  140. package/src/css/forms/form.css +7 -4
  141. package/src/css/forms/index.css +4 -4
  142. package/src/css/forms/input-icon.css +30 -12
  143. package/src/css/forms/native.css +50 -11
  144. package/src/css/forms/range.css +17 -9
  145. package/src/css/forms/select.css +8 -8
  146. package/src/css/forms/switch.css +14 -12
  147. package/src/css/forms/validation.css +32 -5
  148. package/src/css/grid.css +19 -18
  149. package/src/css/intents.css +2 -2
  150. package/src/css/layout.css +29 -1
  151. package/src/css/optional/aura.css +93 -0
  152. package/src/css/optional/chat.css +105 -0
  153. package/src/css/optional/fab.css +104 -0
  154. package/src/css/optional/floating-field.css +87 -0
  155. package/src/css/optional/index.css +5 -0
  156. package/src/css/optional/layout-extra.css +7 -4
  157. package/src/css/optional/otp.css +115 -0
  158. package/src/css/optional/scroll-snap.css +6 -0
  159. package/src/css/optional/scroller.css +13 -7
  160. package/src/css/optional/typography-fluid.css +5 -0
  161. package/src/css/optional/utilities-extra.css +17 -2
  162. package/src/css/prose.css +18 -8
  163. package/src/css/reset.css +0 -10
  164. package/src/css/theme.css +21 -5
  165. package/src/css/themes/cyberpunk.css +1 -1
  166. package/src/css/themes/dim.css +3 -3
  167. package/src/css/themes/edge.css +8 -10
  168. package/src/css/themes/index.css +3 -3
  169. package/src/css/themes/{dark.css → indigo.css} +5 -4
  170. package/src/css/themes/neon.css +5 -5
  171. package/src/css/themes/square.css +0 -3
  172. package/src/css/tokens.css +74 -20
  173. package/src/css/utilities.css +8 -10
  174. package/src/css/variants.css +37 -65
  175. package/src/js/command.js +1 -3
  176. package/src/js/context-menu.js +67 -35
  177. package/src/js/dialog.js +68 -79
  178. package/src/js/dismiss.js +15 -0
  179. package/src/js/enhance.js +54 -23
  180. package/src/js/enhancement-loader.js +301 -0
  181. package/src/js/events.js +3 -0
  182. package/src/js/filter.js +3 -3
  183. package/src/js/floating.js +101 -131
  184. package/src/js/flyout.js +104 -87
  185. package/src/js/focus-group.js +116 -0
  186. package/src/js/focus.js +6 -1
  187. package/src/js/index.js +4 -2
  188. package/src/js/input.js +1 -1
  189. package/src/js/keys.js +27 -0
  190. package/src/js/mask.js +7 -6
  191. package/src/js/menu.js +87 -34
  192. package/src/js/parse-config.js +47 -0
  193. package/src/js/password.js +9 -1
  194. package/src/js/scrollspy.js +12 -4
  195. package/src/js/selectors.js +0 -7
  196. package/src/js/status.js +3 -1
  197. package/src/js/surface.js +185 -136
  198. package/src/js/tab.js +36 -53
  199. package/src/js/tooltip.js +53 -31
  200. package/src/js/validation.js +34 -8
  201. package/dist/actual.js.map +0 -31
  202. package/docs/README.md +0 -28
  203. package/docs/components.md +0 -860
  204. package/docs/design-notes/previous-work.md +0 -5
  205. package/docs/forms.md +0 -1265
  206. package/docs/javascript.md +0 -496
  207. package/docs/layout.md +0 -480
  208. package/docs/patterns.md +0 -504
  209. package/docs/reserved.md +0 -7
  210. package/docs/tokens.md +0 -455
  211. package/docs/ui.md +0 -929
  212. package/docs/utilities.md +0 -384
  213. package/src/css/dialog-fallback.css +0 -56
  214. package/src/js/dialog-fallback.js +0 -163
package/docs/utilities.md DELETED
@@ -1,384 +0,0 @@
1
- # Utilities
2
-
3
- Utilities are a small escape hatch for common single-purpose needs. They should support composition, not become the primary way to build UI.
4
-
5
- - Prefer semantic HTML, components, and layout primitives first.
6
- - Add utilities only when the rule is broadly useful and unlikely to become a component.
7
- - Keep utility names stable, boring, and few.
8
- - Utilities should use logical properties where relevant.
9
-
10
- ## Accessibility
11
-
12
- ### Screen Reader Only
13
-
14
- Use `.sr-only` for text that should be available to assistive technology but visually hidden.
15
-
16
- ```html
17
- <button class="btn ghost" type="button">
18
- <i class="ti ti-menu-2" aria-hidden="true"></i>
19
- <span class="sr-only">Open navigation</span>
20
- </button>
21
- ```
22
-
23
- ```css
24
- .sr-only {
25
- position: absolute;
26
- inline-size: 1px;
27
- block-size: 1px;
28
- padding: 0;
29
- margin: -1px;
30
- overflow: hidden;
31
- clip: rect(0, 0, 0, 0);
32
- white-space: nowrap;
33
- border: 0;
34
- }
35
- ```
36
-
37
- ## Overflow
38
-
39
- > Explicit overflow handling for content that may exceed its container.
40
-
41
- Use `.overflow-auto` when content may overflow its container, especially tables and code-like regions.
42
-
43
- ```html
44
- <div class="overflow-auto">
45
- <table class="table">
46
- <caption>Team members</caption>
47
- <thead>
48
- <tr>
49
- <th>Name</th>
50
- <th>Role</th>
51
- </tr>
52
- </thead>
53
- <tbody>
54
- <tr>
55
- <td>Alice Johnson</td>
56
- <td>Admin</td>
57
- </tr>
58
- </tbody>
59
- </table>
60
- </div>
61
- ```
62
-
63
- ```css
64
- .overflow-auto {
65
- overflow: auto;
66
- }
67
- ```
68
-
69
- ## Sizing And Wrapping
70
-
71
- > Small layout corrections for controls, labels, and compact rails.
72
-
73
- Use `.fit` when a control or element should shrink to its content instead of filling the available inline space.
74
-
75
- ```html
76
- <select class="select fit" aria-label="Theme">
77
- <option>System</option>
78
- <option>Light</option>
79
- <option>Dark</option>
80
- </select>
81
- ```
82
-
83
- Use `.nowrap` on a flex layout such as `.cluster` when the group must stay on one line.
84
-
85
- ```html
86
- <div class="cluster nowrap sm">
87
- <select class="select sm fit" aria-label="Segment">
88
- <option>All segments</option>
89
- </select>
90
- <button class="btn sm outline" type="button">Filter</button>
91
- </div>
92
- ```
93
-
94
- Use `.truncate` on the flexible item that should ellipsize inside a constrained row.
95
-
96
- ```html
97
- <header class="cluster nowrap">
98
- <strong class="truncate">A long account name that should not push actions away</strong>
99
- <button class="btn sm ghost" type="button">Open</button>
100
- </header>
101
- ```
102
-
103
- ```css
104
- .fit {
105
- inline-size: fit-content;
106
- max-inline-size: 100%;
107
- }
108
-
109
- .nowrap {
110
- flex-wrap: nowrap;
111
- white-space: nowrap;
112
- }
113
-
114
- .truncate {
115
- min-inline-size: 0;
116
- overflow: hidden;
117
- text-overflow: ellipsis;
118
- white-space: nowrap;
119
- }
120
- ```
121
-
122
- ### Scroller
123
-
124
- Use `.scroller` to apply optional framework scrollbar treatment to a scroll container. It styles the scrollbar only; pair it with `.overflow-auto` or a component that already creates overflow.
125
-
126
- `scroller` is not imported by `actual.css`. Import it explicitly when a project wants Actual CSS scrollbar chrome instead of the native OS default:
127
-
128
- ```css
129
- @import "actual-css/css/optional/scroller";
130
- ```
131
-
132
- ```html
133
- <div class="overflow-auto scroller" style="max-block-size: 12rem">
134
- <div class="stack">
135
- <p>Scrollable content keeps the native scrollbar but makes it quieter.</p>
136
- <p>Long content can keep flowing without forcing every component to invent its own scrollbar rules.</p>
137
- <p>The utility exposes local custom properties for one-off tuning.</p>
138
- </div>
139
- </div>
140
- ```
141
-
142
- ```css
143
- .scroller {
144
- --scroller-size: 0.625rem;
145
- --scroller-padding: 0.125rem;
146
- --scroller-track: transparent;
147
- --scroller-thumb: var(--border);
148
- --scroller-thumb-hover: var(--text-muted);
149
-
150
- scrollbar-color: var(--scroller-thumb) var(--scroller-track);
151
- scrollbar-width: thin;
152
- }
153
- ```
154
-
155
- Customize locally when a scroll surface needs more contrast:
156
-
157
- ```html
158
- <div class="overflow-auto scroller"
159
- style="--scroller-thumb: var(--text-muted); --scroller-thumb-hover: var(--text)">
160
- ...
161
- </div>
162
- ```
163
-
164
- For rounded scroll containers, keep the thumb visually away from the edge by tuning `--scroller-padding` rather than adding extra wrappers or masking pseudo-elements.
165
-
166
- ## Metadata Separator
167
-
168
- > A small inline dot for separating facts in a metadata row.
169
-
170
- Use `.dot` between short facts in a byline, timestamp row, or breadcrumb-like list of details — anywhere a plain `·` character would otherwise be typed as text (which screen readers announce awkwardly).
171
-
172
- ```html
173
- <p class="cluster" style="--cluster-justify: flex-start;">
174
- <span>Ada Meridian</span>
175
- <span class="dot" aria-hidden="true"></span>
176
- <time datetime="2026-06-12">June 12, 2026</time>
177
- <span class="dot" aria-hidden="true"></span>
178
- <span>8 min read</span>
179
- </p>
180
- ```
181
-
182
- ```css
183
- .dot {
184
- flex: none;
185
- inline-size: 0.25rem;
186
- block-size: 0.25rem;
187
- border-radius: var(--radius-full);
188
- background: var(--text-subtle);
189
- }
190
- ```
191
-
192
- Always mark it `aria-hidden="true"` — it is a visual separator, not content.
193
-
194
- ## Flex Helpers
195
-
196
- > Small flex helpers for grow behavior and other one-line needs.
197
-
198
- ### Grow
199
-
200
- Use `.grow` when one item in a flex layout should take available space without overflowing.
201
-
202
- ```html
203
- <header class="cluster">
204
- <a href="/" class="brand">Actual CSS</a>
205
- <nav class="grow" aria-label="Main navigation">
206
- <a href="/docs">Docs</a>
207
- <a href="/components">Components</a>
208
- </nav>
209
- <button class="btn ghost" type="button">Menu</button>
210
- </header>
211
- ```
212
-
213
- ```css
214
- .grow {
215
- flex: 1 1 auto;
216
- min-inline-size: 0;
217
- }
218
- ```
219
-
220
- ### Item Alignment
221
-
222
- Use `.items-start` on flex or grid layouts when children should keep their natural height and align to the block-start edge. This is especially useful for form fields in a grid, where the default grid stretch would make short fields as tall as taller neighbors.
223
-
224
- ```html
225
- <div class="grid items-start">
226
- <label class="field">
227
- <span class="field-label">Name</span>
228
- <input type="text" />
229
- </label>
230
- <label class="field">
231
- <span class="field-label">Notes</span>
232
- <textarea></textarea>
233
- </label>
234
- </div>
235
- ```
236
-
237
- Use `.items-center` when a flex or grid layout should center its children on the cross axis. Use `.items-end` when children should align to the block-end edge.
238
-
239
- ## Spacing Helpers
240
-
241
- > Semantic step helpers for gap, padding, and margin — the most common inline-style escape hatches.
242
-
243
- Spacing helpers use a restrained semantic scale:
244
-
245
- - `-sm` — small step, `--space-2` (0.5rem)
246
- - Default — standard step, `--space-4` (1rem)
247
- - `-lg` — large step, `--space-5` (1.5rem)
248
-
249
- All map to logical properties (`padding-block`, `margin-block-end`, etc.) for writing-direction safety.
250
-
251
- ### Gap
252
-
253
- Override the default gap from layout primitives (`.stack`, `.cluster`, `.grid`):
254
-
255
- ```html
256
- <ul class="cluster">
257
- <li><a href="/about" class="btn ghost">About</a></li>
258
- <li><a href="/contact" class="btn ghost">Contact</a></li>
259
- </ul>
260
- ```
261
-
262
- - `.gap-none` → `gap: 0`
263
-
264
- ### Padding
265
-
266
- Block (vertical) and inline (horizontal) padding. Values respond to the `.sm` / `.lg` modifiers.
267
-
268
- ```html
269
- <section role="tabpanel" class="py">
270
- Panel content with breathing room above and below.
271
- </section>
272
- ```
273
-
274
- - `.py` → `padding-block: var(--variant-space)`
275
- - `.px` → `padding-inline: var(--variant-space)`
276
-
277
- ### Margin
278
-
279
- Block-start and block-end margin for giving elements room:
280
-
281
- ```html
282
- <h2 class="mbs">A section heading with space above</h2>
283
- ```
284
-
285
- - `.mbs` → `margin-block-start: var(--variant-space)`
286
- - `.mbe` → `margin-block-end: var(--variant-space)`
287
-
288
- No `mbs-none` / `mbe-none` — use `margin: 0` via `.list-reset` for lists, or a layout primitive that already resets margins (`.stack > *`).
289
-
290
- ## Text Helpers
291
-
292
- > Lightweight helpers for muted or secondary text without a full color scale.
293
-
294
- ### Muted
295
-
296
- Use `.muted` for secondary text when no semantic element already carries the meaning.
297
-
298
- ```html
299
- <p class="muted">Last updated June 12, 2026.</p>
300
- ```
301
-
302
- ```css
303
- .muted {
304
- color: var(--text-muted);
305
- }
306
- ```
307
-
308
- Do not create a full text color utility scale. Intent colors belong to components and state, not arbitrary text decoration.
309
-
310
- ### Text Alignment
311
-
312
- Use `.text-start`, `.text-center`, or `.text-end` when a component or layout primitive does not already set alignment. These use logical properties so they follow the writing direction.
313
-
314
- ### Text Wrap
315
-
316
- `.text-balance` and `.text-pretty` opt elements outside `.prose` into balanced or pretty text wrapping. They are safe progressive enhancements: browsers that do not support a `text-wrap` value ignore that declaration and keep normal wrapping.
317
-
318
- ### Lead
319
-
320
- `.lead` is a slightly larger, more relaxed reading-introduction paragraph (`1.125em`, `--line-height-relaxed`). Use it for introductory text in editorial surfaces. For fluid headline sizing, use `src/css/optional/typography-fluid.css`.
321
-
322
- ## Shape Helpers
323
-
324
- > Rare shape utilities for cases that must be perfectly round or square.
325
-
326
- Shape utilities should be rare because shape is mostly theme-level.
327
-
328
- ### Circle
329
-
330
- Use `.circle` only when an element must be perfectly round.
331
-
332
- ```html
333
- <img class="circle" src="https://i.pravatar.cc/48?img=5" alt="Jane Doe" width="48" height="48" />
334
- ```
335
-
336
- ```css
337
- .circle {
338
- border-radius: var(--radius-full);
339
- }
340
- ```
341
-
342
- Do not add `.rounded-sm`, `.rounded-lg`, `.square`, or `.pill` unless repeated real use proves they are needed.
343
-
344
- ## Content
345
-
346
- ### Measure
347
-
348
- `.measure` caps a block at a readable width using `--prose-measure`. It does not center — combine with `.center` for the common centered reading column, or with `margin-inline: auto` for a one-off centered block.
349
-
350
- Use it for any content that needs a comfortable measure: prose articles, TOC lists, form fields, callouts. Avoid using it for full-bleed surfaces.
351
-
352
- ## List Helpers
353
-
354
- ### List Reset
355
-
356
- `.list-reset` removes the native list chrome (margin, padding, markers) from any list. It is the generic version of `.nav-list` — use `.nav-list` when the list is a navigation list for semantic intent, and `.list-reset` for everything else (tag clouds, footer columns, related items, comment threads, embedded controls).
357
-
358
- ## Editorial Labels
359
-
360
- ### Overline
361
-
362
- `.overline` is a small editorial label: muted color, smaller size, uppercase, slight letter-spacing. It does not impose a shape by itself. Add `.pill` for a bordered rounded chip, and combine with an intent class (`.primary`, `.success`, etc.) to tint the chip's text, border, and background.
363
-
364
- The overline exists because categories, kicker labels, and section markers recur across editorial surfaces, and `.badge` is the wrong shape for them. `.badge` is a status indicator; `.overline` is metadata.
365
-
366
- ## Link Variants
367
-
368
- ### Plain
369
-
370
- `.link-plain` removes the link's underline and inherits the surrounding color. Use for chrome that is conceptually a link (a card title, a table row action, a tag, a breadcrumb segment) but should not look like prose.
371
-
372
- ### Muted
373
-
374
- `.link-muted` is a `.link-plain` that starts in the muted text color and shifts to the full text color on hover. Use for navigation lists, table of contents, and other secondary navigation surfaces.
375
-
376
- ## Non-Goals
377
-
378
- > Utilities deliberately excluded to keep the surface small and intentional.
379
-
380
- - No display scale such as `.block`, `.flex`, `.grid` — use layout primitives.
381
- - No color scales such as `.text-primary` or `.bg-success` — intent colors belong to components and state.
382
- - No breakpoint utility variants — use container queries or layout primitives.
383
- - No utility variants for hover, focus, dark mode, or arbitrary selectors — use component states.
384
- - No full spacing scale with every step and direction — the 17 spacing helpers above cover the most common escape hatches.
@@ -1,56 +0,0 @@
1
- /*
2
- * Legacy dialog fallback — presentation for the dialog-fallback.js shim
3
- * (browsers without native <dialog>: Safari <= 15.3, Firefox <= 97).
4
- *
5
- * Isolated in its own file so a custom bundle can opt out by dropping this
6
- * import; the JS side is disabled with data-dialog-fallback="false" on the
7
- * root element or on a dialog. Must load before component styles so ties
8
- * such as dialog.modal's padding resolve in the component's favor.
9
- *
10
- * The whole file is inert on modern browsers: rules key on the
11
- * .dialog-fallback marker written by the shim, so browsers that support
12
- * <dialog> but not :modal are never affected either.
13
- */
14
- @supports not (selector(dialog:modal)) {
15
- /* Browsers without native <dialog> ship no UA dialog styles at all;
16
- approximate them. :where() keeps specificity at dialog[open] level so
17
- component styles such as dialog.modal still override the emulation. */
18
- dialog[open]:where(.dialog-fallback) {
19
- position: absolute;
20
- inset-inline: 0;
21
- width: -moz-fit-content;
22
- width: fit-content;
23
- max-inline-size: calc(100% - 2rem);
24
- margin: auto;
25
- padding: var(--space-4, 1em);
26
- border: var(--border-width, 1px) solid var(--border, currentColor);
27
- background: var(--surface-raised, #fff);
28
- color: var(--text, inherit);
29
- }
30
-
31
- /* Open modally: fixed near the top (no fit-content in the block axis on
32
- these browsers, so no vertical centering) and above menus, below
33
- tooltips. Legacy-only layer, hence no z-index token. The spread shadow is
34
- the visible backdrop: the dialog is its own stacking context, where a
35
- negative z-index child paints above the element's background, so the
36
- dimming cannot live on the ::before. */
37
- dialog[open].is-fallback-modal {
38
- position: fixed;
39
- inset-block: 8vh auto;
40
- max-block-size: 84vh;
41
- overflow: auto;
42
- z-index: 40;
43
- box-shadow: 0 0 0 100vmax var(--backdrop-fill, rgb(0 0 0 / 35%));
44
- }
45
-
46
- /* Transparent stand-in for ::backdrop, hit-testing only. Clicks on it hit
47
- the dialog element outside its own box, which dialog.js already treats as
48
- a backdrop click, and it blocks pointer interaction with the page behind
49
- the modal. */
50
- dialog[open].is-fallback-modal::before {
51
- content: "";
52
- position: fixed;
53
- inset: 0;
54
- z-index: -1;
55
- }
56
- }
@@ -1,163 +0,0 @@
1
- /*
2
- * Dialog fallback — minimal per-element shim for browsers without native
3
- * <dialog> support (Safari <= 15.3, Firefox <= 97, both below Baseline 2023).
4
- *
5
- * Standalone side-effect module: the default runtime imports it, a custom
6
- * build opts out by omitting it — dialog.js has no dependency on this file
7
- * and falls back to its acknowledgement alert without it. On supporting
8
- * browsers importing this module registers nothing.
9
- *
10
- * Not a polyfill: no top layer, no focus trap, no inert background. It only
11
- * provides show()/showModal()/close(), an `open` property, and the
12
- * form[method=dialog] close-on-submit contract (otherwise those forms really
13
- * navigate on legacy browsers), so dialog.js can run its normal wiring —
14
- * backdrop click, Escape cancel, close events, focus restore, and the scroll
15
- * lock all come from that wiring, not from here.
16
- *
17
- * Presentation lives in dialog-fallback.css, keyed on the classes written
18
- * below. The simulated backdrop is split in two there: a spread box-shadow
19
- * for the dimming, and a transparent ::before covering the viewport for
20
- * hit-testing — clicks on it target the dialog element outside its own box,
21
- * which dialog.js already treats as a backdrop click, and it blocks pointer
22
- * interaction with the page behind the modal.
23
- *
24
- * An adopter-provided polyfill (e.g. dialog-polyfill) still wins: elements it
25
- * already patched expose showModal() and are left untouched.
26
- */
27
-
28
- import { targetFor } from "./command.js";
29
- import enhance from "./enhance.js";
30
- import { CLASSES } from "./selectors.js";
31
-
32
- function supportsDialog() {
33
- return (
34
- typeof HTMLDialogElement !== "undefined" &&
35
- typeof HTMLDialogElement.prototype.showModal === "function"
36
- );
37
- }
38
-
39
- function focusInitial(dialog) {
40
- const target = dialog.querySelector("[autofocus]") || dialog;
41
- if (target === dialog && !dialog.hasAttribute("tabindex")) {
42
- dialog.setAttribute("tabindex", "-1");
43
- }
44
- target.focus?.();
45
- }
46
-
47
- /**
48
- * Patch one dialog element with rudimentary show/showModal/close support.
49
- * No-op when the element is already controllable (native or polyfilled).
50
- *
51
- * @param {HTMLElement} dialog A <dialog> element.
52
- */
53
- export default function shimDialog(dialog) {
54
- if (
55
- typeof dialog.show === "function" &&
56
- typeof dialog.showModal === "function" &&
57
- typeof dialog.close === "function"
58
- ) {
59
- return;
60
- }
61
-
62
- const doc = dialog.ownerDocument;
63
- let escController = null;
64
- let savedScroll = null;
65
-
66
- function stopEscapeListener() {
67
- escController?.abort();
68
- escController = null;
69
- }
70
-
71
- function handleSubmit(event) {
72
- const form = event.target;
73
- // Read the attribute: on these browsers "dialog" is an invalid method
74
- // value, so the reflected form.method property reports "get" and the
75
- // form would otherwise really submit and navigate away.
76
- if (form?.getAttribute?.("method")?.toLowerCase() !== "dialog") return;
77
- event.preventDefault();
78
- const submitter =
79
- event.submitter || (doc.activeElement?.form === form ? doc.activeElement : null);
80
- dialog.close(submitter?.value || "");
81
- }
82
-
83
- function handleEscape(event) {
84
- if (event.key !== "Escape") return;
85
- event.preventDefault();
86
- const cancel = new Event("cancel", { cancelable: true });
87
- // dialog.js always claims the cancel event and decides itself whether to
88
- // close; only an unwired dialog falls through to the direct close.
89
- if (dialog.dispatchEvent(cancel)) {
90
- dialog.close();
91
- }
92
- }
93
-
94
- function open(modal) {
95
- if (dialog.open) return;
96
- // Old WebKit clamps the scroll position to 0 when the root element gains
97
- // overflow:hidden (the has-modal-open lock applied right after this),
98
- // losing the user's place. Remember it and put it back after close.
99
- const win = doc.defaultView;
100
- savedScroll = modal && win ? { x: win.scrollX, y: win.scrollY } : null;
101
- dialog.setAttribute("open", "");
102
- dialog.classList.toggle(CLASSES.fallbackModal, modal);
103
- if (modal) {
104
- escController = new AbortController();
105
- doc.addEventListener("keydown", handleEscape, { signal: escController.signal });
106
- }
107
- focusInitial(dialog);
108
- }
109
-
110
- Object.defineProperty(dialog, "open", {
111
- configurable: true,
112
- get() {
113
- return this.hasAttribute("open");
114
- },
115
- set(value) {
116
- this.toggleAttribute("open", Boolean(value));
117
- },
118
- });
119
-
120
- dialog.returnValue = "";
121
- dialog.classList.add(CLASSES.dialogFallback);
122
- dialog.addEventListener("submit", handleSubmit);
123
- dialog.show = () => open(false);
124
- dialog.showModal = () => open(true);
125
- dialog.close = (returnValue = "") => {
126
- if (!dialog.open) return;
127
- stopEscapeListener();
128
- dialog.returnValue = returnValue;
129
- dialog.removeAttribute("open");
130
- dialog.classList.remove(CLASSES.fallbackModal);
131
- dialog.dispatchEvent(new Event("close"));
132
- // After the close event: dialog.js has lifted the scroll lock and moved
133
- // focus back to the trigger, so the restored position sticks.
134
- if (savedScroll) {
135
- doc.defaultView?.scrollTo?.(savedScroll.x, savedScroll.y);
136
- savedScroll = null;
137
- }
138
- };
139
- }
140
-
141
- if (typeof document !== "undefined" && !supportsDialog()) {
142
- enhance({
143
- dialog: (el) => {
144
- shimDialog(el);
145
- },
146
- });
147
-
148
- // A dialog inserted right before its trigger's click may not be scanned by
149
- // enhance() yet, so shim command targets in capture phase too — before the
150
- // delegated command routing resolves them.
151
- document.addEventListener(
152
- "click",
153
- (event) => {
154
- const trigger = event.target?.closest?.("button[commandfor][command]");
155
- if (!trigger) return;
156
- const dialog = targetFor(trigger);
157
- if (dialog?.localName === "dialog") {
158
- shimDialog(dialog);
159
- }
160
- },
161
- true,
162
- );
163
- }