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.
- package/CHANGELOG.md +214 -1
- package/README.md +13 -11
- package/components.json +668 -0
- package/dist/actual.css +166 -37
- package/dist/actual.full.css +1005 -550
- package/dist/actual.full.js +1 -1
- package/dist/actual.full.min.css +1 -1
- package/dist/actual.js +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/accessibility-decisions.md +33 -0
- package/docs/design-notes/browser-support.md +82 -25
- package/docs/design-notes/column-layout.md +3 -3
- package/docs/design-notes/css-anchor.md +75 -21
- package/docs/design-notes/enhancement-contract.md +14 -6
- package/docs/design-notes/grid.md +4 -4
- package/docs/design-notes/naming.md +6 -1
- package/docs/design-notes/platform-alignment.md +99 -2
- package/docs/design-notes/popover-manual-poc.md +328 -0
- package/docs/design-notes/surface-reparenting.md +131 -0
- package/docs/design-notes/tooltip-coordinate-space.md +132 -0
- package/docs/design-notes/widget-primitives.md +9 -6
- package/docs/pages/components/accordion.md +41 -2
- package/docs/pages/components/alert.md +80 -30
- package/docs/pages/components/app-navigation.md +6 -0
- package/docs/pages/components/avatar.md +6 -6
- package/docs/pages/components/badge.md +101 -16
- package/docs/pages/components/button.md +16 -8
- package/docs/pages/components/card.md +10 -10
- package/docs/pages/components/dialog.md +16 -6
- package/docs/pages/components/fab.md +4 -3
- package/docs/pages/components/list.md +42 -4
- package/docs/pages/components/navbar.md +17 -1
- package/docs/pages/components/pagination.md +2 -2
- package/docs/pages/components/steps.md +19 -0
- package/docs/pages/components/table.md +3 -2
- package/docs/pages/enhancements/flyout.md +144 -24
- package/docs/pages/enhancements/overview.md +25 -0
- package/docs/pages/enhancements/status-bar.md +20 -0
- package/docs/pages/enhancements/tabs.md +45 -37
- package/docs/pages/enhancements/tooltip.md +40 -2
- package/docs/pages/examples/overview.md +38 -5
- package/docs/pages/forms/choice-cards.md +6 -2
- package/docs/pages/forms/combobox.md +1 -1
- package/docs/pages/forms/floating-field.md +4 -3
- package/docs/pages/forms/joined-controls.md +22 -0
- package/docs/pages/forms/otp.md +2 -1
- package/docs/pages/forms/overview.md +1 -1
- package/docs/pages/forms/states-and-sizes.md +16 -18
- package/docs/pages/forms/sticky-actions.md +2 -2
- package/docs/pages/forms/switch.md +1 -1
- package/docs/pages/foundations/philosophy.md +67 -22
- package/docs/pages/foundations/theming.md +10 -2
- package/docs/pages/foundations/tokens.md +118 -21
- package/docs/pages/foundations/typography.md +35 -14
- package/docs/pages/guides/introduction.md +11 -9
- package/docs/pages/guides/progressive-enhancement.md +136 -49
- package/docs/pages/guides/tailwind.md +3 -2
- package/docs/pages/layout/media.md +1 -1
- package/docs/pages/layout/overview.md +11 -1
- package/docs/pages/layout/scroll-snap.md +3 -3
- package/docs/pages/layout/stack.md +17 -9
- package/docs/pages/patterns/icon-input.md +4 -2
- package/docs/pages/patterns/icon-slot.md +2 -0
- package/docs/pages/patterns/intent-nesting.md +1 -1
- package/docs/pages/utilities/overview.md +23 -2
- package/docs/pages/utilities/sizing-wrapping.md +1 -1
- package/docs/pages/utilities/spacing.md +10 -8
- package/llms.txt +2 -1
- package/package.json +19 -8
- package/{scripts/reserved-classes.json → reserved-classes.json} +4 -6
- package/src/css/components/accordion.css +42 -3
- package/src/css/components/alert.css +25 -13
- package/src/css/components/app-nav.css +18 -8
- package/src/css/components/avatar.css +13 -1
- package/src/css/components/badge.css +78 -12
- package/src/css/components/breadcrumb.css +2 -3
- package/src/css/components/button.css +9 -16
- package/src/css/components/card.css +9 -2
- package/src/css/components/chat.css +1 -0
- package/src/css/components/data-list.css +1 -1
- package/src/css/components/drawer.css +79 -25
- package/src/css/components/fab.css +0 -6
- package/src/css/components/flyout.css +46 -63
- package/src/css/components/index.css +0 -1
- package/src/css/components/indicator.css +21 -0
- package/src/css/components/join.css +7 -0
- package/src/css/components/key.css +10 -0
- package/src/css/components/list.css +40 -4
- package/src/css/components/menu.css +18 -11
- package/src/css/components/modal.css +48 -33
- package/src/css/components/navbar.css +37 -4
- package/src/css/components/pagination.css +1 -0
- package/src/css/components/spinner.css +6 -6
- package/src/css/components/status-bar.css +0 -5
- package/src/css/components/steps.css +45 -59
- package/src/css/components/tab.css +29 -9
- package/src/css/components/table.css +5 -5
- package/src/css/components/tooltip.css +45 -13
- package/src/css/core/base.css +23 -1
- package/src/css/core/intents.css +17 -6
- package/src/css/core/theme.css +27 -0
- package/src/css/core/tokens.css +35 -15
- package/src/css/core/variants.css +64 -15
- package/src/css/forms/choice-card.css +4 -4
- package/src/css/forms/choice.css +6 -3
- package/src/css/forms/control.css +2 -1
- package/src/css/forms/floating-field.css +3 -3
- package/src/css/forms/form.css +4 -3
- package/src/css/forms/input-icon.css +20 -14
- package/src/css/forms/native.css +6 -1
- package/src/css/forms/otp.css +9 -1
- package/src/css/forms/range.css +2 -0
- package/src/css/forms/select.css +29 -9
- package/src/css/forms/switch.css +19 -5
- package/src/css/layout/app-layout.css +1 -1
- package/src/css/layout/grid.css +50 -76
- package/src/css/layout/scroll-snap.css +11 -7
- package/src/css/layout/scroller.css +3 -4
- package/src/css/layout/stack.css +2 -2
- package/src/css/typography/fluid.css +4 -3
- package/src/css/typography/prose.css +6 -5
- package/src/css/utilities/base.css +2 -1
- package/src/css/utilities/extra.css +20 -17
- package/src/js/context-menu.js +27 -26
- package/src/js/dialog.js +2 -1
- package/src/js/dismiss.js +5 -0
- package/src/js/enhance.js +34 -2
- package/src/js/enhancement-loader.js +36 -43
- package/src/js/events.js +0 -3
- package/src/js/filter.js +0 -1
- package/src/js/floating-space.js +42 -0
- package/src/js/flyout.js +9 -44
- package/src/js/focus-group.js +7 -0
- package/src/js/focus.js +6 -0
- package/src/js/menu.js +10 -1
- package/src/js/selectors.js +5 -9
- package/src/js/status.js +44 -7
- package/src/js/surface.js +106 -132
- package/src/js/tab.js +6 -1
- package/src/js/tooltip.js +152 -53
- package/src/js/validation.js +1 -1
- package/src/css/components/surface.css +0 -49
- 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 {
|
|
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
|
|
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 {
|
|
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,
|
|
74
|
+
const tipStates = new WeakMap(); // tip -> { refs, activeRef, controller, stopTracking, generated, visible, timer }
|
|
59
75
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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 (
|
|
160
|
-
|
|
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)
|
|
236
|
+
if (state.stopTracking) {
|
|
237
|
+
if (state.trackedRef === state.activeRef) return;
|
|
238
|
+
stopTracking(state);
|
|
239
|
+
}
|
|
165
240
|
|
|
166
|
-
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)
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
306
|
-
//
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
418
|
-
else
|
|
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.
|
package/src/js/validation.js
CHANGED
|
@@ -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
|
-
}
|