@hearthscale/app-ui 0.2.4 → 0.4.0-rc.1
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/README.md +14 -14
- package/dist/CLASSES.md +24 -11
- package/dist/TOKENS.md +14 -11
- package/dist/chunks/{chunk-UDXTR7UW.js → chunk-K3W7YUMY.js} +6 -0
- package/dist/index.d.ts +152 -85
- package/dist/index.js +247 -147
- package/dist/markdown.js +24 -2
- package/dist/ui.css +352 -59
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
PackageGlyph,
|
|
11
11
|
SearchGlyph,
|
|
12
12
|
TrashGlyph
|
|
13
|
-
} from "./chunks/chunk-
|
|
13
|
+
} from "./chunks/chunk-K3W7YUMY.js";
|
|
14
14
|
|
|
15
15
|
// ../ui/dist/Button.js
|
|
16
16
|
import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -206,7 +206,8 @@ function anchorFrom(key, e) {
|
|
|
206
206
|
element: e.currentTarget
|
|
207
207
|
};
|
|
208
208
|
}
|
|
209
|
-
|
|
209
|
+
var spaces = (n) => `calc(var(--space) * ${n})`;
|
|
210
|
+
function MenuSurface({ anchor, align = "auto", dir = "down", minWidth = spaces(45), maxWidth, maxHeight, fit = false, keyboard = false, onDismiss, children }) {
|
|
210
211
|
const menu = useRef2(null);
|
|
211
212
|
const [root] = useState(() => popupRoot(anchor.element));
|
|
212
213
|
const grace = useSafeTriangle(anchor.element, menu, root, onDismiss, !keyboard);
|
|
@@ -276,10 +277,14 @@ function MenuSurface({ anchor, align = "auto", dir = "down", minWidth = 180, max
|
|
|
276
277
|
padding: 8,
|
|
277
278
|
apply({ availableWidth, availableHeight, elements, rects }) {
|
|
278
279
|
const surface = elements.floating.firstElementChild;
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
280
|
+
const room = `${Math.max(0, availableWidth)}px`;
|
|
281
|
+
const tall = `${Math.max(0, availableHeight)}px`;
|
|
282
|
+
const own = `${rects.reference.width}px`;
|
|
283
|
+
const wanted = fit ? own : `max(${minWidth}, ${own})`;
|
|
284
|
+
const most = fit ? wanted : maxWidth === void 0 ? null : `max(${wanted}, ${maxWidth})`;
|
|
285
|
+
surface.style.minWidth = `min(${wanted}, ${room})`;
|
|
286
|
+
surface.style.maxWidth = most ? `min(${most}, ${room})` : room;
|
|
287
|
+
surface.style.maxHeight = maxHeight === void 0 ? tall : `min(${maxHeight}, ${tall})`;
|
|
283
288
|
if (fit)
|
|
284
289
|
surface.style.borderRadius = getComputedStyle(anchor.element).borderRadius;
|
|
285
290
|
}
|
|
@@ -299,9 +304,13 @@ function MenuSurface({ anchor, align = "auto", dir = "down", minWidth = 180, max
|
|
|
299
304
|
useEffect2(() => {
|
|
300
305
|
const floating = menu.current;
|
|
301
306
|
const wheel = (e) => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
307
|
+
for (let at = e.target; at; at = at.parentElement) {
|
|
308
|
+
if (at.scrollHeight > at.clientHeight && getComputedStyle(at).overflowY !== "hidden")
|
|
309
|
+
return;
|
|
310
|
+
if (at === floating)
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
e.preventDefault();
|
|
305
314
|
};
|
|
306
315
|
floating.addEventListener("wheel", wheel, { passive: false });
|
|
307
316
|
return () => floating.removeEventListener("wheel", wheel);
|
|
@@ -330,7 +339,10 @@ function MenuSurface({ anchor, align = "auto", dir = "down", minWidth = 180, max
|
|
|
330
339
|
event.preventDefault();
|
|
331
340
|
choices[next]?.focus();
|
|
332
341
|
}
|
|
333
|
-
}, style: pos, children: _jsx5("div", { className: "hs-menu hs-menu-surface", role: keyboard ? "menu" : void 0, style: {
|
|
342
|
+
}, style: pos, children: _jsx5("div", { className: "hs-menu hs-menu-surface", role: keyboard ? "menu" : void 0, style: {
|
|
343
|
+
minWidth: `min(${minWidth}, calc(100vw - var(--space) * 4))`,
|
|
344
|
+
...maxWidth !== void 0 && { maxWidth }
|
|
345
|
+
}, children: _jsx5(PopupNest.Provider, { value: grace.nest, children: _jsx5(OpenSubmenu.Provider, { value: submenu, children }) }) }) }), root);
|
|
334
346
|
}
|
|
335
347
|
var OpenSubmenu = createContext2(null);
|
|
336
348
|
function MItem({ icon, label, sub, chip, checked, selected, danger, disabled, onClick, trailing }) {
|
|
@@ -341,7 +353,7 @@ function MItem({ icon, label, sub, chip, checked, selected, danger, disabled, on
|
|
|
341
353
|
}
|
|
342
354
|
}, children: [icon, _jsxs3("span", { className: "hs-menu-label", children: [_jsx5("span", { className: "hs-menu-title", children: label }), sub && _jsx5("span", { className: "hs-menu-sub", children: sub })] }), chip && _jsx5("span", { className: "hs-menu-chip", children: chip }), checked && _jsx5(CheckGlyph, { size: 13 }), trailing] });
|
|
343
355
|
}
|
|
344
|
-
function MSub({ icon, label, minWidth =
|
|
356
|
+
function MSub({ icon, label, minWidth = spaces(55), children }) {
|
|
345
357
|
const id = useId();
|
|
346
358
|
const open = useContext(OpenSubmenu);
|
|
347
359
|
const [anchor, setAnchor] = useState(null);
|
|
@@ -399,6 +411,8 @@ function useFloatingTips(placement) {
|
|
|
399
411
|
const [shown, setShown] = useState(null);
|
|
400
412
|
const [hide] = useState(() => () => setShown(null));
|
|
401
413
|
return (key, text, more) => ({
|
|
414
|
+
show: (anchor) => setShown({ key, anchor }),
|
|
415
|
+
hide,
|
|
402
416
|
hover: {
|
|
403
417
|
onMouseEnter: (e) => setShown({ key, anchor: e.currentTarget }),
|
|
404
418
|
onFocus: (e) => {
|
|
@@ -511,7 +525,7 @@ function SegmentedControl({ value, options, onChange, label, disabled = false })
|
|
|
511
525
|
|
|
512
526
|
// ../ui/dist/settings.js
|
|
513
527
|
import { jsx as _jsx13, jsxs as _jsxs7, Fragment as _Fragment4 } from "react/jsx-runtime";
|
|
514
|
-
import { createContext as createContext3, useContext as useContext2, useLayoutEffect as useLayoutEffect2, useState as useState2 } from "react";
|
|
528
|
+
import { createContext as createContext3, useContext as useContext2, useLayoutEffect as useLayoutEffect2, useEffect as useEffect4, useState as useState2 } from "react";
|
|
515
529
|
function SettingsCard({ children }) {
|
|
516
530
|
return _jsx13("div", { className: "hs-settings-card", children });
|
|
517
531
|
}
|
|
@@ -523,27 +537,30 @@ function HelpTip({ text, onOpen }) {
|
|
|
523
537
|
const inner = _jsxs7(_Fragment4, { children: [_jsx13(HelpGlyph, { size: 13 }), tip] });
|
|
524
538
|
return onOpen ? _jsx13("button", { type: "button", className: "hs-help-button", onClick: onOpen, ...hover, children: inner }) : _jsx13("span", { className: "hs-help-mark", ...hover, children: inner });
|
|
525
539
|
}
|
|
526
|
-
function SettingsSearch({ value, placeholder, onChange }) {
|
|
527
|
-
return _jsxs7("label", { className: "hs-url hs-settings-search", children: [_jsx13(SearchGlyph, { size: 12 }), _jsx13("input", { className: "hs-in hs-urlin", "aria-label": placeholder, placeholder, spellCheck: false, value, onChange: (e) => onChange(e.target.value) }), _jsx13("span", { "aria-hidden": "true", className: "hs-urlph hs-ph-icon", children: placeholder })] });
|
|
540
|
+
function SettingsSearch({ value, placeholder, onChange, autoFocus }) {
|
|
541
|
+
return _jsxs7("label", { className: "hs-url hs-settings-search", children: [_jsx13(SearchGlyph, { size: 12 }), _jsx13("input", { className: "hs-in hs-urlin", "aria-label": placeholder, placeholder, spellCheck: false, value, ...autoFocus && { autoFocus: true }, onChange: (e) => onChange(e.target.value) }), _jsx13("span", { "aria-hidden": "true", className: "hs-urlph hs-ph-icon", children: placeholder })] });
|
|
528
542
|
}
|
|
529
|
-
function SettingsSelect({ value, options, onPick, minWidth =
|
|
543
|
+
function SettingsSelect({ value, options, onPick, minWidth = spaces(45), menuHeight, menuWidth, placeholder, disabled, label, note }) {
|
|
530
544
|
const [anchor, setAnchor] = useState2(null);
|
|
531
545
|
const current = options.find((o) => o.value === value);
|
|
532
546
|
return _jsxs7("span", { className: "hs-select-wrap", children: [_jsxs7("button", { type: "button", className: "hs-glassbtn hs-hovink hs-inktext hs-select", "aria-label": label, "aria-haspopup": "menu", "aria-expanded": anchor !== null, disabled, "data-open": anchor ? "true" : "false", onClick: (e) => {
|
|
533
547
|
const next = anchorFrom("select", e);
|
|
534
548
|
setAnchor((current2) => current2 ? null : next);
|
|
535
|
-
}, children: [current?.label ?? (value || placeholder), _jsx13(ChevronDownGlyph, { size: 11 })] }), anchor && _jsx13(MenuSurface, { keyboard: true, anchor, onDismiss: () => setAnchor(null), minWidth, ...menuHeight !== void 0 && { maxHeight: menuHeight }, ...menuWidth !== void 0 && { maxWidth: menuWidth }, children: options.map((option) => _jsx13(MItem, { label: option.label, ...option.sub && { sub: option.sub }, ...option.trailing && { trailing: option.trailing }, ...option.disabled && { disabled: true }, checked: option.value === value, onClick: () => {
|
|
549
|
+
}, children: [_jsx13("span", { className: "hs-select-label", children: current?.label ?? (value || placeholder) }), note && _jsx13("span", { className: "hs-select-note", children: note }), _jsx13(ChevronDownGlyph, { size: 11 })] }), anchor && _jsx13(MenuSurface, { keyboard: true, anchor, onDismiss: () => setAnchor(null), minWidth, ...menuHeight !== void 0 && { maxHeight: menuHeight }, ...menuWidth !== void 0 && { maxWidth: menuWidth }, children: options.map((option) => _jsx13(MItem, { label: option.label, ...option.sub && { sub: option.sub }, ...option.trailing && { trailing: option.trailing }, ...option.disabled && { disabled: true }, checked: option.value === value, onClick: () => {
|
|
536
550
|
anchor.element.focus();
|
|
537
551
|
setAnchor(null);
|
|
538
552
|
onPick(option.value);
|
|
539
553
|
} }, option.value)) })] });
|
|
540
554
|
}
|
|
541
|
-
function ToggleRow({ id, title, sub, help, on, onFlip }) {
|
|
555
|
+
function ToggleRow({ id, mark, title, sub, help, actions, on, onFlip }) {
|
|
542
556
|
const docs = useContext2(SettingsDocs);
|
|
543
557
|
const open = id ? docs(id) : void 0;
|
|
544
|
-
return _jsxs7("div", { className: "hs-setrow hs-toggle-row", "data-row": id, children: [_jsxs7("span", { className: "hs-setting-label", children: [_jsxs7("span", { className: "hs-setting-label-line", children: [_jsx13("span", { className: "hs-setting-title", children: title }), help && _jsx13(HelpTip, { text: help, ...open && { onOpen: open } })] }), sub && _jsx13("span", { className: "hs-setting-sub", children: sub })] }), _jsx13(Toggle, { checked: on, "aria-label": title, disabled: !onFlip, ...onFlip && { onChange: onFlip } })] });
|
|
558
|
+
return _jsxs7("div", { className: "hs-setrow hs-toggle-row", "data-row": id, children: [mark && _jsx13("span", { className: "hs-row-mark", children: mark }), _jsxs7("span", { className: "hs-setting-label", children: [_jsxs7("span", { className: "hs-setting-label-line", children: [_jsx13("span", { className: "hs-setting-title", children: title }), help && _jsx13(HelpTip, { text: help, ...open && { onOpen: open } })] }), sub && _jsx13("span", { className: "hs-setting-sub", children: sub })] }), actions && _jsx13(SettingControls, { children: actions }), _jsx13(Toggle, { checked: on, "aria-label": title, disabled: !onFlip, ...onFlip && { onChange: onFlip } })] });
|
|
545
559
|
}
|
|
546
560
|
var SettingsDocs = createContext3(() => void 0);
|
|
561
|
+
function SettingControls({ children }) {
|
|
562
|
+
return _jsx13("span", { className: "hs-setting-controls", children });
|
|
563
|
+
}
|
|
547
564
|
function InfoRow({ id, title, sub, help, helpOpen, value }) {
|
|
548
565
|
const docs = useContext2(SettingsDocs);
|
|
549
566
|
const open = helpOpen ?? (id ? docs(id) : void 0);
|
|
@@ -573,53 +590,63 @@ function SettingsTabs({ label, value, tabs, onPick, panelRef }) {
|
|
|
573
590
|
}, children: tab.label }, tab.value)) });
|
|
574
591
|
}
|
|
575
592
|
|
|
576
|
-
// ../ui/dist/
|
|
593
|
+
// ../ui/dist/Modal.js
|
|
577
594
|
import { jsx as _jsx14, jsxs as _jsxs8 } from "react/jsx-runtime";
|
|
578
|
-
import { useEffect as
|
|
595
|
+
import { useEffect as useEffect6, useRef as useRef6 } from "react";
|
|
579
596
|
|
|
580
|
-
// ../ui/dist/
|
|
581
|
-
import { useEffect as
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
for (const hear of hearers)
|
|
586
|
-
hear();
|
|
587
|
-
}
|
|
588
|
-
function useAsksPerson(on) {
|
|
589
|
-
useEffect4(() => {
|
|
590
|
-
if (!on)
|
|
591
|
-
return;
|
|
592
|
-
asking += 1;
|
|
593
|
-
tell();
|
|
594
|
-
return () => {
|
|
595
|
-
asking -= 1;
|
|
596
|
-
tell();
|
|
597
|
-
};
|
|
598
|
-
}, [on]);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// ../ui/dist/ShellConfirm.js
|
|
602
|
-
function ShellConfirm({ title, body, action, tone = "danger", icon = tone === "danger" ? _jsx14(TrashGlyph, { size: 13 }) : void 0, onConfirm, onCancel }) {
|
|
603
|
-
useAsksPerson(true);
|
|
597
|
+
// ../ui/dist/escape.js
|
|
598
|
+
import { useEffect as useEffect5, useRef as useRef5 } from "react";
|
|
599
|
+
function useEscape(onEscape) {
|
|
600
|
+
const live = useRef5(onEscape);
|
|
601
|
+
live.current = onEscape;
|
|
604
602
|
useEffect5(() => {
|
|
605
603
|
const onKey = (e) => {
|
|
606
|
-
if (e.key
|
|
607
|
-
|
|
608
|
-
e.preventDefault();
|
|
609
|
-
onCancel();
|
|
604
|
+
if (e.key === "Escape" && !e.defaultPrevented)
|
|
605
|
+
live.current();
|
|
610
606
|
};
|
|
611
|
-
window.addEventListener("keydown", onKey
|
|
612
|
-
return () => window.removeEventListener("keydown", onKey
|
|
613
|
-
}, [
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
607
|
+
window.addEventListener("keydown", onKey);
|
|
608
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
609
|
+
}, []);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// ../ui/dist/Modal.js
|
|
613
|
+
function Modal({ title, children, onClose, width = 460, scrim = true }) {
|
|
614
|
+
const panel = useRef6(null);
|
|
615
|
+
useEffect6(() => {
|
|
616
|
+
const previous = document.activeElement;
|
|
617
|
+
panel.current?.focus();
|
|
618
|
+
return () => previous?.focus();
|
|
619
|
+
}, []);
|
|
620
|
+
useEscape(onClose);
|
|
621
|
+
return _jsx14("div", { onClick: onClose, className: scrim ? "hs-modal-backdrop hs-scrim" : "hs-modal-backdrop", children: _jsxs8("div", { ref: panel, tabIndex: -1, role: "dialog", "aria-modal": "true", "aria-label": title, onKeyDown: (event) => {
|
|
622
|
+
if (event.key === "Escape") {
|
|
623
|
+
event.stopPropagation();
|
|
624
|
+
onClose();
|
|
625
|
+
}
|
|
626
|
+
if (event.key !== "Tab")
|
|
627
|
+
return;
|
|
628
|
+
const controls = [
|
|
629
|
+
...event.currentTarget.querySelectorAll('button:not(:disabled), input:not(:disabled), textarea:not(:disabled), a[href], [tabindex="0"]')
|
|
630
|
+
];
|
|
631
|
+
const first = controls[0];
|
|
632
|
+
const last = controls.at(-1);
|
|
633
|
+
if (event.shiftKey && (document.activeElement === first || document.activeElement === panel.current)) {
|
|
634
|
+
event.preventDefault();
|
|
635
|
+
last?.focus();
|
|
636
|
+
} else if (!event.shiftKey && document.activeElement === last) {
|
|
637
|
+
event.preventDefault();
|
|
638
|
+
first?.focus();
|
|
639
|
+
}
|
|
640
|
+
}, onClick: (event) => event.stopPropagation(), className: "hs-modal", style: { width }, children: [_jsxs8("div", { className: "hs-modal-head", children: [_jsx14("p", { className: "hs-modal-title", children: title }), _jsx14(IconButton, { "aria-label": `Close ${title.toLowerCase()}`, onClick: onClose, className: "hs-push-end", children: _jsx14(CloseGlyph, { size: 14 }) })] }), children] }) });
|
|
618
641
|
}
|
|
619
642
|
|
|
643
|
+
// ../ui/dist/MultiSelect.js
|
|
644
|
+
import { jsx as _jsx16, jsxs as _jsxs10 } from "react/jsx-runtime";
|
|
645
|
+
import { useState as useState3 } from "react";
|
|
646
|
+
|
|
620
647
|
// ../ui/dist/OverlayScroll.js
|
|
621
648
|
import { jsx as _jsx15, jsxs as _jsxs9 } from "react/jsx-runtime";
|
|
622
|
-
import { useLayoutEffect as useLayoutEffect3, useRef as
|
|
649
|
+
import { useLayoutEffect as useLayoutEffect3, useRef as useRef7 } from "react";
|
|
623
650
|
function overlayThumb(scroller, thumb) {
|
|
624
651
|
let inset = 0;
|
|
625
652
|
let least = 0;
|
|
@@ -691,57 +718,125 @@ function overlayThumb(scroller, thumb) {
|
|
|
691
718
|
};
|
|
692
719
|
}
|
|
693
720
|
function OverlayScroll({ className, children }) {
|
|
694
|
-
const scroller =
|
|
695
|
-
const thumb =
|
|
721
|
+
const scroller = useRef7(null);
|
|
722
|
+
const thumb = useRef7(null);
|
|
696
723
|
useLayoutEffect3(() => overlayThumb(scroller.current, thumb.current), []);
|
|
697
724
|
return _jsxs9("div", { className: "hs-overlay-scroll", children: [_jsx15("div", { ref: scroller, className, children }), _jsx15("div", { ref: thumb, className: "hs-overlay-thumb", "aria-hidden": "true" })] });
|
|
698
725
|
}
|
|
699
726
|
|
|
727
|
+
// ../ui/dist/MultiSelect.js
|
|
728
|
+
var NAMED_MOST = 2;
|
|
729
|
+
var MENU_WIDTH = spaces(62.5);
|
|
730
|
+
function MultiSelect({ label, options, labelOf, picked, onPick, searchWords, countWord, onOpen, align, all }) {
|
|
731
|
+
const [anchor, setAnchor] = useState3(null);
|
|
732
|
+
const [search, setSearch] = useState3("");
|
|
733
|
+
const needle = search.trim().toLowerCase();
|
|
734
|
+
const shown = [...picked, ...options.filter((value) => !picked.includes(value))].filter((value) => !needle || value.includes(needle) || labelOf(value).toLowerCase().includes(needle));
|
|
735
|
+
const toggle = (value) => {
|
|
736
|
+
if (!picked.includes(value))
|
|
737
|
+
onPick([...picked, value]);
|
|
738
|
+
else if (all !== void 0 || picked.length > 1)
|
|
739
|
+
onPick(picked.filter((one) => one !== value));
|
|
740
|
+
};
|
|
741
|
+
const words = picked.length === 0 ? all : picked.length > NAMED_MOST ? `${picked.length} ${countWord}` : picked.map(labelOf).join(", ");
|
|
742
|
+
return _jsxs10("span", { className: "hs-select-wrap", children: [_jsxs10("button", { type: "button", className: "hs-glassbtn hs-hovink hs-inktext hs-select", "aria-label": label, "aria-haspopup": "menu", "aria-expanded": anchor !== null, "data-open": anchor ? "true" : "false", onClick: (e) => {
|
|
743
|
+
const next = anchorFrom(label, e);
|
|
744
|
+
if (!anchor)
|
|
745
|
+
onOpen?.();
|
|
746
|
+
setAnchor(anchor ? null : next);
|
|
747
|
+
setSearch("");
|
|
748
|
+
}, children: [_jsx16("span", { className: "hs-select-label", children: words }), _jsx16(ChevronDownGlyph, { size: 11 })] }), anchor && _jsx16(MenuSurface, { keyboard: true, anchor, ...align && { align }, minWidth: MENU_WIDTH, maxWidth: MENU_WIDTH, onDismiss: () => setAnchor(null), children: _jsxs10("div", { className: "hs-multi-select-menu", children: [_jsx16("div", { className: "hs-menu-search", children: _jsx16(SettingsSearch, { value: search, placeholder: searchWords, onChange: setSearch }) }), _jsxs10(OverlayScroll, { className: "hs-scroll hs-multi-select-list", children: [all !== void 0 && !needle && _jsx16(MItem, { label: all, checked: picked.length === 0, onClick: () => onPick([]) }), shown.map((value) => _jsx16(MItem, { label: labelOf(value), checked: picked.includes(value), onClick: () => toggle(value) }, value))] })] }) })] });
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// ../ui/dist/ShellConfirm.js
|
|
752
|
+
import { jsx as _jsx17, jsxs as _jsxs11 } from "react/jsx-runtime";
|
|
753
|
+
import { useEffect as useEffect8 } from "react";
|
|
754
|
+
|
|
755
|
+
// ../ui/dist/asking.js
|
|
756
|
+
import { useEffect as useEffect7, useSyncExternalStore } from "react";
|
|
757
|
+
var asking = 0;
|
|
758
|
+
var hearers = /* @__PURE__ */ new Set();
|
|
759
|
+
function tell() {
|
|
760
|
+
for (const hear of hearers)
|
|
761
|
+
hear();
|
|
762
|
+
}
|
|
763
|
+
function useAsksPerson(on) {
|
|
764
|
+
useEffect7(() => {
|
|
765
|
+
if (!on)
|
|
766
|
+
return;
|
|
767
|
+
asking += 1;
|
|
768
|
+
tell();
|
|
769
|
+
return () => {
|
|
770
|
+
asking -= 1;
|
|
771
|
+
tell();
|
|
772
|
+
};
|
|
773
|
+
}, [on]);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// ../ui/dist/ShellConfirm.js
|
|
777
|
+
function ShellConfirm({ title, body, action, tone = "danger", icon = tone === "danger" ? _jsx17(TrashGlyph, { size: 13 }) : void 0, onConfirm, onCancel }) {
|
|
778
|
+
useAsksPerson(true);
|
|
779
|
+
useEffect8(() => {
|
|
780
|
+
const onKey = (e) => {
|
|
781
|
+
if (e.key !== "Escape")
|
|
782
|
+
return;
|
|
783
|
+
e.preventDefault();
|
|
784
|
+
onCancel();
|
|
785
|
+
};
|
|
786
|
+
window.addEventListener("keydown", onKey, true);
|
|
787
|
+
return () => window.removeEventListener("keydown", onKey, true);
|
|
788
|
+
}, [onCancel]);
|
|
789
|
+
return _jsx17("div", { className: "hs-confirm", onClick: (e) => {
|
|
790
|
+
e.stopPropagation();
|
|
791
|
+
onCancel();
|
|
792
|
+
}, children: _jsxs11("div", { className: "hs-confirm-box", role: "dialog", onClick: (e) => e.stopPropagation(), children: [_jsx17("span", { className: "hs-confirm-title", children: title }), _jsx17("span", { className: "hs-confirm-body", children: body }), _jsxs11("div", { className: "hs-confirm-footer", children: [_jsx17(Button, { className: "hs-confirm-cancel", onClick: onCancel, children: "Cancel" }), _jsx17(Button, { className: "hs-confirm-action", variant: tone, icon, onClick: onConfirm, children: action })] })] }) });
|
|
793
|
+
}
|
|
794
|
+
|
|
700
795
|
// ../ui/dist/Kbd.js
|
|
701
|
-
import { jsx as
|
|
796
|
+
import { jsx as _jsx18 } from "react/jsx-runtime";
|
|
702
797
|
function Kbd({ children }) {
|
|
703
|
-
return
|
|
798
|
+
return _jsx18("kbd", { className: "hs-kbd", children });
|
|
704
799
|
}
|
|
705
800
|
|
|
706
801
|
// ../ui/dist/Meter.js
|
|
707
|
-
import { jsx as
|
|
802
|
+
import { jsx as _jsx19, jsxs as _jsxs12 } from "react/jsx-runtime";
|
|
708
803
|
var RADIUS = 7.5;
|
|
709
804
|
var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
710
805
|
function Meter({ value, label, variant = "bar", tone }) {
|
|
711
806
|
const share = Math.max(0, Math.min(1, value));
|
|
712
|
-
return
|
|
807
|
+
return _jsx19("span", { className: "hs-meter", "data-variant": variant, "data-tone": tone, role: "progressbar", "aria-label": label, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(share * 100), children: variant === "ring" ? _jsx19("svg", { width: 20, height: 20, viewBox: "0 0 20 20", "aria-hidden": "true", children: _jsxs12("g", { transform: "rotate(-90 10 10)", children: [_jsx19("circle", { className: "hs-meter-track", cx: 10, cy: 10, r: RADIUS }), _jsx19("circle", { className: "hs-meter-fill", cx: 10, cy: 10, r: RADIUS, strokeDasharray: CIRCUMFERENCE, strokeDashoffset: CIRCUMFERENCE * (1 - share) })] }) }) : _jsx19("span", { className: "hs-meter-fill", style: { width: `${share * 100}%` } }) });
|
|
713
808
|
}
|
|
714
809
|
|
|
715
810
|
// ../ui/dist/Lightbox.js
|
|
716
|
-
import { jsx as
|
|
717
|
-
import { useEffect as
|
|
811
|
+
import { jsx as _jsx20, jsxs as _jsxs13, Fragment as _Fragment5 } from "react/jsx-runtime";
|
|
812
|
+
import { useEffect as useEffect9, useLayoutEffect as useLayoutEffect4, useRef as useRef8, useState as useState4 } from "react";
|
|
718
813
|
import { createPortal as createPortal2 } from "react-dom";
|
|
719
814
|
var MAX_ZOOM = 8;
|
|
720
815
|
var CLICK_ZOOM = 2;
|
|
721
816
|
var DRAG_SLOP = 4;
|
|
722
817
|
var FIT = { scale: 1, x: 0, y: 0 };
|
|
723
818
|
function Lightbox({ items, start, onClose }) {
|
|
724
|
-
const [index, setIndex] =
|
|
725
|
-
const [view, setView] =
|
|
726
|
-
const [broken, setBroken] =
|
|
727
|
-
const [host, setHost] =
|
|
728
|
-
const anchor =
|
|
729
|
-
const stage =
|
|
730
|
-
const closer =
|
|
731
|
-
const drag =
|
|
819
|
+
const [index, setIndex] = useState4(start);
|
|
820
|
+
const [view, setView] = useState4(FIT);
|
|
821
|
+
const [broken, setBroken] = useState4(false);
|
|
822
|
+
const [host, setHost] = useState4(null);
|
|
823
|
+
const anchor = useRef8(null);
|
|
824
|
+
const stage = useRef8(null);
|
|
825
|
+
const closer = useRef8(null);
|
|
826
|
+
const drag = useRef8(null);
|
|
732
827
|
const item = items[index];
|
|
733
828
|
const many = items.length > 1;
|
|
734
829
|
useLayoutEffect4(() => {
|
|
735
830
|
setHost(anchor.current?.closest(".hs-shell") ?? document.body);
|
|
736
831
|
}, []);
|
|
737
|
-
|
|
832
|
+
useEffect9(() => {
|
|
738
833
|
if (!host)
|
|
739
834
|
return;
|
|
740
835
|
const opener = document.activeElement;
|
|
741
836
|
closer.current?.focus();
|
|
742
837
|
return () => opener?.focus();
|
|
743
838
|
}, [host]);
|
|
744
|
-
|
|
839
|
+
useEffect9(() => {
|
|
745
840
|
setView(FIT);
|
|
746
841
|
setBroken(false);
|
|
747
842
|
}, [index]);
|
|
@@ -757,7 +852,7 @@ function Lightbox({ items, start, onClose }) {
|
|
|
757
852
|
return { px: clientX - box.left - box.width / 2, py: clientY - box.top - box.height / 2 };
|
|
758
853
|
};
|
|
759
854
|
const step = (delta) => setIndex((i) => (i + delta + items.length) % items.length);
|
|
760
|
-
|
|
855
|
+
useEffect9(() => {
|
|
761
856
|
const onKey = (event) => {
|
|
762
857
|
if (event.key === "Escape")
|
|
763
858
|
onClose();
|
|
@@ -779,7 +874,7 @@ function Lightbox({ items, start, onClose }) {
|
|
|
779
874
|
window.addEventListener("keydown", onKey, true);
|
|
780
875
|
return () => window.removeEventListener("keydown", onKey, true);
|
|
781
876
|
});
|
|
782
|
-
|
|
877
|
+
useEffect9(() => {
|
|
783
878
|
const box = stage.current;
|
|
784
879
|
if (!box)
|
|
785
880
|
return;
|
|
@@ -822,34 +917,34 @@ function Lightbox({ items, start, onClose }) {
|
|
|
822
917
|
};
|
|
823
918
|
if (!item)
|
|
824
919
|
return null;
|
|
825
|
-
const dialog =
|
|
920
|
+
const dialog = _jsxs13("div", { className: "hs-lightbox", role: "dialog", "aria-modal": "true", "aria-label": item.name, onClick: onClose, children: [_jsxs13("div", { className: "hs-lightbox-bar", onClick: (e) => e.stopPropagation(), children: [item.onSave && _jsx20("button", { type: "button", className: "hs-lightbox-button", "aria-label": "Save", onClick: item.onSave, children: _jsx20(DownloadGlyph, { size: 16 }) }), item.onOpen && _jsx20("button", { type: "button", className: "hs-lightbox-button", "aria-label": "Open", onClick: (e) => item.onOpen?.(e.currentTarget), children: _jsx20(ExternalGlyph, { size: 16 }) }), _jsx20("button", { ref: closer, type: "button", className: "hs-lightbox-button", "aria-label": "Close", onClick: onClose, children: _jsx20(CloseGlyph, { size: 16 }) })] }), many && _jsx20("button", { type: "button", className: "hs-lightbox-step", "data-side": "previous", "aria-label": "Previous picture", onClick: (e) => {
|
|
826
921
|
e.stopPropagation();
|
|
827
922
|
step(-1);
|
|
828
|
-
}, children:
|
|
923
|
+
}, children: _jsx20(ChevronLeftGlyph, { size: 20 }) }), _jsxs13("div", { className: "hs-lightbox-body", onClick: (e) => e.stopPropagation(), children: [_jsx20("div", { ref: stage, className: "hs-lightbox-stage", "data-zoomed": view.scale > 1 ? "true" : "false", onPointerDown, onPointerMove, onPointerUp, children: broken ? _jsx20("span", { className: "hs-lightbox-broken", children: "This picture could not be loaded." }) : _jsx20("img", { src: item.src, alt: item.name, draggable: false, onError: () => setBroken(true), style: { transform: `translate(${view.x}px, ${view.y}px) scale(${view.scale})` } }) }), _jsxs13("span", { className: "hs-lightbox-caption", "aria-live": "polite", children: [item.name, many && ` (${index + 1} of ${items.length})`] }), item.note && _jsx20("div", { className: "hs-lightbox-note", children: item.note })] }), many && _jsx20("button", { type: "button", className: "hs-lightbox-step", "data-side": "next", "aria-label": "Next picture", onClick: (e) => {
|
|
829
924
|
e.stopPropagation();
|
|
830
925
|
step(1);
|
|
831
|
-
}, children:
|
|
832
|
-
return
|
|
926
|
+
}, children: _jsx20(ChevronRightGlyph, { size: 20 }) })] });
|
|
927
|
+
return _jsxs13(_Fragment5, { children: [_jsx20("span", { ref: anchor, hidden: true }), host && createPortal2(dialog, host)] });
|
|
833
928
|
}
|
|
834
929
|
|
|
835
930
|
// ../ui/dist/Slider.js
|
|
836
|
-
import { jsx as
|
|
931
|
+
import { jsx as _jsx21, jsxs as _jsxs14 } from "react/jsx-runtime";
|
|
837
932
|
function Slider({ value, onChange, min = 0, max = 1, step = 0.01, label, shown, disabled }) {
|
|
838
|
-
return
|
|
933
|
+
return _jsxs14("span", { className: "hs-slider", children: [_jsx21("input", { type: "range", className: "hs-range", "aria-label": label, "aria-valuetext": shown, min, max, step, value, disabled, onChange: (event) => onChange(Number(event.target.value)) }), shown !== void 0 && _jsx21("span", { className: "hs-slider-value", children: shown })] });
|
|
839
934
|
}
|
|
840
935
|
|
|
841
936
|
// ../ui/dist/Popover.js
|
|
842
|
-
import { jsx as
|
|
843
|
-
import { useEffect as
|
|
937
|
+
import { jsx as _jsx22 } from "react/jsx-runtime";
|
|
938
|
+
import { useEffect as useEffect10, useLayoutEffect as useLayoutEffect5, useRef as useRef9, useState as useState5 } from "react";
|
|
844
939
|
import { createPortal as createPortal3 } from "react-dom";
|
|
845
940
|
import { autoUpdate as autoUpdate2, computePosition as computePosition2, flip as flip2, offset as offset2, shift as shift2, size as size2 } from "@floating-ui/dom";
|
|
846
941
|
var tabbable = (panel) => [...panel.querySelectorAll(FOCUSABLE)].filter((control) => control.tabIndex >= 0);
|
|
847
942
|
var FOCUSABLE = 'button:not(:disabled), [href], input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"]), [contenteditable="true"]';
|
|
848
943
|
function Popover({ anchor, placement = "bottom-start", label, onDismiss, children }) {
|
|
849
|
-
const panel =
|
|
850
|
-
const [root] =
|
|
851
|
-
const [pos, setPos] =
|
|
852
|
-
const dismiss =
|
|
944
|
+
const panel = useRef9(null);
|
|
945
|
+
const [root] = useState5(() => popupRoot(anchor));
|
|
946
|
+
const [pos, setPos] = useState5({ visibility: "hidden" });
|
|
947
|
+
const dismiss = useRef9(onDismiss);
|
|
853
948
|
dismiss.current = onDismiss;
|
|
854
949
|
useLayoutEffect5(() => {
|
|
855
950
|
const floating = panel.current;
|
|
@@ -891,8 +986,8 @@ function Popover({ anchor, placement = "bottom-start", label, onDismiss, childre
|
|
|
891
986
|
anchor.focus();
|
|
892
987
|
};
|
|
893
988
|
}, [shown, anchor]);
|
|
894
|
-
const pressed =
|
|
895
|
-
|
|
989
|
+
const pressed = useRef9(null);
|
|
990
|
+
useEffect10(() => {
|
|
896
991
|
const outside = (event) => {
|
|
897
992
|
if (pressed.current !== event && !anchor.contains(event.target))
|
|
898
993
|
dismiss.current();
|
|
@@ -905,7 +1000,7 @@ function Popover({ anchor, placement = "bottom-start", label, onDismiss, childre
|
|
|
905
1000
|
window.removeEventListener("blur", blur);
|
|
906
1001
|
};
|
|
907
1002
|
}, [anchor]);
|
|
908
|
-
return createPortal3(
|
|
1003
|
+
return createPortal3(_jsx22("div", { ref: panel, className: "hs-popover", role: "dialog", "aria-label": label, tabIndex: -1, style: pos, onPointerDown: (event) => {
|
|
909
1004
|
pressed.current = event.nativeEvent;
|
|
910
1005
|
}, onKeyDown: (event) => {
|
|
911
1006
|
if (event.key === "Escape") {
|
|
@@ -935,15 +1030,15 @@ function Popover({ anchor, placement = "bottom-start", label, onDismiss, childre
|
|
|
935
1030
|
}
|
|
936
1031
|
|
|
937
1032
|
// ../ui/dist/Toast.js
|
|
938
|
-
import { jsx as
|
|
939
|
-
import { useEffect as
|
|
1033
|
+
import { jsx as _jsx23, jsxs as _jsxs15 } from "react/jsx-runtime";
|
|
1034
|
+
import { useEffect as useEffect11, useLayoutEffect as useLayoutEffect6, useRef as useRef10, useState as useState6 } from "react";
|
|
940
1035
|
import { createPortal as createPortal4 } from "react-dom";
|
|
941
1036
|
function Toast({ children, action, duration = 6e3, above, onClose }) {
|
|
942
|
-
const [root, setRoot] =
|
|
943
|
-
const place =
|
|
944
|
-
const [held, setHeld] =
|
|
945
|
-
const [anchor, setAnchor] =
|
|
946
|
-
const close =
|
|
1037
|
+
const [root, setRoot] = useState6(null);
|
|
1038
|
+
const place = useRef10(null);
|
|
1039
|
+
const [held, setHeld] = useState6({ pointer: false, focus: false });
|
|
1040
|
+
const [anchor, setAnchor] = useState6(null);
|
|
1041
|
+
const close = useRef10(onClose);
|
|
947
1042
|
close.current = onClose;
|
|
948
1043
|
useLayoutEffect6(() => {
|
|
949
1044
|
setRoot(place.current?.closest(".hs-shell") ?? document.body);
|
|
@@ -965,31 +1060,31 @@ function Toast({ children, action, duration = 6e3, above, onClose }) {
|
|
|
965
1060
|
return () => cancelAnimationFrame(frame);
|
|
966
1061
|
}, [above]);
|
|
967
1062
|
const waiting = !held.pointer && !held.focus;
|
|
968
|
-
|
|
1063
|
+
useEffect11(() => {
|
|
969
1064
|
if (!waiting)
|
|
970
1065
|
return;
|
|
971
1066
|
const timer = setTimeout(() => close.current(), duration);
|
|
972
1067
|
return () => clearTimeout(timer);
|
|
973
1068
|
}, [waiting, duration]);
|
|
974
|
-
return
|
|
1069
|
+
return _jsx23("span", { ref: place, hidden: true, children: root && createPortal4(_jsx23("div", { className: "hs-toast-place", ...anchor && {
|
|
975
1070
|
"data-above": "true",
|
|
976
1071
|
style: {
|
|
977
1072
|
bottom: `calc(${anchor.bottom}px + var(--space) * 4)`,
|
|
978
1073
|
left: `${anchor.left}px`,
|
|
979
1074
|
width: `${anchor.width}px`
|
|
980
1075
|
}
|
|
981
|
-
}, children:
|
|
1076
|
+
}, children: _jsxs15("div", { className: "hs-toast", role: "status", "aria-live": "polite", onPointerEnter: () => setHeld((h) => ({ ...h, pointer: true })), onPointerLeave: () => setHeld((h) => ({ ...h, pointer: false })), onFocus: () => setHeld((h) => ({ ...h, focus: true })), onBlur: (event) => {
|
|
982
1077
|
if (!event.currentTarget.contains(event.relatedTarget))
|
|
983
1078
|
setHeld((h) => ({ ...h, focus: false }));
|
|
984
|
-
}, children: [
|
|
1079
|
+
}, children: [_jsx23("span", { className: "hs-toast-text", children }), action && _jsx23(Button, { variant: "ghost", size: "sm", onClick: () => {
|
|
985
1080
|
action.onPress();
|
|
986
1081
|
close.current();
|
|
987
|
-
}, children: action.label }),
|
|
1082
|
+
}, children: action.label }), _jsx23(IconButton, { size: "sm", "aria-label": "Close", onClick: () => close.current(), children: _jsx23(CloseGlyph, {}) })] }) }), root) });
|
|
988
1083
|
}
|
|
989
1084
|
|
|
990
1085
|
// ../ui/dist/DatePicker.js
|
|
991
|
-
import { jsx as
|
|
992
|
-
import { useEffect as
|
|
1086
|
+
import { jsx as _jsx24, jsxs as _jsxs16, Fragment as _Fragment6 } from "react/jsx-runtime";
|
|
1087
|
+
import { useEffect as useEffect12, useMemo, useRef as useRef11, useState as useState7 } from "react";
|
|
993
1088
|
var pad = (n, width = 2) => String(n).padStart(width, "0");
|
|
994
1089
|
function instant(date) {
|
|
995
1090
|
const [year, month, day] = date.split("-").map(Number);
|
|
@@ -1023,15 +1118,15 @@ function firstDayOfWeek(locale) {
|
|
|
1023
1118
|
var STEPS = { ArrowLeft: -1, ArrowRight: 1, ArrowUp: -7, ArrowDown: 7 };
|
|
1024
1119
|
function DateGrid({ value, onChange, locale, min, max }) {
|
|
1025
1120
|
const now = today();
|
|
1026
|
-
const [focus, setFocus] =
|
|
1121
|
+
const [focus, setFocus] = useState7(value ?? now);
|
|
1027
1122
|
const month = monthOf(focus);
|
|
1028
|
-
const keyed =
|
|
1029
|
-
const days =
|
|
1030
|
-
|
|
1123
|
+
const keyed = useRef11(false);
|
|
1124
|
+
const days = useRef11(/* @__PURE__ */ new Map());
|
|
1125
|
+
useEffect12(() => {
|
|
1031
1126
|
if (value)
|
|
1032
1127
|
setFocus(value);
|
|
1033
1128
|
}, [value]);
|
|
1034
|
-
|
|
1129
|
+
useEffect12(() => {
|
|
1035
1130
|
if (!keyed.current)
|
|
1036
1131
|
return;
|
|
1037
1132
|
keyed.current = false;
|
|
@@ -1057,7 +1152,7 @@ function DateGrid({ value, onChange, locale, min, max }) {
|
|
|
1057
1152
|
keyed.current = true;
|
|
1058
1153
|
setFocus(min && next < min ? min : max && next > max ? max : next);
|
|
1059
1154
|
};
|
|
1060
|
-
return
|
|
1155
|
+
return _jsxs16("div", { className: "hs-date-grid", children: [_jsxs16("div", { className: "hs-date-grid-head", children: [_jsx24("span", { className: "hs-date-grid-month", "aria-live": "polite", children: words.month.format(instant(month)) }), _jsx24(IconButton, { size: "sm", "aria-label": "Previous month", onClick: () => setFocus(addMonths(focus, -1)), children: _jsx24(ChevronLeftGlyph, {}) }), _jsx24(IconButton, { size: "sm", "aria-label": "Next month", onClick: () => setFocus(addMonths(focus, 1)), children: _jsx24(ChevronRightGlyph, {}) })] }), _jsxs16("div", { className: "hs-date-grid-days", role: "grid", "aria-label": words.month.format(instant(month)), children: [_jsx24("div", { role: "row", className: "hs-date-grid-row", children: weeks[0].map((day) => _jsx24("span", { className: "hs-date-grid-weekday", role: "columnheader", "aria-label": words.long.format(instant(day)), children: words.narrow.format(instant(day)) }, day)) }), weeks.map((week) => _jsx24("div", { role: "row", className: "hs-date-grid-row", children: week.map((day) => _jsx24("button", { ref: (button) => {
|
|
1061
1156
|
if (button)
|
|
1062
1157
|
days.current.set(day, button);
|
|
1063
1158
|
else
|
|
@@ -1068,20 +1163,20 @@ function DateGrid({ value, onChange, locale, min, max }) {
|
|
|
1068
1163
|
}, onKeyDown: (event) => key(event, day), children: words.day.format(instant(day)) }, day)) }, week[0]))] })] });
|
|
1069
1164
|
}
|
|
1070
1165
|
function DatePicker({ value, onChange, locale, min, max, label, placeholder, disabled }) {
|
|
1071
|
-
const [anchor, setAnchor] =
|
|
1166
|
+
const [anchor, setAnchor] = useState7(null);
|
|
1072
1167
|
const shown = useMemo(() => new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeZone: "UTC" }), [locale]);
|
|
1073
|
-
return
|
|
1168
|
+
return _jsxs16(_Fragment6, { children: [_jsx24("button", { type: "button", className: "hs-input hs-picker-field", "aria-label": label, "aria-haspopup": "dialog", "aria-expanded": anchor !== null, "data-empty": value === null, disabled, onClick: (event) => setAnchor(anchor ? null : event.currentTarget), children: value ? shown.format(instant(value)) : placeholder }), anchor && _jsx24(Popover, { anchor, label, onDismiss: () => setAnchor(null), children: _jsx24(DateGrid, { value, locale, ...min && { min }, ...max && { max }, onChange: (date) => {
|
|
1074
1169
|
onChange(date);
|
|
1075
1170
|
setAnchor(null);
|
|
1076
1171
|
} }) })] });
|
|
1077
1172
|
}
|
|
1078
1173
|
|
|
1079
1174
|
// ../ui/dist/TimePicker.js
|
|
1080
|
-
import { jsx as
|
|
1081
|
-
import { useMemo as useMemo2, useState as
|
|
1175
|
+
import { jsx as _jsx25, Fragment as _Fragment7, jsxs as _jsxs17 } from "react/jsx-runtime";
|
|
1176
|
+
import { useMemo as useMemo2, useState as useState8 } from "react";
|
|
1082
1177
|
var pad2 = (n) => String(n).padStart(2, "0");
|
|
1083
1178
|
function TimePicker({ value, onChange, locale, label, step = 15, placeholder, disabled }) {
|
|
1084
|
-
const [anchor, setAnchor] =
|
|
1179
|
+
const [anchor, setAnchor] = useState8(null);
|
|
1085
1180
|
const shown = useMemo2(() => new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "2-digit", timeZone: "UTC" }), [locale]);
|
|
1086
1181
|
const words = (time) => {
|
|
1087
1182
|
const [hours, minutes] = time.split(":").map(Number);
|
|
@@ -1094,7 +1189,7 @@ function TimePicker({ value, onChange, locale, label, step = 15, placeholder, di
|
|
|
1094
1189
|
});
|
|
1095
1190
|
return value && !steps.includes(value) ? [...steps, value].sort() : steps;
|
|
1096
1191
|
}, [step, value]);
|
|
1097
|
-
return
|
|
1192
|
+
return _jsxs17(_Fragment7, { children: [_jsx25("button", { type: "button", className: "hs-input hs-picker-field", "aria-label": label, "aria-haspopup": "menu", "aria-expanded": anchor !== null, "data-empty": value === null, disabled, onClick: (event) => setAnchor(anchor ? null : { key: "time", element: event.currentTarget }), children: value ? words(value) : placeholder }), anchor && _jsx25(MenuSurface, { anchor, fit: true, keyboard: true, maxHeight: spaces(70), onDismiss: () => setAnchor(null), children: times.map((time) => _jsx25(MItem, { label: words(time), checked: time === value, onClick: () => {
|
|
1098
1193
|
onChange(time);
|
|
1099
1194
|
setAnchor(null);
|
|
1100
1195
|
anchor.element.focus();
|
|
@@ -1102,8 +1197,8 @@ function TimePicker({ value, onChange, locale, label, step = 15, placeholder, di
|
|
|
1102
1197
|
}
|
|
1103
1198
|
|
|
1104
1199
|
// ../ui/dist/SwatchPicker.js
|
|
1105
|
-
import { jsx as
|
|
1106
|
-
import { useRef as
|
|
1200
|
+
import { jsx as _jsx26 } from "react/jsx-runtime";
|
|
1201
|
+
import { useRef as useRef12 } from "react";
|
|
1107
1202
|
var SWATCHES = [
|
|
1108
1203
|
"rose",
|
|
1109
1204
|
"ember",
|
|
@@ -1136,7 +1231,7 @@ var NAMES = {
|
|
|
1136
1231
|
};
|
|
1137
1232
|
var STEPS2 = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 };
|
|
1138
1233
|
function SwatchPicker({ value, onChange, label }) {
|
|
1139
|
-
const dots =
|
|
1234
|
+
const dots = useRef12([]);
|
|
1140
1235
|
const tips = useFloatingTips();
|
|
1141
1236
|
const step = (event, index) => {
|
|
1142
1237
|
const by = STEPS2[event.key];
|
|
@@ -1147,17 +1242,17 @@ function SwatchPicker({ value, onChange, label }) {
|
|
|
1147
1242
|
onChange(SWATCHES[next]);
|
|
1148
1243
|
dots.current[next]?.focus();
|
|
1149
1244
|
};
|
|
1150
|
-
return
|
|
1245
|
+
return _jsx26("div", { className: "hs-swatch-picker", role: "radiogroup", "aria-label": label, children: SWATCHES.map((swatch, index) => {
|
|
1151
1246
|
const tip = tips(swatch, NAMES[swatch]);
|
|
1152
|
-
return
|
|
1247
|
+
return _jsx26("button", { ref: (dot) => {
|
|
1153
1248
|
dots.current[index] = dot;
|
|
1154
1249
|
}, type: "button", role: "radio", "aria-checked": swatch === value, "aria-label": NAMES[swatch], tabIndex: swatch === value ? 0 : -1, className: "hs-swatch-choice", "data-swatch": swatch, onClick: () => onChange(swatch), onKeyDown: (event) => step(event, index), ...tip.hover, children: tip.tip }, swatch);
|
|
1155
1250
|
}) });
|
|
1156
1251
|
}
|
|
1157
1252
|
|
|
1158
1253
|
// ../ui/dist/PersonMark.js
|
|
1159
|
-
import { jsx as
|
|
1160
|
-
import { useEffect as
|
|
1254
|
+
import { jsx as _jsx27 } from "react/jsx-runtime";
|
|
1255
|
+
import { useEffect as useEffect13, useState as useState9 } from "react";
|
|
1161
1256
|
function initials(name) {
|
|
1162
1257
|
const trimmed = name.trim();
|
|
1163
1258
|
const words = (/\s/.test(trimmed) ? trimmed : trimmed.split("@")[0]).split(/[\s._-]+/).filter(Boolean);
|
|
@@ -1173,17 +1268,17 @@ function hueOf(name) {
|
|
|
1173
1268
|
return SWATCHES[(hash >>> 0) % 12];
|
|
1174
1269
|
}
|
|
1175
1270
|
function PersonMark({ name, picture, size: size3 = "md", swatch }) {
|
|
1176
|
-
const [broken, setBroken] =
|
|
1177
|
-
|
|
1178
|
-
return
|
|
1271
|
+
const [broken, setBroken] = useState9(false);
|
|
1272
|
+
useEffect13(() => setBroken(false), [picture]);
|
|
1273
|
+
return _jsx27("span", { className: "hs-person-mark", "data-size": size3, "data-swatch": swatch ?? hueOf(name), role: "img", "aria-label": name, children: picture && !broken ? _jsx27("img", { src: picture, alt: "", onError: () => setBroken(true) }) : initials(name) });
|
|
1179
1274
|
}
|
|
1180
1275
|
|
|
1181
1276
|
// ../ui/dist/ModelAvatar.js
|
|
1182
|
-
import { jsx as
|
|
1183
|
-
import { createContext as createContext4, useContext as useContext3, useState as
|
|
1277
|
+
import { jsx as _jsx29, jsxs as _jsxs18 } from "react/jsx-runtime";
|
|
1278
|
+
import { createContext as createContext4, useContext as useContext3, useState as useState10 } from "react";
|
|
1184
1279
|
|
|
1185
1280
|
// ../ui/dist/brand-marks.js
|
|
1186
|
-
import { jsx as
|
|
1281
|
+
import { jsx as _jsx28 } from "react/jsx-runtime";
|
|
1187
1282
|
|
|
1188
1283
|
// ../ui/dist/brand-svg.js
|
|
1189
1284
|
var BRAND_FILES = ["linux"];
|
|
@@ -1247,7 +1342,8 @@ var BRAND_SVG = {
|
|
|
1247
1342
|
vercel: '<svg viewBox="0 0 24 24" fill="currentColor" style="display:block;width:100%;height:100%"><path d="m12 1.608 12 20.784H0Z"/></svg>',
|
|
1248
1343
|
sentry: '<svg viewBox="0 0 24 24" fill="currentColor" style="display:block;width:100%;height:100%"><path d="M13.91 2.505c-.873-1.448-2.972-1.448-3.844 0L6.904 7.92a15.478 15.478 0 0 1 8.53 12.811h-2.221A13.301 13.301 0 0 0 5.784 9.814l-2.926 5.06a7.65 7.65 0 0 1 4.435 5.848H2.194a.365.365 0 0 1-.298-.534l1.413-2.402a5.16 5.16 0 0 0-1.614-.913L.296 19.275a2.182 2.182 0 0 0 .812 2.999 2.24 2.24 0 0 0 1.086.288h6.983a9.322 9.322 0 0 0-3.845-8.318l1.11-1.922a11.47 11.47 0 0 1 4.95 10.24h5.915a17.242 17.242 0 0 0-7.885-15.28l2.244-3.845a.37.37 0 0 1 .504-.13c.255.14 9.75 16.708 9.928 16.9a.365.365 0 0 1-.327.543h-2.287c.029.612.029 1.223 0 1.831h2.297a2.206 2.206 0 0 0 1.922-3.31z"/></svg>',
|
|
1249
1344
|
apple: '<svg viewBox="0 0 24 24" fill="currentColor" style="display:block;width:100%;height:100%"><path d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"/></svg>',
|
|
1250
|
-
windows: `<svg viewBox="0 0 22 22" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:block;width:100%;height:100%"><!-- The Microsoft squares on a white square. The white edge around them is one unit, the same as the gap between them, so the tile reads as the mark with its own margin. Drawn once, so every place shows the same tile. The colours are Microsoft's, as @lobehub/icons-static-svg carries them. --><rect width="22" height="22" fill="#fff"/><rect x="1" y="1" width="9.5" height="9.5" fill="#F25022"/><rect x="11.5" y="1" width="9.5" height="9.5" fill="#7FBA00"/><rect x="1" y="11.5" width="9.5" height="9.5" fill="#00A4EF"/><rect x="11.5" y="11.5" width="9.5" height="9.5" fill="#FFB900"/></svg
|
|
1345
|
+
windows: `<svg viewBox="0 0 22 22" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:block;width:100%;height:100%"><!-- The Microsoft squares on a white square. The white edge around them is one unit, the same as the gap between them, so the tile reads as the mark with its own margin. Drawn once, so every place shows the same tile. The colours are Microsoft's, as @lobehub/icons-static-svg carries them. --><rect width="22" height="22" fill="#fff"/><rect x="1" y="1" width="9.5" height="9.5" fill="#F25022"/><rect x="11.5" y="1" width="9.5" height="9.5" fill="#7FBA00"/><rect x="1" y="11.5" width="9.5" height="9.5" fill="#00A4EF"/><rect x="11.5" y="11.5" width="9.5" height="9.5" fill="#FFB900"/></svg>`,
|
|
1346
|
+
docker: '<svg viewBox="0 0 24 24" fill="#2496ED" style="display:block;width:100%;height:100%"><path d="M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.185.185 0 00-.185.185v1.888c0 .102.083.185.185.185m-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.887c0 .102.082.185.185.186m-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.185.185 0 00-.185.185v1.887c0 .102.083.185.185.186m-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.185.185 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.185.186.186m5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.083.185.185.185m-2.964 0h2.119a.185.185 0 00.185-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185m-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.082.185.185.185M23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.376 11.376 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.248 12.248 0 003.823-1.389c.98-.567 1.86-1.288 2.61-2.136 1.252-1.418 1.998-2.997 2.553-4.4h.221c1.372 0 2.215-.549 2.68-1.009.309-.293.55-.65.707-1.046l.098-.288Z"/></svg>'
|
|
1251
1347
|
};
|
|
1252
1348
|
|
|
1253
1349
|
// ../ui/dist/brand-marks.js
|
|
@@ -1312,7 +1408,8 @@ var BRAND_NAMES = {
|
|
|
1312
1408
|
sentry: "Sentry",
|
|
1313
1409
|
apple: "Apple",
|
|
1314
1410
|
linux: "Linux",
|
|
1315
|
-
windows: "Windows"
|
|
1411
|
+
windows: "Windows",
|
|
1412
|
+
docker: "Docker"
|
|
1316
1413
|
};
|
|
1317
1414
|
function BrandMark({ brand, size: size3 = 16, style }) {
|
|
1318
1415
|
const props = {
|
|
@@ -1321,7 +1418,7 @@ function BrandMark({ brand, size: size3 = 16, style }) {
|
|
|
1321
1418
|
"aria-label": BRAND_NAMES[brand],
|
|
1322
1419
|
style: { width: size3, height: size3, ...style }
|
|
1323
1420
|
};
|
|
1324
|
-
return isFileBrand(brand) ?
|
|
1421
|
+
return isFileBrand(brand) ? _jsx28("span", { ...props, "data-brand": brand }) : _jsx28("span", { ...props, dangerouslySetInnerHTML: { __html: BRAND_SVG[brand] } });
|
|
1325
1422
|
}
|
|
1326
1423
|
function isFileBrand(brand) {
|
|
1327
1424
|
return BRAND_FILES.includes(brand);
|
|
@@ -1368,25 +1465,25 @@ function brandOfPublisher(owner) {
|
|
|
1368
1465
|
// ../ui/dist/ModelAvatar.js
|
|
1369
1466
|
var PublisherPicturesContext = createContext4(() => void 0);
|
|
1370
1467
|
function ModelAvatar({ identity, server, size: size3 = 24 }) {
|
|
1371
|
-
return
|
|
1468
|
+
return _jsx29(PublisherAvatar, { identity, server, size: size3 }, `${server}:${identity.repository}:${identity.publisher}`);
|
|
1372
1469
|
}
|
|
1373
1470
|
function PublisherAvatar({ identity, server, size: size3 }) {
|
|
1374
1471
|
const pictures = useContext3(PublisherPicturesContext);
|
|
1375
1472
|
const owner = identity.repository?.split("/")[0];
|
|
1376
1473
|
const picture = owner ? pictures(server, owner) : void 0;
|
|
1377
|
-
const [failed, setFailed] =
|
|
1474
|
+
const [failed, setFailed] = useState10(false);
|
|
1378
1475
|
const brand = brandOfPublisher(identity.publisher);
|
|
1379
1476
|
const tips = useFloatingTips();
|
|
1380
1477
|
const { hover, tip } = tips("avatar", identity.publisher);
|
|
1381
|
-
return
|
|
1478
|
+
return _jsxs18("span", { className: "hs-model-avatar", style: { width: size3, height: size3 }, role: "img", "aria-label": identity.publisher, ...hover, children: [tip, picture && !failed ? _jsx29("img", { src: picture, alt: "", width: size3, height: size3, loading: "lazy", decoding: "async", onError: () => setFailed(true) }) : brand ? _jsx29(BrandMark, { brand, size: size3 }) : identity.publisher ? _jsx29("span", { className: "hs-model-avatar-initial", children: identity.publisher.slice(0, 1) }) : _jsx29(PackageGlyph, { size: size3 })] });
|
|
1382
1479
|
}
|
|
1383
1480
|
|
|
1384
1481
|
// ../ui/dist/VirtualList.js
|
|
1385
|
-
import { jsx as
|
|
1386
|
-
import { useImperativeHandle, useRef as
|
|
1482
|
+
import { jsx as _jsx30 } from "react/jsx-runtime";
|
|
1483
|
+
import { useImperativeHandle, useRef as useRef13 } from "react";
|
|
1387
1484
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
1388
1485
|
function VirtualList({ count, estimate, row, rowKey, className, ref }) {
|
|
1389
|
-
const scroller =
|
|
1486
|
+
const scroller = useRef13(null);
|
|
1390
1487
|
const list = useVirtualizer({
|
|
1391
1488
|
count,
|
|
1392
1489
|
getScrollElement: () => scroller.current,
|
|
@@ -1395,21 +1492,21 @@ function VirtualList({ count, estimate, row, rowKey, className, ref }) {
|
|
|
1395
1492
|
...rowKey && { getItemKey: rowKey }
|
|
1396
1493
|
});
|
|
1397
1494
|
useImperativeHandle(ref, () => ({ scrollToIndex: (index, align = "auto") => list.scrollToIndex(index, { align }) }), [list]);
|
|
1398
|
-
return
|
|
1495
|
+
return _jsx30("div", { ref: scroller, className: className ? `hs-virtual-list ${className}` : "hs-virtual-list", children: _jsx30("div", { className: "hs-virtual-list-rows", style: { height: list.getTotalSize() }, children: list.getVirtualItems().map((item) => _jsx30("div", { ref: list.measureElement, "data-index": item.index, className: "hs-virtual-list-row", style: { transform: `translateY(${item.start}px)` }, children: row(item.index) }, item.key)) }) });
|
|
1399
1496
|
}
|
|
1400
1497
|
|
|
1401
1498
|
// ../ui/dist/PictureCompare.js
|
|
1402
|
-
import { jsx as
|
|
1403
|
-
import { useRef as
|
|
1499
|
+
import { jsx as _jsx31, jsxs as _jsxs19 } from "react/jsx-runtime";
|
|
1500
|
+
import { useRef as useRef14, useState as useState11 } from "react";
|
|
1404
1501
|
var KEY_STEP = 5;
|
|
1405
1502
|
function PictureCompare({ before, after }) {
|
|
1406
|
-
const [split, setSplit] =
|
|
1407
|
-
const box =
|
|
1503
|
+
const [split, setSplit] = useState11(50);
|
|
1504
|
+
const box = useRef14(null);
|
|
1408
1505
|
const follow = (event) => {
|
|
1409
1506
|
const rect = box.current.getBoundingClientRect();
|
|
1410
1507
|
setSplit(Math.max(0, Math.min(100, (event.clientX - rect.left) / rect.width * 100)));
|
|
1411
1508
|
};
|
|
1412
|
-
return
|
|
1509
|
+
return _jsxs19("div", { ref: box, className: "hs-picture-compare", onPointerDown: (event) => {
|
|
1413
1510
|
if (event.button !== 0)
|
|
1414
1511
|
return;
|
|
1415
1512
|
event.currentTarget.setPointerCapture(event.pointerId);
|
|
@@ -1417,13 +1514,13 @@ function PictureCompare({ before, after }) {
|
|
|
1417
1514
|
}, onPointerMove: (event) => {
|
|
1418
1515
|
if (event.currentTarget.hasPointerCapture(event.pointerId))
|
|
1419
1516
|
follow(event);
|
|
1420
|
-
}, children: [
|
|
1517
|
+
}, children: [_jsx31("img", { src: before.src, alt: before.name, draggable: false }), _jsx31("div", { className: "hs-picture-compare-after", style: { clipPath: `inset(0 0 0 ${split}%)` }, children: _jsx31("img", { src: after.src, alt: after.name, draggable: false }) }), _jsx31("span", { className: "hs-picture-compare-name", "data-side": "before", children: before.name }), _jsx31("span", { className: "hs-picture-compare-name", "data-side": "after", children: after.name }), _jsx31("div", { className: "hs-picture-compare-handle", role: "slider", tabIndex: 0, "aria-label": `${before.name} and ${after.name}`, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(split), style: { left: `${split}%` }, onKeyDown: (event) => {
|
|
1421
1518
|
const next = event.key === "ArrowLeft" || event.key === "ArrowDown" ? split - KEY_STEP : event.key === "ArrowRight" || event.key === "ArrowUp" ? split + KEY_STEP : event.key === "Home" ? 0 : event.key === "End" ? 100 : null;
|
|
1422
1519
|
if (next === null)
|
|
1423
1520
|
return;
|
|
1424
1521
|
event.preventDefault();
|
|
1425
1522
|
setSplit(Math.max(0, Math.min(100, next)));
|
|
1426
|
-
}, children:
|
|
1523
|
+
}, children: _jsx31("span", { className: "hs-picture-compare-knob" }) })] });
|
|
1427
1524
|
}
|
|
1428
1525
|
|
|
1429
1526
|
// src/Icon.tsx
|
|
@@ -1462,8 +1559,10 @@ export {
|
|
|
1462
1559
|
MSub,
|
|
1463
1560
|
MenuSurface,
|
|
1464
1561
|
Meter,
|
|
1562
|
+
Modal,
|
|
1465
1563
|
ModelAvatar,
|
|
1466
1564
|
Mono,
|
|
1565
|
+
MultiSelect,
|
|
1467
1566
|
Notice,
|
|
1468
1567
|
OverlayScroll,
|
|
1469
1568
|
PageTitle,
|
|
@@ -1490,5 +1589,6 @@ export {
|
|
|
1490
1589
|
ToggleRow,
|
|
1491
1590
|
VirtualList,
|
|
1492
1591
|
anchorFrom,
|
|
1592
|
+
spaces,
|
|
1493
1593
|
useFloatingTips
|
|
1494
1594
|
};
|