actual-css 0.6.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 (143) hide show
  1. package/CHANGELOG.md +214 -1
  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 +1005 -550
  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 +82 -25
  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 +99 -2
  18. package/docs/design-notes/popover-manual-poc.md +328 -0
  19. package/docs/design-notes/surface-reparenting.md +131 -0
  20. package/docs/design-notes/tooltip-coordinate-space.md +132 -0
  21. package/docs/design-notes/widget-primitives.md +9 -6
  22. package/docs/pages/components/accordion.md +41 -2
  23. package/docs/pages/components/alert.md +80 -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 +16 -6
  30. package/docs/pages/components/fab.md +4 -3
  31. package/docs/pages/components/list.md +42 -4
  32. package/docs/pages/components/navbar.md +17 -1
  33. package/docs/pages/components/pagination.md +2 -2
  34. package/docs/pages/components/steps.md +19 -0
  35. package/docs/pages/components/table.md +3 -2
  36. package/docs/pages/enhancements/flyout.md +144 -24
  37. package/docs/pages/enhancements/overview.md +25 -0
  38. package/docs/pages/enhancements/status-bar.md +20 -0
  39. package/docs/pages/enhancements/tabs.md +45 -37
  40. package/docs/pages/enhancements/tooltip.md +40 -2
  41. package/docs/pages/examples/overview.md +38 -5
  42. package/docs/pages/forms/choice-cards.md +6 -2
  43. package/docs/pages/forms/combobox.md +1 -1
  44. package/docs/pages/forms/floating-field.md +4 -3
  45. package/docs/pages/forms/joined-controls.md +22 -0
  46. package/docs/pages/forms/otp.md +2 -1
  47. package/docs/pages/forms/overview.md +1 -1
  48. package/docs/pages/forms/states-and-sizes.md +16 -18
  49. package/docs/pages/forms/sticky-actions.md +2 -2
  50. package/docs/pages/forms/switch.md +1 -1
  51. package/docs/pages/foundations/philosophy.md +67 -22
  52. package/docs/pages/foundations/theming.md +10 -2
  53. package/docs/pages/foundations/tokens.md +118 -21
  54. package/docs/pages/foundations/typography.md +35 -14
  55. package/docs/pages/guides/introduction.md +11 -9
  56. package/docs/pages/guides/progressive-enhancement.md +136 -49
  57. package/docs/pages/guides/tailwind.md +3 -2
  58. package/docs/pages/layout/media.md +1 -1
  59. package/docs/pages/layout/overview.md +11 -1
  60. package/docs/pages/layout/scroll-snap.md +3 -3
  61. package/docs/pages/layout/stack.md +17 -9
  62. package/docs/pages/patterns/icon-input.md +4 -2
  63. package/docs/pages/patterns/icon-slot.md +2 -0
  64. package/docs/pages/patterns/intent-nesting.md +1 -1
  65. package/docs/pages/utilities/overview.md +23 -2
  66. package/docs/pages/utilities/sizing-wrapping.md +1 -1
  67. package/docs/pages/utilities/spacing.md +10 -8
  68. package/llms.txt +2 -1
  69. package/package.json +19 -8
  70. package/{scripts/reserved-classes.json → reserved-classes.json} +4 -6
  71. package/src/css/components/accordion.css +42 -3
  72. package/src/css/components/alert.css +25 -13
  73. package/src/css/components/app-nav.css +18 -8
  74. package/src/css/components/avatar.css +13 -1
  75. package/src/css/components/badge.css +78 -12
  76. package/src/css/components/breadcrumb.css +2 -3
  77. package/src/css/components/button.css +9 -16
  78. package/src/css/components/card.css +9 -2
  79. package/src/css/components/chat.css +1 -0
  80. package/src/css/components/data-list.css +1 -1
  81. package/src/css/components/drawer.css +79 -25
  82. package/src/css/components/fab.css +0 -6
  83. package/src/css/components/flyout.css +46 -63
  84. package/src/css/components/index.css +0 -1
  85. package/src/css/components/indicator.css +21 -0
  86. package/src/css/components/join.css +7 -0
  87. package/src/css/components/key.css +10 -0
  88. package/src/css/components/list.css +40 -4
  89. package/src/css/components/menu.css +18 -11
  90. package/src/css/components/modal.css +48 -33
  91. package/src/css/components/navbar.css +37 -4
  92. package/src/css/components/pagination.css +1 -0
  93. package/src/css/components/spinner.css +6 -6
  94. package/src/css/components/status-bar.css +0 -5
  95. package/src/css/components/steps.css +45 -59
  96. package/src/css/components/tab.css +29 -9
  97. package/src/css/components/table.css +5 -5
  98. package/src/css/components/tooltip.css +45 -13
  99. package/src/css/core/base.css +23 -1
  100. package/src/css/core/intents.css +17 -6
  101. package/src/css/core/theme.css +27 -0
  102. package/src/css/core/tokens.css +35 -15
  103. package/src/css/core/variants.css +64 -15
  104. package/src/css/forms/choice-card.css +4 -4
  105. package/src/css/forms/choice.css +6 -3
  106. package/src/css/forms/control.css +2 -1
  107. package/src/css/forms/floating-field.css +3 -3
  108. package/src/css/forms/form.css +4 -3
  109. package/src/css/forms/input-icon.css +20 -14
  110. package/src/css/forms/native.css +6 -1
  111. package/src/css/forms/otp.css +9 -1
  112. package/src/css/forms/range.css +2 -0
  113. package/src/css/forms/select.css +29 -9
  114. package/src/css/forms/switch.css +19 -5
  115. package/src/css/layout/app-layout.css +1 -1
  116. package/src/css/layout/grid.css +50 -76
  117. package/src/css/layout/scroll-snap.css +11 -7
  118. package/src/css/layout/scroller.css +3 -4
  119. package/src/css/layout/stack.css +2 -2
  120. package/src/css/typography/fluid.css +4 -3
  121. package/src/css/typography/prose.css +6 -5
  122. package/src/css/utilities/base.css +2 -1
  123. package/src/css/utilities/extra.css +20 -17
  124. package/src/js/context-menu.js +27 -26
  125. package/src/js/dialog.js +2 -1
  126. package/src/js/dismiss.js +5 -0
  127. package/src/js/enhance.js +34 -2
  128. package/src/js/enhancement-loader.js +36 -43
  129. package/src/js/events.js +0 -3
  130. package/src/js/filter.js +0 -1
  131. package/src/js/floating-space.js +42 -0
  132. package/src/js/flyout.js +9 -44
  133. package/src/js/focus-group.js +7 -0
  134. package/src/js/focus.js +6 -0
  135. package/src/js/menu.js +10 -1
  136. package/src/js/selectors.js +5 -9
  137. package/src/js/status.js +44 -7
  138. package/src/js/surface.js +106 -132
  139. package/src/js/tab.js +6 -1
  140. package/src/js/tooltip.js +152 -53
  141. package/src/js/validation.js +1 -1
  142. package/src/css/components/surface.css +0 -49
  143. package/src/js/floating.js +0 -432
