actual-css 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 (144) hide show
  1. package/CHANGELOG.md +217 -0
  2. package/README.md +13 -11
  3. package/components.json +668 -0
  4. package/dist/actual.css +166 -37
  5. package/dist/actual.full.css +1087 -643
  6. package/dist/actual.full.js +1 -1
  7. package/dist/actual.full.min.css +1 -1
  8. package/dist/actual.js +1 -1
  9. package/dist/actual.min.css +1 -1
  10. package/docs/design-notes/accessibility-decisions.md +33 -0
  11. package/docs/design-notes/browser-support.md +62 -30
  12. package/docs/design-notes/column-layout.md +3 -3
  13. package/docs/design-notes/css-anchor.md +75 -21
  14. package/docs/design-notes/enhancement-contract.md +14 -6
  15. package/docs/design-notes/grid.md +4 -4
  16. package/docs/design-notes/naming.md +6 -1
  17. package/docs/design-notes/platform-alignment.md +53 -7
  18. package/docs/design-notes/popover-manual-poc.md +105 -25
  19. package/docs/design-notes/surface-reparenting.md +56 -47
  20. package/docs/design-notes/tooltip-coordinate-space.md +132 -0
  21. package/docs/design-notes/widget-primitives.md +7 -4
  22. package/docs/pages/components/accordion.md +41 -2
  23. package/docs/pages/components/alert.md +85 -30
  24. package/docs/pages/components/app-navigation.md +6 -0
  25. package/docs/pages/components/avatar.md +6 -6
  26. package/docs/pages/components/badge.md +101 -16
  27. package/docs/pages/components/button.md +16 -8
  28. package/docs/pages/components/card.md +10 -10
  29. package/docs/pages/components/dialog.md +21 -6
  30. package/docs/pages/components/drawer.md +13 -0
  31. package/docs/pages/components/fab.md +4 -3
  32. package/docs/pages/components/list.md +42 -4
  33. package/docs/pages/components/navbar.md +17 -1
  34. package/docs/pages/components/pagination.md +2 -2
  35. package/docs/pages/components/skeleton.md +3 -1
  36. package/docs/pages/components/steps.md +19 -0
  37. package/docs/pages/components/table.md +3 -2
  38. package/docs/pages/enhancements/flyout.md +82 -38
  39. package/docs/pages/enhancements/overview.md +25 -0
  40. package/docs/pages/enhancements/status-bar.md +1 -1
  41. package/docs/pages/enhancements/tabs.md +45 -37
  42. package/docs/pages/enhancements/tooltip.md +36 -10
  43. package/docs/pages/examples/overview.md +38 -5
  44. package/docs/pages/forms/choice-cards.md +11 -6
  45. package/docs/pages/forms/combobox.md +1 -1
  46. package/docs/pages/forms/floating-field.md +4 -3
  47. package/docs/pages/forms/joined-controls.md +22 -0
  48. package/docs/pages/forms/otp.md +2 -1
  49. package/docs/pages/forms/overview.md +1 -1
  50. package/docs/pages/forms/states-and-sizes.md +16 -18
  51. package/docs/pages/forms/sticky-actions.md +2 -2
  52. package/docs/pages/forms/switch.md +1 -1
  53. package/docs/pages/foundations/philosophy.md +57 -26
  54. package/docs/pages/foundations/theming.md +2 -2
  55. package/docs/pages/foundations/tokens.md +118 -21
  56. package/docs/pages/foundations/typography.md +35 -14
  57. package/docs/pages/guides/introduction.md +11 -9
  58. package/docs/pages/guides/progressive-enhancement.md +115 -30
  59. package/docs/pages/guides/tailwind.md +3 -2
  60. package/docs/pages/layout/media.md +1 -1
  61. package/docs/pages/layout/overview.md +11 -1
  62. package/docs/pages/layout/scroll-snap.md +3 -3
  63. package/docs/pages/layout/stack.md +17 -9
  64. package/docs/pages/patterns/icon-input.md +4 -2
  65. package/docs/pages/patterns/icon-slot.md +2 -0
  66. package/docs/pages/patterns/intent-nesting.md +1 -1
  67. package/docs/pages/utilities/overview.md +23 -2
  68. package/docs/pages/utilities/sizing-wrapping.md +1 -1
  69. package/docs/pages/utilities/spacing.md +10 -8
  70. package/llms.txt +2 -1
  71. package/package.json +159 -149
  72. package/{scripts/reserved-classes.json → reserved-classes.json} +4 -6
  73. package/src/css/components/accordion.css +42 -3
  74. package/src/css/components/alert.css +25 -13
  75. package/src/css/components/app-nav.css +18 -8
  76. package/src/css/components/avatar.css +13 -1
  77. package/src/css/components/badge.css +78 -12
  78. package/src/css/components/breadcrumb.css +2 -3
  79. package/src/css/components/button.css +9 -16
  80. package/src/css/components/card.css +9 -2
  81. package/src/css/components/chat.css +1 -0
  82. package/src/css/components/data-list.css +1 -1
  83. package/src/css/components/drawer.css +101 -32
  84. package/src/css/components/fab.css +0 -6
  85. package/src/css/components/flyout.css +35 -98
  86. package/src/css/components/index.css +0 -1
  87. package/src/css/components/indicator.css +21 -0
  88. package/src/css/components/key.css +10 -0
  89. package/src/css/components/list.css +40 -4
  90. package/src/css/components/menu.css +2 -1
  91. package/src/css/components/modal.css +48 -33
  92. package/src/css/components/navbar.css +37 -4
  93. package/src/css/components/pagination.css +1 -0
  94. package/src/css/components/skeleton.css +15 -4
  95. package/src/css/components/spinner.css +6 -6
  96. package/src/css/components/status-bar.css +0 -5
  97. package/src/css/components/steps.css +45 -59
  98. package/src/css/components/tab.css +29 -9
  99. package/src/css/components/table.css +13 -5
  100. package/src/css/components/tooltip.css +36 -40
  101. package/src/css/core/base.css +23 -1
  102. package/src/css/core/intents.css +17 -6
  103. package/src/css/core/theme.css +27 -0
  104. package/src/css/core/tokens.css +35 -15
  105. package/src/css/core/variants.css +64 -15
  106. package/src/css/forms/choice-card.css +4 -4
  107. package/src/css/forms/choice.css +76 -29
  108. package/src/css/forms/control.css +2 -1
  109. package/src/css/forms/floating-field.css +3 -3
  110. package/src/css/forms/form.css +4 -3
  111. package/src/css/forms/input-icon.css +20 -14
  112. package/src/css/forms/native.css +6 -1
  113. package/src/css/forms/otp.css +9 -1
  114. package/src/css/forms/range.css +2 -0
  115. package/src/css/forms/select.css +29 -9
  116. package/src/css/forms/switch.css +28 -8
  117. package/src/css/layout/app-layout.css +1 -1
  118. package/src/css/layout/grid.css +50 -76
  119. package/src/css/layout/scroll-snap.css +11 -7
  120. package/src/css/layout/scroller.css +3 -4
  121. package/src/css/layout/stack.css +2 -2
  122. package/src/css/typography/fluid.css +4 -3
  123. package/src/css/typography/prose.css +6 -5
  124. package/src/css/utilities/base.css +2 -1
  125. package/src/css/utilities/extra.css +20 -17
  126. package/src/js/context-menu.js +27 -26
  127. package/src/js/dialog.js +2 -1
  128. package/src/js/dismiss.js +5 -0
  129. package/src/js/enhance.js +34 -2
  130. package/src/js/enhancement-loader.js +36 -43
  131. package/src/js/events.js +0 -3
  132. package/src/js/filter.js +0 -1
  133. package/src/js/floating-space.js +42 -0
  134. package/src/js/flyout.js +9 -44
  135. package/src/js/focus-group.js +7 -0
  136. package/src/js/focus.js +6 -0
  137. package/src/js/menu.js +10 -1
  138. package/src/js/selectors.js +5 -9
  139. package/src/js/status.js +6 -5
  140. package/src/js/surface.js +97 -139
  141. package/src/js/tab.js +6 -1
  142. package/src/js/tooltip.js +150 -51
  143. package/src/js/validation.js +1 -1
  144. package/src/css/components/surface.css +0 -49
