@joewinke/jatui 0.1.31 → 0.2.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/CLAUDE.md +22 -0
- package/dist/actions/attention.d.ts +24 -0
- package/dist/actions/attention.js +94 -0
- package/dist/actions/collapse.js +29 -15
- package/dist/actions/floating.d.ts +53 -0
- package/dist/actions/floating.js +158 -0
- package/dist/actions/listNav.js +137 -108
- package/dist/actions/railNav.js +89 -72
- package/dist/actions/staggerEntrance.d.ts +28 -0
- package/dist/actions/staggerEntrance.js +71 -0
- package/dist/actions/tooltip.d.ts +28 -0
- package/dist/actions/tooltip.js +186 -0
- package/dist/assets/sounds/README.md +47 -0
- package/dist/assets/sounds/error.d.ts +1 -0
- package/dist/assets/sounds/error.js +4 -0
- package/dist/assets/sounds/notify.d.ts +1 -0
- package/dist/assets/sounds/notify.js +4 -0
- package/dist/assets/sounds/pop.d.ts +1 -0
- package/dist/assets/sounds/pop.js +4 -0
- package/dist/assets/sounds/send.d.ts +1 -0
- package/dist/assets/sounds/send.js +4 -0
- package/dist/assets/sounds/success.d.ts +1 -0
- package/dist/assets/sounds/success.js +4 -0
- package/dist/assets/sounds/toggle.d.ts +1 -0
- package/dist/assets/sounds/toggle.js +4 -0
- package/dist/components/AnimatedNumber.svelte +112 -0
- package/dist/components/AnimatedNumber.svelte.d.ts +8 -0
- package/dist/components/Badge.svelte +75 -4
- package/dist/components/Badge.svelte.d.ts +6 -1
- package/dist/components/Button.svelte +196 -21
- package/dist/components/Button.svelte.d.ts +10 -1
- package/dist/components/Carousel.svelte +265 -0
- package/dist/components/Carousel.svelte.d.ts +21 -0
- package/dist/components/ChipInput.svelte +63 -3
- package/dist/components/Collapse.svelte +70 -14
- package/dist/components/Collapse.svelte.d.ts +11 -0
- package/dist/components/ColorSelector.svelte +21 -24
- package/dist/components/CommandPalette.svelte +475 -0
- package/dist/components/CommandPalette.svelte.d.ts +3 -0
- package/dist/components/ContextMenu.svelte +9 -73
- package/dist/components/CopyButton.svelte +156 -0
- package/dist/components/CopyButton.svelte.d.ts +12 -0
- package/dist/components/HoldToConfirm.svelte +183 -0
- package/dist/components/HoldToConfirm.svelte.d.ts +11 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte +54 -8
- package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +3 -0
- package/dist/components/PasswordMeter.svelte +87 -0
- package/dist/components/PasswordMeter.svelte.d.ts +8 -0
- package/dist/components/PinInput.svelte +186 -0
- package/dist/components/PinInput.svelte.d.ts +13 -0
- package/dist/components/QuantityStepper.svelte +185 -0
- package/dist/components/QuantityStepper.svelte.d.ts +12 -0
- package/dist/components/Skeleton.svelte +123 -0
- package/dist/components/Skeleton.svelte.d.ts +12 -0
- package/dist/components/SpeechForm.svelte +37 -0
- package/dist/components/StatusBadge.svelte +31 -3
- package/dist/components/StatusBadge.svelte.d.ts +0 -5
- package/dist/components/Tabs.svelte +270 -0
- package/dist/components/Tabs.svelte.d.ts +15 -0
- package/dist/components/TextInput.svelte +138 -38
- package/dist/components/TextInput.svelte.d.ts +9 -1
- package/dist/components/VoicePlayer.svelte +51 -0
- package/dist/components/basic/Alert.svelte +36 -0
- package/dist/components/basic/Alert.svelte.d.ts +9 -0
- package/dist/components/basic/Breadcrumb.svelte +27 -0
- package/dist/components/basic/Breadcrumb.svelte.d.ts +11 -0
- package/dist/components/basic/ButtonGroup.svelte +15 -0
- package/dist/components/basic/ButtonGroup.svelte.d.ts +8 -0
- package/dist/components/basic/Checkbox.svelte +85 -0
- package/dist/components/basic/Checkbox.svelte.d.ts +15 -0
- package/dist/components/basic/Empty.svelte +17 -0
- package/dist/components/basic/Empty.svelte.d.ts +8 -0
- package/dist/components/basic/Kbd.svelte +16 -0
- package/dist/components/basic/Kbd.svelte.d.ts +8 -0
- package/dist/components/basic/Pagination.svelte +104 -0
- package/dist/components/basic/Pagination.svelte.d.ts +12 -0
- package/dist/components/basic/RadioGroup.svelte +71 -0
- package/dist/components/basic/RadioGroup.svelte.d.ts +18 -0
- package/dist/components/basic/Separator.svelte +19 -0
- package/dist/components/basic/Separator.svelte.d.ts +8 -0
- package/dist/components/basic/Slider.svelte +72 -0
- package/dist/components/basic/Slider.svelte.d.ts +17 -0
- package/dist/components/basic/Switch.svelte +88 -0
- package/dist/components/basic/Switch.svelte.d.ts +14 -0
- package/dist/components/basic/Toggle.svelte +43 -0
- package/dist/components/basic/Toggle.svelte.d.ts +14 -0
- package/dist/components/graph/GraphCanvas.svelte +103 -0
- package/dist/components/graph/GraphCanvas.svelte.d.ts +22 -0
- package/dist/components/graph/JatuiNode.svelte +128 -0
- package/dist/components/graph/JatuiNode.svelte.d.ts +14 -0
- package/dist/components/graph/theme.d.ts +27 -0
- package/dist/components/graph/theme.js +136 -0
- package/dist/components/markup.js +62 -59
- package/dist/components/messaging/MessageItem.svelte +92 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +5 -0
- package/dist/components/messaging/TypingIndicator.svelte +63 -0
- package/dist/components/messaging/TypingIndicator.svelte.d.ts +7 -0
- package/dist/components/pipeline/PipelineColumn.svelte +44 -3
- package/dist/components/progress/ProgressBar.svelte +189 -0
- package/dist/components/progress/ProgressBar.svelte.d.ts +17 -0
- package/dist/components/progress/ProgressRing.svelte +138 -0
- package/dist/components/progress/ProgressRing.svelte.d.ts +12 -0
- package/dist/components/progress/Steps.svelte +195 -0
- package/dist/components/progress/Steps.svelte.d.ts +14 -0
- package/dist/components/session-nav/transcriptModel.js +66 -49
- package/dist/components/shell/NavigationMenu.svelte +422 -0
- package/dist/components/shell/NavigationMenu.svelte.d.ts +43 -0
- package/dist/components/shell/Sidebar.svelte +276 -0
- package/dist/components/shell/Sidebar.svelte.d.ts +32 -0
- package/dist/components/shell/SidebarGroup.svelte +180 -0
- package/dist/components/shell/SidebarGroup.svelte.d.ts +19 -0
- package/dist/components/shell/SidebarItem.svelte +170 -0
- package/dist/components/shell/SidebarItem.svelte.d.ts +24 -0
- package/dist/components/shell/shell.d.ts +30 -0
- package/dist/components/shell/shell.js +65 -0
- package/dist/components/table/DataTable.svelte +364 -0
- package/dist/components/table/DataTable.svelte.d.ts +4 -0
- package/dist/components/table/flexRender.d.ts +31 -0
- package/dist/components/table/flexRender.js +32 -0
- package/dist/components/table/types.d.ts +28 -0
- package/dist/components/table/types.js +1 -0
- package/dist/components/toast/ToastHost.svelte +21 -0
- package/dist/components/toast/ToastHost.svelte.d.ts +3 -0
- package/dist/components/toast/ToastItem.svelte +287 -0
- package/dist/components/toast/ToastItem.svelte.d.ts +9 -0
- package/dist/data/emojis.js +4 -4
- package/dist/dnd/autoScroll.js +12 -10
- package/dist/dnd/createDndBoard.svelte.js +110 -76
- package/dist/dnd/createDndBoard.test.js +161 -85
- package/dist/dnd/draggable.js +23 -15
- package/dist/dnd/dropTarget.js +29 -15
- package/dist/dnd/index.d.ts +0 -1
- package/dist/dnd/index.js +0 -1
- package/dist/dnd/types.d.ts +0 -9
- package/dist/dnd/types.js +14 -2
- package/dist/index.d.ts +60 -6
- package/dist/index.js +73 -6
- package/dist/showcase/AnimatedBeam.svelte +183 -0
- package/dist/showcase/AnimatedBeam.svelte.d.ts +26 -0
- package/dist/showcase/AuroraDrift.svelte +74 -0
- package/dist/showcase/AuroraDrift.svelte.d.ts +9 -0
- package/dist/showcase/BentoCard.svelte +50 -0
- package/dist/showcase/BentoCard.svelte.d.ts +14 -0
- package/dist/showcase/BentoGrid.svelte +43 -0
- package/dist/showcase/BentoGrid.svelte.d.ts +12 -0
- package/dist/showcase/BorderBeam.svelte +79 -0
- package/dist/showcase/BorderBeam.svelte.d.ts +12 -0
- package/dist/showcase/ClipWipe.svelte +82 -0
- package/dist/showcase/ClipWipe.svelte.d.ts +12 -0
- package/dist/showcase/Confetti.svelte +71 -0
- package/dist/showcase/Confetti.svelte.d.ts +10 -0
- package/dist/showcase/CursorSpotlight.svelte +85 -0
- package/dist/showcase/CursorSpotlight.svelte.d.ts +9 -0
- package/dist/showcase/DeviceMock.svelte +186 -0
- package/dist/showcase/DeviceMock.svelte.d.ts +11 -0
- package/dist/showcase/Dock.svelte +123 -0
- package/dist/showcase/Dock.svelte.d.ts +17 -0
- package/dist/showcase/FlipCard.svelte +103 -0
- package/dist/showcase/FlipCard.svelte.d.ts +10 -0
- package/dist/showcase/FocusReveal.svelte +83 -0
- package/dist/showcase/FocusReveal.svelte.d.ts +11 -0
- package/dist/showcase/Globe.svelte +202 -0
- package/dist/showcase/Globe.svelte.d.ts +16 -0
- package/dist/showcase/KenBurns.svelte +105 -0
- package/dist/showcase/KenBurns.svelte.d.ts +13 -0
- package/dist/showcase/Marquee.svelte +89 -0
- package/dist/showcase/Marquee.svelte.d.ts +9 -0
- package/dist/showcase/ParallaxTilt.svelte +98 -0
- package/dist/showcase/ParallaxTilt.svelte.d.ts +10 -0
- package/dist/showcase/ScrambleText.svelte +98 -0
- package/dist/showcase/ScrambleText.svelte.d.ts +11 -0
- package/dist/showcase/ShineSweep.svelte +81 -0
- package/dist/showcase/ShineSweep.svelte.d.ts +9 -0
- package/dist/showcase/Terminal.svelte +230 -0
- package/dist/showcase/Terminal.svelte.d.ts +18 -0
- package/dist/showcase/TextSplitReveal.svelte +146 -0
- package/dist/showcase/TextSplitReveal.svelte.d.ts +13 -0
- package/dist/showcase/TextWave.svelte +55 -0
- package/dist/showcase/TextWave.svelte.d.ts +8 -0
- package/dist/showcase/TypewriterText.svelte +130 -0
- package/dist/showcase/TypewriterText.svelte.d.ts +9 -0
- package/dist/showcase/backdrop/GrainGradient.svelte +126 -0
- package/dist/showcase/backdrop/GrainGradient.svelte.d.ts +23 -0
- package/dist/showcase/backdrop/MeshGradient.svelte +104 -0
- package/dist/showcase/backdrop/MeshGradient.svelte.d.ts +20 -0
- package/dist/showcase/backdrop/Metaballs.svelte +116 -0
- package/dist/showcase/backdrop/Metaballs.svelte.d.ts +18 -0
- package/dist/showcase/backdrop/NeuroNoise.svelte +115 -0
- package/dist/showcase/backdrop/NeuroNoise.svelte.d.ts +20 -0
- package/dist/showcase/backdrop/ShowcaseBackdrop.svelte +48 -0
- package/dist/showcase/backdrop/ShowcaseBackdrop.svelte.d.ts +12 -0
- package/dist/showcase/generative/GenerativeBackdrop.svelte +234 -0
- package/dist/showcase/generative/GenerativeBackdrop.svelte.d.ts +9 -0
- package/dist/showcase/generative/intent.d.ts +7 -0
- package/dist/showcase/generative/intent.js +67 -0
- package/dist/showcase/generative/manifest.d.ts +9 -0
- package/dist/showcase/generative/manifest.js +97 -0
- package/dist/showcase/generative/types.d.ts +48 -0
- package/dist/showcase/generative/types.js +8 -0
- package/dist/showcase/index.d.ts +36 -0
- package/dist/showcase/index.js +46 -0
- package/dist/showcase/scroll/SmoothScroll.svelte +49 -0
- package/dist/showcase/scroll/SmoothScroll.svelte.d.ts +12 -0
- package/dist/showcase/scroll/scrollProgress.d.ts +24 -0
- package/dist/showcase/scroll/scrollProgress.js +65 -0
- package/dist/showcase/scroll/scrollReveal.d.ts +30 -0
- package/dist/showcase/scroll/scrollReveal.js +70 -0
- package/dist/stores/commandPalette.svelte.d.ts +24 -0
- package/dist/stores/commandPalette.svelte.js +82 -0
- package/dist/stores/confirmDialog.svelte.js +5 -5
- package/dist/stores/inputDialog.svelte.js +5 -5
- package/dist/stores/toast.svelte.d.ts +28 -0
- package/dist/stores/toast.svelte.js +33 -0
- package/dist/styles/motion.css +46 -0
- package/dist/styles/tokens.css +31 -0
- package/dist/transitions/glide.d.ts +31 -0
- package/dist/transitions/glide.js +58 -0
- package/dist/types/booking.js +4 -4
- package/dist/types/comments.js +2 -2
- package/dist/types/messaging.js +3 -3
- package/dist/types/pipeline.js +2 -2
- package/dist/utils/currency.js +4 -2
- package/dist/utils/daisyuiColors.js +27 -25
- package/dist/utils/dateFormatters.d.ts +20 -0
- package/dist/utils/dateFormatters.js +65 -44
- package/dist/utils/googleMapsLoader.js +100 -46
- package/dist/utils/mentionParser.js +30 -30
- package/dist/utils/phone.js +27 -21
- package/dist/utils/phoneFormat.js +9 -9
- package/dist/utils/sound.d.ts +6 -0
- package/dist/utils/sound.js +113 -0
- package/dist/utils/splitText.d.ts +25 -0
- package/dist/utils/splitText.js +94 -0
- package/dist/utils/taskUtils.js +1 -1
- package/dist/utils/themeWipe.d.ts +21 -0
- package/dist/utils/themeWipe.js +94 -0
- package/dist/utils/viewTransition.d.ts +23 -0
- package/dist/utils/viewTransition.js +75 -0
- package/package.json +56 -4
package/dist/actions/railNav.js
CHANGED
|
@@ -60,6 +60,17 @@
|
|
|
60
60
|
* 3. Handle Left/Right in `onAction` and call `rail.bump(host)` on change:
|
|
61
61
|
* onAction: (id, dir, host) => { formData[id] = cycle(opts[id], …, dir); rail.bump(host); }
|
|
62
62
|
*/
|
|
63
|
+
var __assign = (this && this.__assign) || function () {
|
|
64
|
+
__assign = Object.assign || function(t) {
|
|
65
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
66
|
+
s = arguments[i];
|
|
67
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
68
|
+
t[p] = s[p];
|
|
69
|
+
}
|
|
70
|
+
return t;
|
|
71
|
+
};
|
|
72
|
+
return __assign.apply(this, arguments);
|
|
73
|
+
};
|
|
63
74
|
// ─── Exported helpers ──────────────────────────────────────────────────────────
|
|
64
75
|
/**
|
|
65
76
|
* Cycle through `list`, returning the item `dir` steps from `current`.
|
|
@@ -73,39 +84,40 @@
|
|
|
73
84
|
export function cycle(list, current, dir) {
|
|
74
85
|
if (list.length === 0)
|
|
75
86
|
return current;
|
|
76
|
-
|
|
87
|
+
var i = list.indexOf(current);
|
|
77
88
|
// When `current` is not in the list, treat it as if we're at position -1
|
|
78
89
|
// so that `dir=1` lands at index 0 (the first item) and `dir=-1` lands at
|
|
79
90
|
// the last item — matching the "not found → start from the beginning" idiom.
|
|
80
|
-
|
|
91
|
+
var base = i === -1 ? -1 : i;
|
|
81
92
|
return list[(((base + dir) % list.length) + list.length) % list.length];
|
|
82
93
|
}
|
|
83
94
|
// ─── Internals ─────────────────────────────────────────────────────────────────
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
var BUMP_DURATION_MS = 280;
|
|
96
|
+
var RAIL_FOCUS_CLASS = 'rail-focus';
|
|
97
|
+
var RAIL_CYCLED_CLASS = 'rail-cycled';
|
|
87
98
|
function resolveOrder(opts) {
|
|
88
99
|
return typeof opts.order === 'function' ? opts.order() : opts.order;
|
|
89
100
|
}
|
|
90
101
|
function resolveAttr(opts) {
|
|
91
|
-
|
|
102
|
+
var _a;
|
|
103
|
+
return (_a = opts.attr) !== null && _a !== void 0 ? _a : 'data-rail-id';
|
|
92
104
|
}
|
|
93
105
|
/** Return all currently-rendered rung hosts in the rail order. */
|
|
94
106
|
function resolveHosts(optsRef) {
|
|
95
|
-
|
|
107
|
+
var container = optsRef.current.container;
|
|
96
108
|
if (!container)
|
|
97
109
|
return [];
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
var attr = resolveAttr(optsRef.current);
|
|
111
|
+
var order = resolveOrder(optsRef.current);
|
|
100
112
|
return order
|
|
101
|
-
.map((id)
|
|
113
|
+
.map(function (id) { return container.querySelector("[".concat(attr, "=\"").concat(id, "\"]")); })
|
|
102
114
|
// checkVisibility() correctly returns false for elements inside a closed <details>
|
|
103
115
|
// (browsers keep offsetParent non-null for those, so that check alone is insufficient).
|
|
104
116
|
// Where checkVisibility is unavailable (jsdom, older engines) treat the rung as
|
|
105
117
|
// visible — a rendered element in `order` is navigable by default; only the
|
|
106
118
|
// closed-<details> case needs the extra exclusion, and that only exists in a
|
|
107
119
|
// real layout engine.
|
|
108
|
-
.filter((el)
|
|
120
|
+
.filter(function (el) { var _a, _b; return !!el && ((_b = (_a = el.checkVisibility) === null || _a === void 0 ? void 0 : _a.call(el)) !== null && _b !== void 0 ? _b : true); });
|
|
109
121
|
}
|
|
110
122
|
/**
|
|
111
123
|
* Focus the most appropriate control inside a rung host:
|
|
@@ -120,17 +132,17 @@ function resolveHosts(optsRef) {
|
|
|
120
132
|
* 4. Last resort: focus the host itself (requires tabindex on the host).
|
|
121
133
|
*/
|
|
122
134
|
function focusRailHost(host) {
|
|
135
|
+
var _a;
|
|
123
136
|
if (host.matches('input,select,textarea,button,[contenteditable="true"],[tabindex]')) {
|
|
124
137
|
host.focus();
|
|
125
138
|
return;
|
|
126
139
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
(inner ?? host).focus();
|
|
140
|
+
var inner = (_a = host.querySelector('[contenteditable="true"],input,select,textarea')) !== null && _a !== void 0 ? _a : host.querySelector('.sd-trigger,button');
|
|
141
|
+
(inner !== null && inner !== void 0 ? inner : host).focus();
|
|
130
142
|
}
|
|
131
143
|
function makeController(optsRef) {
|
|
132
|
-
|
|
133
|
-
|
|
144
|
+
var _currentRailId = '';
|
|
145
|
+
var _lastFocusedHost = null;
|
|
134
146
|
function applyFocusClass(host) {
|
|
135
147
|
if (_lastFocusedHost && _lastFocusedHost !== host) {
|
|
136
148
|
_lastFocusedHost.classList.remove(RAIL_FOCUS_CLASS);
|
|
@@ -145,14 +157,14 @@ function makeController(optsRef) {
|
|
|
145
157
|
host.classList.remove(RAIL_CYCLED_CLASS);
|
|
146
158
|
void host.offsetWidth; // reflow so the animation restarts on rapid presses
|
|
147
159
|
host.classList.add(RAIL_CYCLED_CLASS);
|
|
148
|
-
setTimeout(()
|
|
160
|
+
setTimeout(function () { return host.classList.remove(RAIL_CYCLED_CLASS); }, BUMP_DURATION_MS);
|
|
149
161
|
}
|
|
150
162
|
function focus(id) {
|
|
151
|
-
|
|
163
|
+
var container = optsRef.current.container;
|
|
152
164
|
if (!container)
|
|
153
165
|
return;
|
|
154
|
-
|
|
155
|
-
|
|
166
|
+
var attr = resolveAttr(optsRef.current);
|
|
167
|
+
var host = container.querySelector("[".concat(attr, "=\"").concat(id, "\"]"));
|
|
156
168
|
if (host) {
|
|
157
169
|
focusRailHost(host);
|
|
158
170
|
applyFocusClass(host);
|
|
@@ -163,20 +175,21 @@ function makeController(optsRef) {
|
|
|
163
175
|
}
|
|
164
176
|
}
|
|
165
177
|
function moveRung(dir) {
|
|
166
|
-
|
|
178
|
+
var _a;
|
|
179
|
+
var hosts = resolveHosts(optsRef);
|
|
167
180
|
if (hosts.length === 0)
|
|
168
181
|
return;
|
|
169
|
-
|
|
170
|
-
|
|
182
|
+
var attr = resolveAttr(optsRef.current);
|
|
183
|
+
var ids = hosts.map(function (h) { return h.getAttribute(attr); });
|
|
171
184
|
// Anchor on the actually-focused rung first. Fall back to the last tracked
|
|
172
185
|
// rung (covers focus parked on the container after an Escape pop-out).
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
var active = document.activeElement;
|
|
187
|
+
var activeFocused = (_a = (active === null || active === void 0 ? void 0 : active.closest("[".concat(attr, "]")))) === null || _a === void 0 ? void 0 : _a.getAttribute(attr);
|
|
188
|
+
var fromId = activeFocused && ids.includes(activeFocused) ? activeFocused : _currentRailId;
|
|
189
|
+
var pos = fromId ? ids.indexOf(fromId) : -1;
|
|
177
190
|
if (pos === -1)
|
|
178
191
|
pos = dir === 1 ? -1 : hosts.length;
|
|
179
|
-
|
|
192
|
+
var next = (((pos + dir) % hosts.length) + hosts.length) % hosts.length;
|
|
180
193
|
focusRailHost(hosts[next]);
|
|
181
194
|
applyFocusClass(hosts[next]);
|
|
182
195
|
_currentRailId = ids[next];
|
|
@@ -184,9 +197,10 @@ function makeController(optsRef) {
|
|
|
184
197
|
function refresh() {
|
|
185
198
|
// Re-derive hosts; re-apply focus class if the current rung is still rendered
|
|
186
199
|
// (DOM may have been reconstructed by Svelte's reactive updates).
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
for (
|
|
200
|
+
var hosts = resolveHosts(optsRef);
|
|
201
|
+
var attr = resolveAttr(optsRef.current);
|
|
202
|
+
for (var _i = 0, hosts_1 = hosts; _i < hosts_1.length; _i++) {
|
|
203
|
+
var h = hosts_1[_i];
|
|
190
204
|
if (h.getAttribute(attr) === _currentRailId) {
|
|
191
205
|
applyFocusClass(h);
|
|
192
206
|
return;
|
|
@@ -194,10 +208,11 @@ function makeController(optsRef) {
|
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
function handleFocusin(event) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
var _a;
|
|
212
|
+
var attr = resolveAttr(optsRef.current);
|
|
213
|
+
var order = resolveOrder(optsRef.current);
|
|
214
|
+
var host = (_a = event.target) === null || _a === void 0 ? void 0 : _a.closest("[".concat(attr, "]"));
|
|
215
|
+
var id = host === null || host === void 0 ? void 0 : host.getAttribute(attr);
|
|
201
216
|
// Only track rungs that are in the rail order. Tabbing into an off-rail
|
|
202
217
|
// control (e.g. a description textarea) leaves the last real rung intact
|
|
203
218
|
// so Up / Down can resume from it after the user tabs back out.
|
|
@@ -207,17 +222,18 @@ function makeController(optsRef) {
|
|
|
207
222
|
}
|
|
208
223
|
}
|
|
209
224
|
function handleKeydown(event) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
225
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
226
|
+
var opts = optsRef.current;
|
|
227
|
+
var el = document.activeElement;
|
|
228
|
+
var tag = el === null || el === void 0 ? void 0 : el.tagName;
|
|
229
|
+
var isTextField = !!el &&
|
|
214
230
|
(tag === 'INPUT' || tag === 'TEXTAREA' || el.isContentEditable === true);
|
|
215
|
-
|
|
216
|
-
|
|
231
|
+
var isMultiline = !!el && (tag === 'TEXTAREA' || el.isContentEditable === true);
|
|
232
|
+
var hasMod = event.metaKey || event.ctrlKey || event.altKey;
|
|
217
233
|
// Modal trap — stop non-text keystrokes from bubbling to window-level page
|
|
218
234
|
// listeners (e.g., a listNav attached to `window`). Text-field keystrokes
|
|
219
235
|
// propagate normally so typing in the drawer doesn't interfere.
|
|
220
|
-
|
|
236
|
+
var trap = opts.trap !== false;
|
|
221
237
|
if (trap && !isTextField)
|
|
222
238
|
event.stopPropagation();
|
|
223
239
|
// Escape cascade:
|
|
@@ -225,33 +241,33 @@ function makeController(optsRef) {
|
|
|
225
241
|
// 2. focus inside a descendant control → pop back to container
|
|
226
242
|
// 3. focus already on the container (or just popped) → call onEscape
|
|
227
243
|
if (event.key === 'Escape' && !hasMod) {
|
|
228
|
-
|
|
229
|
-
if (
|
|
244
|
+
var popoverOpen_1 = (_b = (_a = opts.isPopoverOpen) === null || _a === void 0 ? void 0 : _a.call(opts)) !== null && _b !== void 0 ? _b : false;
|
|
245
|
+
if (popoverOpen_1) {
|
|
230
246
|
event.preventDefault();
|
|
231
|
-
opts.onPopoverEscape
|
|
247
|
+
(_c = opts.onPopoverEscape) === null || _c === void 0 ? void 0 : _c.call(opts);
|
|
232
248
|
return true;
|
|
233
249
|
}
|
|
234
|
-
|
|
250
|
+
var container = opts.container;
|
|
235
251
|
if (container && el && el !== container && container.contains(el)) {
|
|
236
252
|
event.preventDefault();
|
|
237
253
|
container.focus();
|
|
238
254
|
return true;
|
|
239
255
|
}
|
|
240
256
|
event.preventDefault();
|
|
241
|
-
opts.onEscape
|
|
257
|
+
(_d = opts.onEscape) === null || _d === void 0 ? void 0 : _d.call(opts);
|
|
242
258
|
return true;
|
|
243
259
|
}
|
|
244
260
|
// Rail motion — suppressed when a popover is open or a modifier is held.
|
|
245
|
-
|
|
261
|
+
var popoverOpen = (_f = (_e = opts.isPopoverOpen) === null || _e === void 0 ? void 0 : _e.call(opts)) !== null && _f !== void 0 ? _f : false;
|
|
246
262
|
if (!hasMod && !popoverOpen) {
|
|
247
263
|
// Vertical: ArrowDown / j step down; ArrowUp / k step up.
|
|
248
264
|
// j / k are blocked in ANY text field; arrows are blocked only inside
|
|
249
265
|
// multiline fields so the caret can still move line-by-line.
|
|
250
|
-
|
|
251
|
-
|
|
266
|
+
var goDown = event.key === 'ArrowDown' || event.key === 'j';
|
|
267
|
+
var goUp = event.key === 'ArrowUp' || event.key === 'k';
|
|
252
268
|
if (goDown || goUp) {
|
|
253
|
-
|
|
254
|
-
|
|
269
|
+
var isVimKey = event.key === 'j' || event.key === 'k';
|
|
270
|
+
var blocked = isVimKey ? isTextField : isMultiline;
|
|
255
271
|
if (!blocked) {
|
|
256
272
|
event.preventDefault();
|
|
257
273
|
moveRung(goDown ? 1 : -1);
|
|
@@ -263,15 +279,14 @@ function makeController(optsRef) {
|
|
|
263
279
|
if ((event.key === 'ArrowLeft' || event.key === 'ArrowRight') &&
|
|
264
280
|
!isTextField) {
|
|
265
281
|
event.preventDefault();
|
|
266
|
-
|
|
282
|
+
var attr = resolveAttr(opts);
|
|
267
283
|
// Prefer the element that actually has DOM focus, then fall back to
|
|
268
284
|
// the last tracked rung (focus parked on the container after pop-out).
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
: null);
|
|
285
|
+
var focusedHost = (_g = (el === null || el === void 0 ? void 0 : el.closest("[".concat(attr, "]")))) !== null && _g !== void 0 ? _g : (opts.container && _currentRailId
|
|
286
|
+
? opts.container.querySelector("[".concat(attr, "=\"").concat(_currentRailId, "\"]"))
|
|
287
|
+
: null);
|
|
273
288
|
if (focusedHost && opts.onAction) {
|
|
274
|
-
|
|
289
|
+
var rungId = (_h = focusedHost.getAttribute(attr)) !== null && _h !== void 0 ? _h : '';
|
|
275
290
|
opts.onAction(rungId, event.key === 'ArrowRight' ? 1 : -1, focusedHost);
|
|
276
291
|
}
|
|
277
292
|
return true;
|
|
@@ -280,13 +295,13 @@ function makeController(optsRef) {
|
|
|
280
295
|
return false;
|
|
281
296
|
}
|
|
282
297
|
return {
|
|
283
|
-
handleKeydown,
|
|
284
|
-
handleFocusin,
|
|
285
|
-
moveRung,
|
|
286
|
-
focus,
|
|
287
|
-
refresh,
|
|
288
|
-
currentId: ()
|
|
289
|
-
bump,
|
|
298
|
+
handleKeydown: handleKeydown,
|
|
299
|
+
handleFocusin: handleFocusin,
|
|
300
|
+
moveRung: moveRung,
|
|
301
|
+
focus: focus,
|
|
302
|
+
refresh: refresh,
|
|
303
|
+
currentId: function () { return _currentRailId; },
|
|
304
|
+
bump: bump,
|
|
290
305
|
};
|
|
291
306
|
}
|
|
292
307
|
// ─── Composable ────────────────────────────────────────────────────────────────
|
|
@@ -301,7 +316,7 @@ function makeController(optsRef) {
|
|
|
301
316
|
* panel.addEventListener('focusin', (e) => rail.handleFocusin(e));
|
|
302
317
|
*/
|
|
303
318
|
export function createRailNav(options) {
|
|
304
|
-
|
|
319
|
+
var ref = { current: options };
|
|
305
320
|
return makeController(ref);
|
|
306
321
|
}
|
|
307
322
|
// ─── Action ────────────────────────────────────────────────────────────────────
|
|
@@ -316,9 +331,10 @@ export function createRailNav(options) {
|
|
|
316
331
|
* <div data-rail-id="priority" tabindex="-1">…</div>
|
|
317
332
|
* </div>
|
|
318
333
|
*/
|
|
319
|
-
export
|
|
320
|
-
|
|
321
|
-
|
|
334
|
+
export var railNav = function (node, initial) {
|
|
335
|
+
if (initial === void 0) { initial = { order: [] }; }
|
|
336
|
+
var ref = { current: __assign(__assign({}, initial), { container: node }) };
|
|
337
|
+
var controller = makeController(ref);
|
|
322
338
|
function onKeydown(e) {
|
|
323
339
|
controller.handleKeydown(e);
|
|
324
340
|
}
|
|
@@ -328,11 +344,12 @@ export const railNav = (node, initial = { order: [] }) => {
|
|
|
328
344
|
node.addEventListener('keydown', onKeydown);
|
|
329
345
|
node.addEventListener('focusin', onFocusin);
|
|
330
346
|
return {
|
|
331
|
-
update
|
|
332
|
-
|
|
347
|
+
update: function (next) {
|
|
348
|
+
if (next === void 0) { next = { order: [] }; }
|
|
349
|
+
ref.current = __assign(__assign({}, next), { container: node });
|
|
333
350
|
controller.refresh();
|
|
334
351
|
},
|
|
335
|
-
destroy() {
|
|
352
|
+
destroy: function () {
|
|
336
353
|
node.removeEventListener('keydown', onKeydown);
|
|
337
354
|
node.removeEventListener('focusin', onFocusin);
|
|
338
355
|
},
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface StaggerEntranceOptions {
|
|
2
|
+
/** Delay between successive children in ms. Default 35. */
|
|
3
|
+
stepMs?: number;
|
|
4
|
+
/** Maximum total stagger time in ms; caps step for large lists. Default 250. */
|
|
5
|
+
maxTotalMs?: number;
|
|
6
|
+
/** translateY distance in px for the rise effect. Default 8. */
|
|
7
|
+
rise?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Stagger-entrance action — apply to a list container to fan children in on
|
|
11
|
+
* mount with a sequenced fade + rise. Each child fades from opacity 0 → 1 and
|
|
12
|
+
* rises from translateY(risepx) → 0, staggered by stepMs.
|
|
13
|
+
*
|
|
14
|
+
* The total stagger time is capped at maxTotalMs regardless of child count,
|
|
15
|
+
* so large lists don't drag on. Runs once per mount; re-mount re-runs it.
|
|
16
|
+
*
|
|
17
|
+
* Reduced-motion: children are set visible immediately with no transition.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* <ul use:staggerEntrance={{ stepMs: 35, maxTotalMs: 250, rise: 8 }}>
|
|
21
|
+
* {#each items as item}
|
|
22
|
+
* <li>{item}</li>
|
|
23
|
+
* {/each}
|
|
24
|
+
* </ul>
|
|
25
|
+
*/
|
|
26
|
+
export declare function staggerEntrance(node: HTMLElement, options?: StaggerEntranceOptions): {
|
|
27
|
+
destroy(): void;
|
|
28
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stagger-entrance action — apply to a list container to fan children in on
|
|
3
|
+
* mount with a sequenced fade + rise. Each child fades from opacity 0 → 1 and
|
|
4
|
+
* rises from translateY(risepx) → 0, staggered by stepMs.
|
|
5
|
+
*
|
|
6
|
+
* The total stagger time is capped at maxTotalMs regardless of child count,
|
|
7
|
+
* so large lists don't drag on. Runs once per mount; re-mount re-runs it.
|
|
8
|
+
*
|
|
9
|
+
* Reduced-motion: children are set visible immediately with no transition.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* <ul use:staggerEntrance={{ stepMs: 35, maxTotalMs: 250, rise: 8 }}>
|
|
13
|
+
* {#each items as item}
|
|
14
|
+
* <li>{item}</li>
|
|
15
|
+
* {/each}
|
|
16
|
+
* </ul>
|
|
17
|
+
*/
|
|
18
|
+
export function staggerEntrance(node, options) {
|
|
19
|
+
if (options === void 0) { options = {}; }
|
|
20
|
+
var _a = options.stepMs, stepMs = _a === void 0 ? 35 : _a, _b = options.maxTotalMs, maxTotalMs = _b === void 0 ? 250 : _b, _c = options.rise, rise = _c === void 0 ? 8 : _c;
|
|
21
|
+
var prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
22
|
+
var children = Array.from(node.children);
|
|
23
|
+
if (prefersReduced || children.length === 0) {
|
|
24
|
+
// Render final state immediately — no animation
|
|
25
|
+
return { destroy: function () { } };
|
|
26
|
+
}
|
|
27
|
+
// Cap the per-item step so total time doesn't exceed maxTotalMs
|
|
28
|
+
var effectiveStep = children.length > 1
|
|
29
|
+
? Math.min(stepMs, Math.floor(maxTotalMs / (children.length - 1)))
|
|
30
|
+
: stepMs;
|
|
31
|
+
var duration = 200; // var(--motion-enter) = 200ms
|
|
32
|
+
// Set all children to their start state (opacity 0, risen)
|
|
33
|
+
for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
|
|
34
|
+
var child = children_1[_i];
|
|
35
|
+
child.style.opacity = '0';
|
|
36
|
+
child.style.transform = "translateY(".concat(rise, "px)");
|
|
37
|
+
child.style.transition = 'none';
|
|
38
|
+
}
|
|
39
|
+
// Trigger entrance in next frame so the start state has been painted
|
|
40
|
+
var rafId = requestAnimationFrame(function () {
|
|
41
|
+
children.forEach(function (child, i) {
|
|
42
|
+
var delay = i * effectiveStep;
|
|
43
|
+
child.style.transition = "opacity ".concat(duration, "ms var(--motion-glide) ").concat(delay, "ms, transform ").concat(duration, "ms var(--motion-glide) ").concat(delay, "ms");
|
|
44
|
+
child.style.opacity = '1';
|
|
45
|
+
child.style.transform = 'translateY(0)';
|
|
46
|
+
});
|
|
47
|
+
// Clean up inline styles after all transitions complete
|
|
48
|
+
var totalMs = (children.length - 1) * effectiveStep + duration + 50;
|
|
49
|
+
var cleanupId = setTimeout(function () {
|
|
50
|
+
for (var _i = 0, children_2 = children; _i < children_2.length; _i++) {
|
|
51
|
+
var child = children_2[_i];
|
|
52
|
+
child.style.opacity = '';
|
|
53
|
+
child.style.transform = '';
|
|
54
|
+
child.style.transition = '';
|
|
55
|
+
}
|
|
56
|
+
}, totalMs);
|
|
57
|
+
return function () { return clearTimeout(cleanupId); };
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
destroy: function () {
|
|
61
|
+
cancelAnimationFrame(rafId);
|
|
62
|
+
// Ensure children are visible if action is destroyed mid-animation
|
|
63
|
+
for (var _i = 0, children_3 = children; _i < children_3.length; _i++) {
|
|
64
|
+
var child = children_3[_i];
|
|
65
|
+
child.style.opacity = '';
|
|
66
|
+
child.style.transform = '';
|
|
67
|
+
child.style.transition = '';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tooltip Svelte action — use:tooltip={{ text, placement?, delayMs? }}
|
|
3
|
+
*
|
|
4
|
+
* Warm/cool window: the first tooltip on a page waits delayMs (default 400ms)
|
|
5
|
+
* before appearing. If another tooltip was shown within the last ~500ms the
|
|
6
|
+
* warm window is still active, so the new tooltip appears instantly — the
|
|
7
|
+
* cursor is already "in tooltip mode".
|
|
8
|
+
*
|
|
9
|
+
* Animation: fade-in + 2px upward rise, var(--motion-glide) var(--motion-fast).
|
|
10
|
+
* Exit is instant (no delay, no motion) so it disappears as soon as you leave.
|
|
11
|
+
*
|
|
12
|
+
* Placement: 'top' | 'bottom' | 'left' | 'right' (default 'top'). Flips to
|
|
13
|
+
* the opposite side when the tooltip would overflow the viewport.
|
|
14
|
+
*
|
|
15
|
+
* Accessibility: sets aria-describedby on the host element.
|
|
16
|
+
* Escape key hides the active tooltip.
|
|
17
|
+
* Focus events (focusin/focusout) trigger alongside mouse hover.
|
|
18
|
+
*/
|
|
19
|
+
export interface TooltipOptions {
|
|
20
|
+
text: string;
|
|
21
|
+
placement?: 'top' | 'bottom' | 'left' | 'right';
|
|
22
|
+
/** ms to wait before showing (default 400). 0 = instant. */
|
|
23
|
+
delayMs?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function tooltip(node: HTMLElement, options: TooltipOptions): {
|
|
26
|
+
update(next: TooltipOptions): void;
|
|
27
|
+
destroy(): void;
|
|
28
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tooltip Svelte action — use:tooltip={{ text, placement?, delayMs? }}
|
|
3
|
+
*
|
|
4
|
+
* Warm/cool window: the first tooltip on a page waits delayMs (default 400ms)
|
|
5
|
+
* before appearing. If another tooltip was shown within the last ~500ms the
|
|
6
|
+
* warm window is still active, so the new tooltip appears instantly — the
|
|
7
|
+
* cursor is already "in tooltip mode".
|
|
8
|
+
*
|
|
9
|
+
* Animation: fade-in + 2px upward rise, var(--motion-glide) var(--motion-fast).
|
|
10
|
+
* Exit is instant (no delay, no motion) so it disappears as soon as you leave.
|
|
11
|
+
*
|
|
12
|
+
* Placement: 'top' | 'bottom' | 'left' | 'right' (default 'top'). Flips to
|
|
13
|
+
* the opposite side when the tooltip would overflow the viewport.
|
|
14
|
+
*
|
|
15
|
+
* Accessibility: sets aria-describedby on the host element.
|
|
16
|
+
* Escape key hides the active tooltip.
|
|
17
|
+
* Focus events (focusin/focusout) trigger alongside mouse hover.
|
|
18
|
+
*/
|
|
19
|
+
var __assign = (this && this.__assign) || function () {
|
|
20
|
+
__assign = Object.assign || function(t) {
|
|
21
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
22
|
+
s = arguments[i];
|
|
23
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
24
|
+
t[p] = s[p];
|
|
25
|
+
}
|
|
26
|
+
return t;
|
|
27
|
+
};
|
|
28
|
+
return __assign.apply(this, arguments);
|
|
29
|
+
};
|
|
30
|
+
var COOL_WINDOW_MS = 500;
|
|
31
|
+
var GAP = 8;
|
|
32
|
+
var tooltipEl = null;
|
|
33
|
+
var lastHideTime = 0;
|
|
34
|
+
var idCounter = 0;
|
|
35
|
+
function getOrCreatePortal() {
|
|
36
|
+
if (tooltipEl)
|
|
37
|
+
return tooltipEl;
|
|
38
|
+
tooltipEl = document.createElement('div');
|
|
39
|
+
tooltipEl.id = 'jatui-tooltip-portal';
|
|
40
|
+
tooltipEl.style.cssText = "\n\t\tposition: fixed;\n\t\ttop: 0; left: 0;\n\t\tpointer-events: none;\n\t\tz-index: 9999;\n\t";
|
|
41
|
+
document.body.appendChild(tooltipEl);
|
|
42
|
+
return tooltipEl;
|
|
43
|
+
}
|
|
44
|
+
function createBubble(text) {
|
|
45
|
+
var el = document.createElement('div');
|
|
46
|
+
el.role = 'tooltip';
|
|
47
|
+
el.textContent = text;
|
|
48
|
+
el.style.cssText = "\n\t\tposition: absolute;\n\t\tpadding: 4px 10px;\n\t\tborder-radius: 6px;\n\t\tfont-size: 0.8125rem;\n\t\tline-height: 1.4;\n\t\twhite-space: nowrap;\n\t\tmax-width: 240px;\n\t\twhite-space: normal;\n\t\tword-break: break-word;\n\t\tbackground: oklch(var(--b3, 20% 0 0));\n\t\tcolor: oklch(var(--bc, 95% 0 0));\n\t\tbox-shadow: 0 2px 6px oklch(0% 0 0 / 18%);\n\t\topacity: 0;\n\t\ttransform: translateY(4px);\n\t\ttransition:\n\t\t\topacity var(--motion-fast, 150ms) var(--motion-glide, cubic-bezier(0.16, 1, 0.3, 1)),\n\t\t\ttransform var(--motion-fast, 150ms) var(--motion-glide, cubic-bezier(0.16, 1, 0.3, 1));\n\t";
|
|
49
|
+
// reduced-motion: remove transform, keep opacity fade
|
|
50
|
+
el.dataset.tooltipBubble = '1';
|
|
51
|
+
return el;
|
|
52
|
+
}
|
|
53
|
+
function positionBubble(bubble, anchor, placement) {
|
|
54
|
+
var rect = anchor.getBoundingClientRect();
|
|
55
|
+
var bw = bubble.offsetWidth;
|
|
56
|
+
var bh = bubble.offsetHeight;
|
|
57
|
+
var vw = window.innerWidth;
|
|
58
|
+
var vh = window.innerHeight;
|
|
59
|
+
var top;
|
|
60
|
+
var left;
|
|
61
|
+
var resolved = placement;
|
|
62
|
+
// Compute primary position, then flip if needed
|
|
63
|
+
var placements = {
|
|
64
|
+
top: function () { return ({ top: rect.top - bh - GAP, left: rect.left + rect.width / 2 - bw / 2 }); },
|
|
65
|
+
bottom: function () { return ({ top: rect.bottom + GAP, left: rect.left + rect.width / 2 - bw / 2 }); },
|
|
66
|
+
left: function () { return ({ top: rect.top + rect.height / 2 - bh / 2, left: rect.left - bw - GAP }); },
|
|
67
|
+
right: function () { return ({ top: rect.top + rect.height / 2 - bh / 2, left: rect.right + GAP }); },
|
|
68
|
+
};
|
|
69
|
+
var pos = placements[resolved]();
|
|
70
|
+
top = pos.top;
|
|
71
|
+
left = pos.left;
|
|
72
|
+
// Flip on viewport edge
|
|
73
|
+
if (resolved === 'top' && top < 0) {
|
|
74
|
+
resolved = 'bottom';
|
|
75
|
+
var p = placements.bottom();
|
|
76
|
+
top = p.top;
|
|
77
|
+
left = p.left;
|
|
78
|
+
}
|
|
79
|
+
else if (resolved === 'bottom' && top + bh > vh) {
|
|
80
|
+
resolved = 'top';
|
|
81
|
+
var p = placements.top();
|
|
82
|
+
top = p.top;
|
|
83
|
+
left = p.left;
|
|
84
|
+
}
|
|
85
|
+
else if (resolved === 'left' && left < 0) {
|
|
86
|
+
resolved = 'right';
|
|
87
|
+
var p = placements.right();
|
|
88
|
+
top = p.top;
|
|
89
|
+
left = p.left;
|
|
90
|
+
}
|
|
91
|
+
else if (resolved === 'right' && left + bw > vw) {
|
|
92
|
+
resolved = 'left';
|
|
93
|
+
var p = placements.left();
|
|
94
|
+
top = p.top;
|
|
95
|
+
left = p.left;
|
|
96
|
+
}
|
|
97
|
+
// Clamp horizontal within viewport
|
|
98
|
+
left = Math.max(GAP, Math.min(left, vw - bw - GAP));
|
|
99
|
+
top = Math.max(GAP, Math.min(top, vh - bh - GAP));
|
|
100
|
+
// Rise direction depends on resolved placement
|
|
101
|
+
var riseY = resolved === 'bottom' ? -4 : 4;
|
|
102
|
+
bubble.style.setProperty('--tooltip-rise-y', "".concat(riseY, "px"));
|
|
103
|
+
bubble.style.top = "".concat(top, "px");
|
|
104
|
+
bubble.style.left = "".concat(left, "px");
|
|
105
|
+
}
|
|
106
|
+
function isWarm() {
|
|
107
|
+
return Date.now() - lastHideTime < COOL_WINDOW_MS;
|
|
108
|
+
}
|
|
109
|
+
export function tooltip(node, options) {
|
|
110
|
+
var opts = __assign({ placement: 'top', delayMs: 400 }, options);
|
|
111
|
+
var bubble = null;
|
|
112
|
+
var showTimer = null;
|
|
113
|
+
var tooltipId = "jatui-tt-".concat(++idCounter);
|
|
114
|
+
function show() {
|
|
115
|
+
var portal = getOrCreatePortal();
|
|
116
|
+
if (bubble) {
|
|
117
|
+
// Already showing — update text and reposition
|
|
118
|
+
bubble.textContent = opts.text;
|
|
119
|
+
positionBubble(bubble, node, opts.placement);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
bubble = createBubble(opts.text);
|
|
123
|
+
bubble.id = tooltipId;
|
|
124
|
+
portal.appendChild(bubble);
|
|
125
|
+
node.setAttribute('aria-describedby', tooltipId);
|
|
126
|
+
// Force a reflow so the initial transform is applied before transitioning
|
|
127
|
+
void bubble.offsetHeight;
|
|
128
|
+
// Measure and position after layout
|
|
129
|
+
positionBubble(bubble, node, opts.placement);
|
|
130
|
+
// Animate in
|
|
131
|
+
bubble.style.opacity = '1';
|
|
132
|
+
bubble.style.transform = 'translateY(0)';
|
|
133
|
+
}
|
|
134
|
+
function hide() {
|
|
135
|
+
if (showTimer) {
|
|
136
|
+
clearTimeout(showTimer);
|
|
137
|
+
showTimer = null;
|
|
138
|
+
}
|
|
139
|
+
if (bubble) {
|
|
140
|
+
lastHideTime = Date.now();
|
|
141
|
+
bubble.remove();
|
|
142
|
+
bubble = null;
|
|
143
|
+
node.removeAttribute('aria-describedby');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function scheduleShow() {
|
|
147
|
+
if (showTimer || bubble)
|
|
148
|
+
return;
|
|
149
|
+
var delay = isWarm() ? 0 : opts.delayMs;
|
|
150
|
+
if (delay === 0) {
|
|
151
|
+
show();
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
showTimer = setTimeout(function () {
|
|
155
|
+
showTimer = null;
|
|
156
|
+
show();
|
|
157
|
+
}, delay);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function handleKeydown(e) {
|
|
161
|
+
if (e.key === 'Escape')
|
|
162
|
+
hide();
|
|
163
|
+
}
|
|
164
|
+
node.addEventListener('mouseenter', scheduleShow);
|
|
165
|
+
node.addEventListener('mouseleave', hide);
|
|
166
|
+
node.addEventListener('focusin', scheduleShow);
|
|
167
|
+
node.addEventListener('focusout', hide);
|
|
168
|
+
document.addEventListener('keydown', handleKeydown);
|
|
169
|
+
return {
|
|
170
|
+
update: function (next) {
|
|
171
|
+
opts = __assign({ placement: 'top', delayMs: 400 }, next);
|
|
172
|
+
if (bubble) {
|
|
173
|
+
bubble.textContent = opts.text;
|
|
174
|
+
positionBubble(bubble, node, opts.placement);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
destroy: function () {
|
|
178
|
+
hide();
|
|
179
|
+
node.removeEventListener('mouseenter', scheduleShow);
|
|
180
|
+
node.removeEventListener('mouseleave', hide);
|
|
181
|
+
node.removeEventListener('focusin', scheduleShow);
|
|
182
|
+
node.removeEventListener('focusout', hide);
|
|
183
|
+
document.removeEventListener('keydown', handleKeydown);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|