package/src/js/tooltip.js CHANGED
@@ -25,11 +25,24 @@
25
25
  *
26
26
  * Show: hover + focus (150ms delay), click toggle, or always visible
27
27
  * Hide: blur, pointer leave, Escape
28
+ *
29
+ * Geometry: a trigger scrolled out of the positioning boundary takes its tip
30
+ * down and keeps it tracked, so scrolling back brings the same tip
31
+ * up again with no second hover or tap.
32
+ *
33
+ * Coordinates: viewport by default, document coordinates whenever the trigger
34
+ * scrolls with the page. See positionModeFor().
35
+ *
36
+ * Transport: the top layer, via popover="manual", written by the runtime on
37
+ * every tip it manages. A .tooltip[popover] with no data-tooltip
38
+ * trigger pointing at it is never reached from here and stays the
39
+ * application's own to drive.
28
40
  */
29
41
 
42
+ import { autoUpdate, reposition } from "@lekoala/floating";
30
43
  import enhance from "./enhance.js";
31
44
  import { registerEscapeDismissal } from "./escape.js";
32
- import { autoUpdate, reposition } from "./floating.js";
45
+ import { positionModeFor } from "./floating-space.js";
33
46
  import { CLASSES } from "./selectors.js";
34
47
 
35
48
  const SHOW_DELAY_MS = 150;