package/dist/actual.css CHANGED
@@ -70,9 +70,9 @@ select {
70
70
  --line-height: 1.5;
71
71
  --line-height-tight: 1.25;
72
72
  --line-height-relaxed: 1.75;
73
- --font-weight: 400;
73
+ --font-weight-normal: 400;
74
74
  --font-weight-medium: 500;
75
- --font-weight-strong: 650;
75
+ --font-weight-semibold: 600;
76
76
  --font-weight-bold: 700;
77
77
 
78
78
  /* Typography scale */
@@ -87,7 +87,6 @@ select {
87
87
  applications, and no future framework step can collide with them. */
88
88
  --gap: 0.75rem;
89
89
  --density-space: var(--space-40);
90
- --density-compact-size: 1.5rem;
91
90
  --space-10: 0.25rem;
92
91
  --space-20: 0.5rem;
93
92
  --space-30: 0.75rem;
@@ -113,7 +112,10 @@ select {
113
112
  beyond this vocabulary. Toggles that share one transition list at
114
113
  --duration-fast (flyout, tooltip) and pure-opacity backdrops stay on
115
114
  `ease`: at 100ms the curve has almost no resolving time, and a scrim is
116
- not traveling anywhere. */
115
+ not traveling anywhere. Animation policy: reset.css is the global safety
116
+ net; every meaningful @keyframes is explicitly gated behind
117
+ prefers-reduced-motion: no-preference; ordinary transitions rely on the
118
+ reset alone. */
117
119
  --duration: 150ms;
118
120
  --duration-fast: 100ms;
119
121
  --duration-slow: 200ms;
@@ -144,20 +146,29 @@ select {
144
146
  --bar-height: 0.65rem;
145
147
 
146
148
  /* Controls — inputs and buttons share --control-size so heights always match.
147
- .sm/.lg (variants.css) switch --control-size; --control-font-size stays
148
- at its baseline because density does not change typography.
149
+ .compact/.spacious (variants.css) switch geometry without changing
150
+ --control-font-size. Local .sm/.lg component sizes switch all three.
149
151
 
150
152
  Inline choices (checkbox, radio, switch) are typographic, not field-sized:
151
153
  they sit on a line of text, so they follow --control-font-size through
152
154
  --choice-control-size instead of --control-size. Being an em value in
153
155
  :root is deliberate — an unregistered custom property resolves its units
154
156
  at the element that consumes it, so one declaration tracks whatever font
155
- size the choice actually renders at. */
157
+ size the choice actually renders at.
158
+
159
+ --control-pad-x is the opposite kind of token: a resolved geometry length,
160
+ not an em ratio. Every part of one control must see the same horizontal
161
+ distance, so it is stated in the typographic tokens rather than an em
162
+ whose value would change on a descendant with its own font size (the
163
+ input-icon glyph, made larger by --input-icon-size). It mirrors
164
+ --control-font-size and is rebound beside it at the .sm/.lg boundaries
165
+ (variants.css); declaring it only in :root would freeze the md value,
166
+ because a var() inside a custom property resolves where it is declared. */
156
167
  --control-size-sm: 2rem;
157
168
  --control-size-md: 2.375rem;
158
169
  --control-size-lg: 2.75rem;
159
170
  --control-size: var(--control-size-md);
160
- --control-pad-x: 1em;
171
+ --control-pad-x: var(--font-size-md);
161
172
  --control-font-size: var(--font-size-md);
162
173
  --choice-control-size: 1.125em;
163
174
  --disabled-opacity: 0.65;
@@ -190,7 +201,10 @@ select {
190
201
  --soft-hover-alpha: 12%;
191
202
  /* Soft foreground: the share of raw intent in soft text. 100% keeps the
192
203
  pure intent color; lower values rebate it toward --text, which vivid or
193
- light intent palettes need to stay legible on their own soft surface. */
204
+ light intent palettes need to stay legible on their own soft surface.
205
+ The default palette ships per-role --*-soft-fg hooks calibrated against
206
+ the hovered soft fill instead (theme.css); this mix is the fallback a
207
+ theme without hooks falls back to. */
194
208
  --soft-fg-mix: 100%;
195
209
 
196
210
  /* Shared icon assets. Override these URLs when a strict CSP disallows data:. */
@@ -206,13 +220,14 @@ select {
206
220
  --viewport-block: 100vh;
207
221
  --viewport-inline: 100vw;
208
222
 
209
- /* Z-index scale — used ONLY by non-dialog overlays (see the layering
210
- note below for the full model). Actual CSS reserves multiples of 10 for
211
- framework layers; applications may use intermediate values for local
212
- layering. */
223
+ /* Z-index scale — orders document-layer components only. Native top-layer
224
+ elements, dialogs and popovers alike, do not participate in this ordering:
225
+ they always paint above the document, and their order among themselves is
226
+ their top-layer promotion order. No z-index value here can reach them.
227
+ Actual CSS reserves multiples of 10 for framework layers; applications may
228
+ use intermediate values for local layering. */
213
229
  --z-sticky: 10;
214
230
  --z-menu: 20;
215
- --z-tooltip: 50;
216
231
  --z-status: 60;
217
232
  }
218
233
 
@@ -247,7 +262,12 @@ select {
247
262
  --shadow-popout: 0 0.25rem 0.75rem color-mix(in oklch, var(--shadow-color) 15%, transparent);
248
263
  }
249
264
 
250
- :root {
265
+ /* Theme-derived like the shadows above, so it is declared on the same
266
+ boundaries: an alias resolved only on :root is inherited already composed,
267
+ and a [data-theme] island overriding --backdrop-color or
268
+ --backdrop-opacity would not change the scrim of a dialog inside it. */
269
+ :root,
270
+ [data-theme] {
251
271
  --backdrop-fill: color-mix(
252
272
  in oklch,
253
273
  var(--backdrop-color) calc(var(--backdrop-opacity) * 100%),
@@ -359,6 +379,33 @@ select {
359
379
  --focus-ring-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring);
360
380
  }
361
381
 
382
+ /* Soft foreground hooks — the soft ink is the intent rebated toward the local
383
+ text so it keeps 4.5:1 against the soft hover fill (the resting fill carries
384
+ the extra margin; variants.css soft recipe). Deliberately scoped to the
385
+ default theme: a custom property bakes its var() references where it is
386
+ declared, so these resolve against root/light/dark tokens on every boundary.
387
+ Presets and custom islands keep their --soft-fg-mix / raw-intent ink unless
388
+ they declare hooks themselves — :where() keeps this reset from outranking a
389
+ theme's own declaration (e.g. brutalist's 45% soft-fg-mix). */
390
+ :where([data-theme]:not([data-theme="light"]):not([data-theme="dark"])) {
391
+ --primary-soft-fg: initial;
392
+ --secondary-soft-fg: initial;
393
+ --success-soft-fg: initial;
394
+ --warning-soft-fg: initial;
395
+ --danger-soft-fg: initial;
396
+ --neutral-soft-fg: initial;
397
+ }
398
+
399
+ :root,
400
+ [data-theme="light"],
401
+ [data-theme="dark"] {
402
+ --secondary-soft-fg: color-mix(in oklab, var(--text) 10%, var(--secondary) 90%);
403
+ --success-soft-fg: color-mix(in oklab, var(--text) 15%, var(--success) 85%);
404
+ --warning-soft-fg: color-mix(in oklab, var(--text) 25%, var(--warning) 75%);
405
+ --danger-soft-fg: color-mix(in oklab, var(--text) 15%, var(--danger) 85%);
406
+ --neutral-soft-fg: color-mix(in oklab, var(--text) 20%, var(--neutral) 80%);
407
+ }
408
+
362
409
  /* Native platform controls (checkbox, radio, range, progress) that are not
363
410
  restyled by a component class still follow the theme accent. Declared on
364
411
  every island: accent-color inherits as a computed value, so islands must
@@ -467,6 +514,7 @@ select {
467
514
  *
468
515
  * Public hooks:
469
516
  * --link
517
+ * --hr-space
470
518
  */
471
519
 
472
520
  body {
@@ -508,10 +556,23 @@ hgroup > * {
508
556
  margin-block: 0;
509
557
  }
510
558
 
559
+ /* Section break.
560
+
561
+ margin-inline: 0 overrides the UA's `margin: 0.5em auto`. In block flow the
562
+ auto margins resolve to zero and nothing changes, but as a flex or grid item
563
+ an inline auto margin replaces the stretch — an <hr> in a .stack computed to
564
+ width 0 and vanished. .stack deliberately leaves the inline axis free, so
565
+ the reset belongs here.
566
+
567
+ --hr-space tunes the block rhythm on the instance: a rule closing a page
568
+ section and a rule separating two rows in a panel are the same element at
569
+ very different scales. It applies to an hr in document flow; inside .stack
570
+ or .prose the parent owns the spacing between siblings and wins. */
511
571
  hr {
512
572
  border: 0;
513
573
  border-block-start: var(--border-width) solid var(--border);
514
- margin-block: var(--space-60);
574
+ margin-block: var(--hr-space, var(--space-60));
575
+ margin-inline: 0;
515
576
  }
516
577
 
517
578
  code,
@@ -521,6 +582,14 @@ pre {
521
582
  font-family: var(--font-mono);
522
583
  }
523
584
 
585
+ /* Overflow containment only. One unbreakable line — a URL, a minified token, a
586
+ wide ASCII table — otherwise widens the whole page, and an author cannot see
587
+ it coming from the markup. Background, padding and radius stay out: those
588
+ belong to .prose or to an application code-block component. */
589
+ pre {
590
+ overflow-x: auto;
591
+ }
592
+
524
593
  small {
525
594
  font-size: 0.875em;
526
595
  }
@@ -532,36 +601,47 @@ small {
532
601
 
533
602
  /*
534
603
  * Intent classes do not style elements directly.
535
- * They only expose --intent and --intent-fg.
536
- * Components and variants decide how to consume them. Each component that
537
- * consumes --intent or --ui-* opens a local intent boundary in a :where()
538
- * block that resets exactly the tokens it consumes to initial. Parent intents
539
- * do not leak into nested components. Local intent classes (.primary, .danger,
540
- * etc.) still apply because they have higher specificity than :where().
604
+ * They only expose --intent, --intent-fg, and the optional per-intent soft
605
+ * foreground --intent-soft-fg, relayed from the per-role --*-soft-fg hooks.
606
+ * The default theme declares those hooks for its soft ink (see theme.css);
607
+ * a theme without them lets the relay resolve to an invalid value, so the soft
608
+ * recipe falls back to its --soft-fg-mix derivation and a theme opts in one
609
+ * role at a time (docs/pages/foundations/tokens.md). Components and variants
610
+ * decide how to consume them. Each component that consumes --intent,
611
+ * --intent-soft-fg or --ui-* opens a local intent boundary in a :where() block
612
+ * that resets exactly the tokens it consumes to initial. Parent intents do not
613
+ * leak into nested components. Local intent classes (.primary, .danger, etc.)
614
+ * still apply because they have higher specificity than :where().
541
615
  */
542
616
  .primary {
543
617
  --intent: var(--primary);
544
618
  --intent-fg: var(--primary-fg);
619
+ --intent-soft-fg: var(--primary-soft-fg);
545
620
  }
546
621
  .secondary {
547
622
  --intent: var(--secondary);
548
623
  --intent-fg: var(--secondary-fg);
624
+ --intent-soft-fg: var(--secondary-soft-fg);
549
625
  }
550
626
  .success {
551
627
  --intent: var(--success);
552
628
  --intent-fg: var(--success-fg);
629
+ --intent-soft-fg: var(--success-soft-fg);
553
630
  }
554
631
  .warning {
555
632
  --intent: var(--warning);
556
633
  --intent-fg: var(--warning-fg);
634
+ --intent-soft-fg: var(--warning-soft-fg);
557
635
  }
558
636
  .danger {
559
637
  --intent: var(--danger);
560
638
  --intent-fg: var(--danger-fg);
639
+ --intent-soft-fg: var(--danger-soft-fg);
561
640
  }
562
641
  .neutral {
563
642
  --intent: var(--neutral);
564
643
  --intent-fg: var(--neutral-fg);
644
+ --intent-soft-fg: var(--neutral-soft-fg);
565
645
  }
566
646
 
567
647
  /* Paint an inherited or local intent on a simple foreground element without
@@ -587,16 +667,15 @@ small {
587
667
  * components/badge.css — .badge default soft behind explicit --ui-*
588
668
  * components/alert.css — .alert default soft behind explicit --ui-*
589
669
  *
590
- * .sm/.lg set shared density tokens: spacing rhythm and geometry only.
591
- * Density never changes typography — controls keep their font-size and
592
- * content components keep theirs. Controls consume --control-size; non-control
593
- * components may consume --density-* when the density context should affect
594
- * their local rhythm. Compact components may consume --density-compact-size.
595
- * Components with bespoke sizing (spinner, avatar) define local .sm/.lg;
596
- * applying .sm/.lg to card, dialog, accordion, navbar, table, progress, meter
597
- * is a no-op. Progress and meter are deliberate: a bar keeps its inline size
598
- * and only changes thickness, which --bar-height expresses better than a
599
- * three-step scale.
670
+ * .compact/.spacious set inherited density tokens: spacing rhythm and geometry
671
+ * only. Density never changes typography or icon size. Controls consume
672
+ * --control-size; non-control components may consume --density-* when the
673
+ * context should affect their local rhythm.
674
+ *
675
+ * .sm/.lg are local size roles, not shared measurements. Shared control
676
+ * participants below map both typography and geometry; components with
677
+ * bespoke geometry (badge, spinner, avatar, rating, key, prose) own those
678
+ * mappings locally. Components without an explicit mapping do not participate.
600
679
  *
601
680
  * Intent list source of truth: intents.css. Components consume --intent* tokens
602
681
  * instead of re-listing intent classes.
@@ -652,17 +731,64 @@ small {
652
731
  border-color: var(--ui-border);
653
732
  }
654
733
 
655
- .sm {
734
+ .compact {
656
735
  --gap: var(--space-20);
657
736
  --density-space: var(--space-20);
658
737
  --control-size: var(--control-size-sm);
659
- --density-compact-size: 1.25rem;
660
738
  }
661
- .lg {
739
+
740
+ .spacious {
662
741
  --gap: var(--space-50);
663
742
  --density-space: var(--space-50);
664
743
  --control-size: var(--control-size-lg);
665
- --density-compact-size: 1.875rem;
744
+ }
745
+
746
+ /* Shared control scale. Wrappers are listed when their descendants form one
747
+ component (field, input-icon, join, pagination, tabs, flyout). A local size
748
+ declaration beats inherited density because it is declared on the sized
749
+ component itself. */
750
+ :where(
751
+ .btn,
752
+ .input,
753
+ .textarea,
754
+ .select,
755
+ .color,
756
+ .file,
757
+ .field,
758
+ .choice,
759
+ .input-icon,
760
+ .otp,
761
+ .join,
762
+ .pagination,
763
+ .tabs,
764
+ .tab,
765
+ .flyout
766
+ ).sm {
767
+ --control-size: var(--control-size-sm);
768
+ --control-font-size: var(--font-size-sm);
769
+ --control-pad-x: var(--font-size-sm);
770
+ }
771
+
772
+ :where(
773
+ .btn,
774
+ .input,
775
+ .textarea,
776
+ .select,
777
+ .color,
778
+ .file,
779
+ .field,
780
+ .choice,
781
+ .input-icon,
782
+ .otp,
783
+ .join,
784
+ .pagination,
785
+ .tabs,
786
+ .tab,
787
+ .flyout
788
+ ).lg {
789
+ --control-size: var(--control-size-lg);
790
+ --control-font-size: var(--font-size-lg);
791
+ --control-pad-x: var(--font-size-lg);
666
792
  }
667
793
 
668
794
  /* Modern color enhancement. Baseline variant values above remain usable
@@ -676,7 +802,10 @@ small {
676
802
  var(--surface) var(--soft-border-mix),
677
803
  var(--intent, var(--neutral))
678
804
  );
679
- --ui-fg: color-mix(in oklab, var(--text), var(--intent, var(--text)) var(--soft-fg-mix));
805
+ --ui-fg: var(
806
+ --intent-soft-fg,
807
+ color-mix(in oklab, var(--text), var(--intent, var(--text)) var(--soft-fg-mix))
808
+ );
680
809
  /* @sync soft-recipe */
681
810
  }
682
811