@@ -40,11 +53,14 @@ const HIDE_DELAY_MS = 100;
40
53
  * @property {Set<Element>} refs Triggers that currently reference this tip.
41
54
  * @property {Element | null} activeRef Trigger that last showed this tip.
42
55
  * @property {AbortController} controller Tip-level event listener cleanup.
43
- * @property {(() => void) | null} stopTracking Floating-position cleanup while visible.
56
+ * @property {(() => void) | null} stopTracking Floating-position cleanup while wanted.
57
+ * @property {Element | null} trackedRef Reference the current subscription observes.
44
58
  * @property {(() => void) | null} unregisterEscape Escape-stack cleanup while visible and dismissable.
45
59
  * @property {Element | null} escapeRef Trigger represented by the current Escape-stack entry.
46
60
  * @property {boolean} generated True when the tip was created from data-tooltip text.
47
- * @property {{ parent: Node, next: ChildNode | null } | null} mount Original DOM position for explicit tips moved into a dialog/body root.
61
+ * @property {boolean} wanted True while the interaction asks for this tip, positionable or not.
62
+ * @property {boolean} visible True while the tip is promoted to the top layer.
63
+ * @property {"viewport" | "document"} space Coordinate space the tip is written in.
48
64
  * @property {ReturnType<typeof setTimeout> | null} timer Pending delayed show.
49
65
  * @property {ReturnType<typeof setTimeout> | null} hideTimer Pending delayed hide.
50
66
  * @property {boolean} hovered Pointer is over the active trigger.
@@ -55,30 +71,69 @@ const HIDE_DELAY_MS = 100;
55
71
  let uid = 0;
56
72
  const triggerStates = new WeakMap(); // trigger -> { tip, cleanup }
57
73
  /** @type {WeakMap<Element, TooltipState>} */
58
- const tipStates = new WeakMap(); // tip -> { refs, activeRef, controller, stopTracking, generated, mount, timer }
74
+ const tipStates = new WeakMap(); // tip -> { refs, activeRef, controller, stopTracking, generated, visible, timer }
59
75
 
60
- function mountTip(tip, trigger) {
61
- const root = trigger.closest("dialog") || trigger.ownerDocument.body;
62
- const parent = tip.parentNode;
63
- if (!root || !parent || parent === root) return null;
76
+ /*
77
+ * Transport, the same shape surface.js uses and for the same reason: the
78
+ * platform promotes the tip to the top layer and does nothing else, leaving
79
+ * the hover/focus/click policy, the show delays and the Escape ordering here
80
+ * untouched. showPopover/hidePopover throw on an out-of-order call, which the
81
+ * state below should already have excluded — the try/catch is there so a
82
+ * surprising DOM does not take the lifecycle down with it.
83
+ */
84
+ function showTransport(tip) {
85
+ try {
86
+ tip.showPopover();
87
+ return true;
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
64
92
 
65
- const mount = { parent, next: tip.nextSibling };
66
- root.append(tip);
67
- return mount;
93
+ function hideTransport(tip) {
94
+ try {
95
+ tip.hidePopover();
96
+ } catch {
97
+ /* Already closed or detached; nothing left to hide. */
98
+ }
68
99
  }
69
100
 
70
- function restoreTip(tip, state) {
71
- const mount = state.mount;
72
- if (!mount) return;
101
+ /*
102
+ * [hidden] stops being the runtime's state here and goes back to what the
103
+ * author wrote: the state before enhancement. Wiring is lazy, so an explicit
104
+ * tip that is never hovered keeps it for the whole life of the page — which
105
+ * is why .tooltip[hidden] has to stay in the CSS. The runtime strips it only
106
+ * at the moment it takes the lifecycle over, because an author declaration
107
+ * outranks the platform's own hidden state for a closed popover.
108
+ */
109
+ function prepareTip(tip) {
110
+ tip.style.position = "fixed";
111
+ tip.removeAttribute("hidden");
112
+ tip.setAttribute("popover", "manual");
113
+ }
73
114
 
74
- if (mount.parent.isConnected) {
75
- const next = mount.next?.parentNode === mount.parent ? mount.next : null;
76
- mount.parent.insertBefore(tip, next);
77
- } else {
78
- tip.remove();
79
- }
115
+ /** True while the tip is promoted. The runtime's state, not :popover-open. */
116
+ export function isTooltipVisible(tip) {
117
+ return tipStates.get(tip)?.visible === true;
80
118
  }
81
119
 
120
+ /*
121
+ * Coordinate space, resolved once per shown tip.
122
+ *
123
+ * The engine always measures in viewport coordinates; the space only decides
124
+ * what gets written. Document coordinates let the browser scroll the tip along
125
+ * with the page, so it stays attached during touch scrolling instead of
126
+ * trailing its trigger until the next autoUpdate() frame. That holds only
127
+ * while the trigger scrolls with the page too: against a viewport-anchored
128
+ * trigger the browser would carry the tip away on every scroll and each update
129
+ * would snap it back, which is worse than the lag it removes.
130
+ *
131
+ * Which is why this asks about the trigger, not about the tip. An open popover
132
+ * is in the top layer, where an absolutely positioned box resolves against the
133
+ * initial containing block whatever its ancestors do — measured for
134
+ * position: relative, transform, filter, contain and both dialog modes — so
135
+ * the tip's own placement never enters into it.
136
+ */
82
137
  function placementFor(ref) {
83
138
  return ref?.getAttribute("data-tooltip-placement") || "top";
84
139
  }
@@ -134,46 +189,70 @@ function nextTooltipId(doc) {
134
189
  return id;
135
190
  }
136
191
 
137
- function repositionTip(ref, tip) {
192
+ function repositionTip(ref, tip, space) {
138
193
  return reposition(ref, tip, {
139
194
  placement: placementFor(ref),
140
195
  distance: 6,
141
196
  flip: true,
142
197
  shift: true,
198
+ coordinateSpace: space,
143
199
  });
144
200
  }
145
201
 
202
+ /*
203
+ * One update, from show() or from a tracking tick.
204
+ *
205
+ * Two separate notions, deliberately: `wanted` is what the interaction asks
206
+ * for — hover, focus, a click toggle, data-tooltip-visible — and `visible` is
207
+ * what is actually promoted. They come apart whenever the trigger leaves the
208
+ * positioning boundary, because reposition() returning false means "not
209
+ * positionable right now", not "the interaction is over": the tip goes down
210
+ * and its tracking stays, so scrolling the trigger back into view brings the
211
+ * same tip up again with no second hover or tap. Only hideTip() ends a tip.
212
+ *
213
+ * A closed popover has no box to measure, so the tip has to be promoted
214
+ * before it can be positioned, and demoted again when that fails.
215
+ */
146
216
  function updateTrackedTip(tip, state) {
147
217
  const ref = state.activeRef;
148
- if (!ref) return;
149
-
150
- const alwaysVisible = isAlwaysVisible(ref);
151
- // Reveal before measuring: an always-visible tooltip may currently be
152
- // hidden because its trigger was outside the positioning boundary.
153
- if (alwaysVisible) tip.hidden = false;
154
- if (tip.hidden || repositionTip(ref, tip)) {
155
- syncEscapeDismissal(tip, state);
156
- return;
218
+ if (!ref || !state.wanted) return;
219
+
220
+ if (!state.visible) {
221
+ if (!showTransport(tip)) return;
222
+ state.visible = true;
157
223
  }
158
224
 
159
- if (alwaysVisible) tip.hidden = true;
160
- else hideTip(tip, true);
225
+ if (!repositionTip(ref, tip, state.space)) {
226
+ state.visible = false;
227
+ hideTransport(tip);
228
+ }
229
+ syncEscapeDismissal(tip, state);
161
230
  }
162
231
 
232
+ // A subscription observes one reference, so a shared tip re-shown from another
233
+ // trigger has to resubscribe — tracking now outlives a demoted tip, and would
234
+ // otherwise keep watching the trigger that is no longer active.
163
235
  function startTracking(tip, state) {
164
- if (state.stopTracking) return;
236
+ if (state.stopTracking) {
237
+ if (state.trackedRef === state.activeRef) return;
238
+ stopTracking(state);
239
+ }
165
240
 
166
- state.stopTracking = autoUpdate(tip, () => updateTrackedTip(tip, state));
241
+ state.trackedRef = state.activeRef;
242
+ state.stopTracking = autoUpdate(state.activeRef, tip, () => updateTrackedTip(tip, state));
167
243
  }
168
244
 
169
245
  function stopTracking(state) {
170
246
  state?.stopTracking?.();
171
- if (state) state.stopTracking = null;
247
+ if (state) {
248
+ state.stopTracking = null;
249
+ state.trackedRef = null;
250
+ }
172
251
  }
173
252
 
174
253
  function syncEscapeDismissal(tip, state) {
175
254
  const ref = state.activeRef;
176
- const dismissable = !tip.hidden && !isAlwaysVisible(ref);
255
+ const dismissable = state.visible && !isAlwaysVisible(ref);
177
256
  // Position tracking calls this after every successful update. Preserve the
178
257
  // current entry so a scroll/resize tick cannot reorder the LIFO stack.
179
258
  if (dismissable && state.unregisterEscape && state.escapeRef === ref) return;
@@ -198,7 +277,11 @@ function hideTip(tip, force = false) {
198
277
  clearTimeout(state.hideTimer);
199
278
  state.hideTimer = null;
200
279
  }
201
- tip.hidden = true;
280
+ if (state) {
281
+ state.wanted = false;
282
+ state.visible = false;
283
+ }
284
+ hideTransport(tip);
202
285
  state?.unregisterEscape?.();
203
286
  if (state) {
204
287
  state.unregisterEscape = null;
@@ -239,10 +322,13 @@ function wireTip(tip, options = {}) {
239
322
  activeRef: null,
240
323
  controller,
241
324
  stopTracking: null,
325
+ trackedRef: null,
242
326
  unregisterEscape: null,
243
327
  escapeRef: null,
244
328
  generated: options.generated === true,
245
- mount: options.mount || null,
329
+ wanted: false,
330
+ visible: false,
331
+ space: "viewport",
246
332
  timer: null,
247
333
  hideTimer: null,
248
334
  hovered: false,
@@ -277,7 +363,6 @@ function ensureTip(trigger) {
277
363
 
278
364
  let tip;
279
365
  let generated = false;
280
- let mount = null;
281
366
  let descriptionAdded = false;
282
367
  const text = trigger.getAttribute("data-tooltip");
283
368
  const doc = trigger.ownerDocument;
@@ -289,12 +374,25 @@ function ensureTip(trigger) {
289
374
  tip.role = "tooltip";
290
375
  tip.id = nextTooltipId(doc);
291
376
  tip.textContent = text;
292
- tip.hidden = true;
293
- tip.style.position = "fixed";
294
377
  generated = true;
295
378
 
379
+ /*
380
+ * A generated tip is Actual's to place, so the placement has to be
381
+ * structurally neutral — not trigger.after(). Structural pseudo-classes
382
+ * are DOM-based and position: fixed does not exempt a generated sibling
383
+ * from :last-child, so it would take `.join > :last-child` from the
384
+ * trigger and drop the group's trailing corner. The shorthand therefore
385
+ * promises no inheritance; authors who need a local theme, density or
386
+ * custom property use the explicit form, which stays where they wrote it.
387
+ *
388
+ * The dialog hop is not geometry any more — the top layer handles that.
389
+ * It is inertness: a modal dialog inerts the rest of the document, and
390
+ * promotion does not lift an element out of that, because inertness is
391
+ * computed on the DOM and not on paint order.
392
+ */
296
393
  const parent = trigger.closest("dialog") || doc.body;
297
394
  parent.appendChild(tip);
395
+ prepareTip(tip);
298
396
  descriptionAdded = addDescription(trigger, tip.id);
299
397
  }
300
398
 
@@ -302,16 +400,14 @@ function ensureTip(trigger) {
302
400
  if (!tip) {
303
401
  tip = explicitTipFor(trigger);
304
402
  if (!tip) return null;
305
- // Wire and mount the shared tip only on first retain. A later trigger
306
- // must not re-hide a tooltip that is currently visible for another.
307
- if (!tipStates.has(tip)) {
308
- tip.hidden = true;
309
- tip.style.position = "fixed";
310
- mount = mountTip(tip, trigger);
311
- }
403
+ // Wire the shared tip only on first retain. A later trigger must not
404
+ // re-hide a tooltip that is currently visible for another.
405
+ // It is not moved: an explicit tip is author-placed, so it keeps every
406
+ // scope that reaches it by inheritance.
407
+ if (!tipStates.has(tip)) prepareTip(tip);
312
408
  }
313
409
 
314
- const state = wireTip(tip, { generated, mount });
410
+ const state = wireTip(tip, { generated });
315
411
  state.refs.add(trigger);
316
412
 
317
413
  const triggerController = new AbortController();
@@ -349,8 +445,8 @@ function ensureTip(trigger) {
349
445
  state.controller.abort();
350
446
  stopTracking(state);
351
447
  tipStates.delete(tip);
448
+ // An explicit tip is left exactly where the author wrote it, closed.
352
449
  if (state.generated) tip.remove();
353
- else restoreTip(tip, state);
354
450
  };
355
451
 
356
452
  triggerStates.set(trigger, { tip, cleanup });
@@ -368,12 +464,15 @@ function show(tip, ref, immediate = false) {
368
464
  if (!state) return;
369
465
 
370
466
  state.activeRef = ref;
467
+ const mode = positionModeFor(ref);
468
+ state.space = mode.space;
469
+ tip.style.position = mode.position;
371
470
  syncEscapeDismissal(tip, state);
372
471
  clearHide(tip);
373
472
  if (state.timer) clearTimeout(state.timer);
374
473
  const reveal = () => {
375
474
  state.timer = null;
376
- tip.hidden = false;
475
+ state.wanted = true;
377
476
  startTracking(tip, state);
378
477
  updateTrackedTip(tip, state);
379
478
  };
@@ -414,8 +513,8 @@ function handleTriggerClick(e) {
414
513
  if (!tip) return;
415
514
 
416
515
  e.preventDefault();
417
- if (tip.hidden) show(tip, trigger, true);
418
- else hideTip(tip, true);
516
+ if (isTooltipVisible(tip)) hideTip(tip, true);
517
+ else show(tip, trigger, true);
419
518
  }
420
519
 
421
520
  // Delegated discovery listeners run at import time; keep SSR imports inert.
@@ -367,7 +367,7 @@ export class FormValidator {
367
367
  rules[name] = callback;
368
368
  }
369
369
 
370
- static init(selector = VALIDATION_SELECTOR) {
370
+ static init(selector = `form${VALIDATION_SELECTOR}`) {
371
371
  if (typeof document === "undefined") return;
372
372
  for (const form of document.querySelectorAll(selector)) {
373
373
  if (isFormElement(form)) connectForm(form);
@@ -1,49 +0,0 @@
1
- /*
2
- * Surface — shared modal scrim and backdrop for flyout and drawer.
3
- *
4
- * Drawn by .drawer::backdrop (native dialog top-layer) and .surface-backdrop
5
- * (custom fixed div for flyout sheets on coarse pointers). The native
6
- * .modal::backdrop uses the same fill and animates opacity from 0 to 1
7
- * (modal.css), so the scrim strength stays consistent across the dialog
8
- * family.
9
- *
10
- * .surface-backdrop, .is-sheet, and .is-open are runtime markers set by
11
- * surface.js. Authors opt in via [data-flyout-mobile="sheet|auto|none|anchored"]
12
- * — the JS resolves "auto" into .is-sheet at run time.
13
- */
14
- /* Custom backdrop for overlays that do not use the native dialog top-layer.
15
- * Its z-index sits just below the flyout it accompanies. */
16
- .surface-backdrop {
17
- position: fixed;
18
- inset: 0;
19
- z-index: calc(var(--z-menu) - 1);
20
- background: var(--backdrop-fill);
21
- opacity: 1;
22
- /* A scrim never travels; it fades on the neutral `ease`. Duration matches
23
- the flyout sheet it accompanies so it never lags the panel. */
24
- transition: opacity var(--duration-fast) ease;
25
- }
26
-
27
- .surface-backdrop[hidden] {
28
- display: none;
29
- opacity: 0;
30
- }
31
-
32
- @starting-style {
33
- .surface-backdrop:not([hidden]) {
34
- opacity: 0;
35
- }
36
- }
37
-
38
- @supports (transition-behavior: allow-discrete) {
39
- .surface-backdrop {
40
- transition:
41
- opacity var(--duration-fast) ease,
42
- display var(--duration-fast) allow-discrete;
43
- }
44
- }
45
- @media print {
46
- .surface-backdrop {
47
- display: none !important;
48
- }
49
- }