@flood-md/react 0.2.6 → 0.2.9
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 +45 -1
- package/dist/alert-dialog.js +1 -1
- package/dist/calendar-period-grid.d.ts +17 -0
- package/dist/calendar-period-grid.js +13 -0
- package/dist/calendar-value.d.ts +10 -0
- package/dist/calendar-value.js +48 -0
- package/dist/calendar.d.ts +21 -0
- package/dist/calendar.js +259 -0
- package/dist/checkbox.js +1 -1
- package/dist/choice-group.js +1 -1
- package/dist/collection-cards.d.ts +4 -0
- package/dist/collection-cards.js +21 -0
- package/dist/color-controls.d.ts +5 -0
- package/dist/color-controls.js +110 -0
- package/dist/combobox.js +22 -13
- package/dist/command-list.d.ts +3 -0
- package/dist/command-list.js +93 -0
- package/dist/content-elements.js +7 -7
- package/dist/context-menu.d.ts +2 -0
- package/dist/context-menu.js +76 -0
- package/dist/data-display.js +2 -2
- package/dist/data-table.d.ts +2 -0
- package/dist/data-table.js +58 -0
- package/dist/date-field.d.ts +2 -0
- package/dist/date-field.js +172 -0
- package/dist/date-picker.d.ts +3 -0
- package/dist/date-picker.js +108 -0
- package/dist/date-range-field.d.ts +3 -0
- package/dist/date-range-field.js +84 -0
- package/dist/date-range-picker.d.ts +2 -0
- package/dist/date-range-picker.js +81 -0
- package/dist/date-range-value.d.ts +8 -0
- package/dist/date-range-value.js +13 -0
- package/dist/date-time-picker.d.ts +3 -0
- package/dist/date-time-picker.js +31 -0
- package/dist/date-time-range-picker.d.ts +2 -0
- package/dist/date-time-range-picker.js +51 -0
- package/dist/date-value.d.ts +10 -0
- package/dist/date-value.js +31 -0
- package/dist/disclosure.js +1 -1
- package/dist/editable.d.ts +3 -0
- package/dist/editable.js +135 -0
- package/dist/error-summary.d.ts +3 -0
- package/dist/error-summary.js +39 -0
- package/dist/feedback-actions.js +2 -2
- package/dist/feedback.js +2 -2
- package/dist/file-input.js +1 -1
- package/dist/file-records.d.ts +5 -0
- package/dist/file-records.js +55 -0
- package/dist/form-controls.js +25 -13
- package/dist/foundations.css +401 -3
- package/dist/hover-card.d.ts +3 -0
- package/dist/hover-card.js +144 -0
- package/dist/index.d.ts +661 -2
- package/dist/index.js +190 -86
- package/dist/menu.d.ts +27 -1
- package/dist/menu.js +327 -89
- package/dist/navigation-layout.js +6 -6
- package/dist/navigation-tree.d.ts +3 -0
- package/dist/navigation-tree.js +98 -0
- package/dist/navigation.js +3 -3
- package/dist/numeric-input.js +1 -1
- package/dist/overlays.js +11 -10
- package/dist/range-calendar.d.ts +2 -0
- package/dist/range-calendar.js +35 -0
- package/dist/resizable-panels.d.ts +3 -0
- package/dist/resizable-panels.js +205 -0
- package/dist/scroll-area.js +1 -1
- package/dist/select.js +17 -6
- package/dist/slider.js +1 -1
- package/dist/tag-input.d.ts +3 -0
- package/dist/tag-input.js +181 -0
- package/dist/text-inputs.js +2 -2
- package/dist/time-field.d.ts +2 -0
- package/dist/time-field.js +176 -0
- package/dist/time-picker.d.ts +2 -0
- package/dist/time-picker.js +83 -0
- package/dist/time-value.d.ts +12 -0
- package/dist/time-value.js +36 -0
- package/dist/toolbar.js +1 -1
- package/dist/tree-select.d.ts +3 -0
- package/dist/tree-select.js +113 -0
- package/dist/tree.d.ts +3 -0
- package/dist/tree.js +206 -0
- package/package.json +2 -2
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { IconButton } from "./index.js";
|
|
4
|
+
import { positionLayer, registerLayer, returnFocus, tabbables } from "./overlay-runtime.js";
|
|
5
|
+
const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
6
|
+
const delay = (value, fallback) => Number.isFinite(value) ? Math.max(0, value) : fallback;
|
|
7
|
+
/** A focus-preserving preview; explicit activation pins it for pointer/touch use. */
|
|
8
|
+
export const HoverPreview = /* @__PURE__ */ forwardRef(function HoverPreview({ trigger, title, children, open: controlled, defaultOpen = false, onOpenChange, openDelay = 300, closeDelay = 180, side = "bottom", align = "start", disabled = false, closeLabel = "Close preview", id: explicitId, className, onPointerEnter, onPointerLeave, onFocus, onBlur, ...attributes }, forwardedRef) {
|
|
9
|
+
const [local, setLocal] = useState(defaultOpen);
|
|
10
|
+
const open = !disabled && (controlled ?? local);
|
|
11
|
+
const anchor = useRef(null), panel = useRef(null);
|
|
12
|
+
const generated = useId(), id = explicitId ?? `flood-hover-card-${generated}`;
|
|
13
|
+
const timer = useRef(undefined);
|
|
14
|
+
const hovered = useRef(false), overPanel = useRef(false), focused = useRef(false);
|
|
15
|
+
const pinned = useRef(defaultOpen), suppressed = useRef(false), focusRequested = useRef(false);
|
|
16
|
+
const current = useRef({ controlled, onOpenChange, open, disabled });
|
|
17
|
+
useBrowserLayoutEffect(() => { current.current = { controlled, onOpenChange, open, disabled }; });
|
|
18
|
+
const setAnchor = useCallback((element) => { anchor.current = element; }, []);
|
|
19
|
+
useImperativeHandle(forwardedRef, () => panel.current, []);
|
|
20
|
+
const clear = () => { clearTimeout(timer.current); timer.current = undefined; };
|
|
21
|
+
const request = (next) => {
|
|
22
|
+
clear();
|
|
23
|
+
if (next && (current.current.disabled || anchor.current?.matches(":disabled")))
|
|
24
|
+
return;
|
|
25
|
+
if (current.current.controlled === undefined)
|
|
26
|
+
setLocal(next);
|
|
27
|
+
if (current.current.open !== next)
|
|
28
|
+
current.current.onOpenChange?.(next);
|
|
29
|
+
};
|
|
30
|
+
const close = () => { pinned.current = false; suppressed.current = true; focusRequested.current = false; request(false); };
|
|
31
|
+
const latest = useRef({ request, close });
|
|
32
|
+
useBrowserLayoutEffect(() => { latest.current = { request, close }; });
|
|
33
|
+
const leave = () => {
|
|
34
|
+
clear();
|
|
35
|
+
if (hovered.current || overPanel.current || focused.current || pinned.current)
|
|
36
|
+
return;
|
|
37
|
+
suppressed.current = false;
|
|
38
|
+
timer.current = setTimeout(() => latest.current.request(false), delay(closeDelay, 180));
|
|
39
|
+
};
|
|
40
|
+
const enter = (immediate = false) => {
|
|
41
|
+
clear();
|
|
42
|
+
if (suppressed.current || disabled)
|
|
43
|
+
return;
|
|
44
|
+
if (immediate)
|
|
45
|
+
request(true);
|
|
46
|
+
else
|
|
47
|
+
timer.current = setTimeout(() => latest.current.request(true), delay(openDelay, 300));
|
|
48
|
+
};
|
|
49
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
50
|
+
useEffect(() => { if (disabled) {
|
|
51
|
+
clear();
|
|
52
|
+
pinned.current = false;
|
|
53
|
+
suppressed.current = false;
|
|
54
|
+
setLocal(false);
|
|
55
|
+
} }, [disabled]);
|
|
56
|
+
useBrowserLayoutEffect(() => {
|
|
57
|
+
if (!open || !panel.current)
|
|
58
|
+
return;
|
|
59
|
+
const element = panel.current, document = element.ownerDocument, view = document.defaultView;
|
|
60
|
+
let alive = true, frame = 0, unregister = () => { };
|
|
61
|
+
const position = () => {
|
|
62
|
+
if (!alive)
|
|
63
|
+
return;
|
|
64
|
+
if (!anchor.current?.isConnected) {
|
|
65
|
+
latest.current.close();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
positionLayer(anchor.current, element, side, align);
|
|
69
|
+
frame = view.requestAnimationFrame(position);
|
|
70
|
+
};
|
|
71
|
+
const start = () => {
|
|
72
|
+
if (!alive || !anchor.current?.isConnected)
|
|
73
|
+
return;
|
|
74
|
+
const parent = anchor.current.closest("dialog");
|
|
75
|
+
if (parent && !parent.open) {
|
|
76
|
+
frame = view.requestAnimationFrame(start);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (typeof element.showPopover !== "function")
|
|
80
|
+
throw new Error("Flood HoverCard requires the native Popover API");
|
|
81
|
+
element.style.visibility = "hidden";
|
|
82
|
+
element.showPopover();
|
|
83
|
+
unregister = registerLayer(document, { panel: element, anchor: () => anchor.current, close: () => latest.current.close() });
|
|
84
|
+
position();
|
|
85
|
+
if (focusRequested.current) {
|
|
86
|
+
focusRequested.current = false;
|
|
87
|
+
(tabbables(element)[0] ?? element).focus({ preventScroll: true });
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const toggle = (event) => {
|
|
91
|
+
if (!alive || event.newState !== "closed" || element.matches(":popover-open") || !current.current.open)
|
|
92
|
+
return;
|
|
93
|
+
latest.current.close();
|
|
94
|
+
// A controlled owner may reject dismissal. Keep its rendered state authoritative.
|
|
95
|
+
queueMicrotask(() => { if (alive && current.current.open && element.isConnected && !element.matches(":popover-open")) {
|
|
96
|
+
element.showPopover();
|
|
97
|
+
if (anchor.current)
|
|
98
|
+
positionLayer(anchor.current, element, side, align);
|
|
99
|
+
} });
|
|
100
|
+
};
|
|
101
|
+
element.addEventListener("toggle", toggle);
|
|
102
|
+
start();
|
|
103
|
+
return () => {
|
|
104
|
+
alive = false;
|
|
105
|
+
view.cancelAnimationFrame(frame);
|
|
106
|
+
unregister();
|
|
107
|
+
element.removeEventListener("toggle", toggle);
|
|
108
|
+
returnFocus(element, anchor.current);
|
|
109
|
+
if (element.matches(":popover-open"))
|
|
110
|
+
element.hidePopover();
|
|
111
|
+
};
|
|
112
|
+
}, [open, side, align]);
|
|
113
|
+
const triggerProps = {
|
|
114
|
+
ref: setAnchor, type: "button", disabled, "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": id,
|
|
115
|
+
onPointerEnter: event => { if (event.pointerType === "touch")
|
|
116
|
+
return; hovered.current = true; enter(); },
|
|
117
|
+
onPointerLeave: () => { hovered.current = false; leave(); },
|
|
118
|
+
onFocus: () => { focused.current = true; enter(true); },
|
|
119
|
+
onBlur: event => { focused.current = Boolean(panel.current?.contains(event.relatedTarget)); leave(); },
|
|
120
|
+
onClick: () => {
|
|
121
|
+
if (pinned.current && open)
|
|
122
|
+
close();
|
|
123
|
+
else {
|
|
124
|
+
suppressed.current = false;
|
|
125
|
+
pinned.current = true;
|
|
126
|
+
request(true);
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
onKeyDown: event => {
|
|
130
|
+
if (event.defaultPrevented || event.key !== "ArrowDown" || disabled)
|
|
131
|
+
return;
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
suppressed.current = false;
|
|
134
|
+
pinned.current = true;
|
|
135
|
+
if (open && panel.current)
|
|
136
|
+
(tabbables(panel.current)[0] ?? panel.current).focus({ preventScroll: true });
|
|
137
|
+
else {
|
|
138
|
+
focusRequested.current = true;
|
|
139
|
+
request(true);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
return _jsxs(_Fragment, { children: [trigger(triggerProps), _jsxs("div", { ...attributes, ref: panel, id: id, popover: "manual", role: "dialog", "aria-modal": "false", "aria-labelledby": `${id}-title`, tabIndex: -1, className: ["flood-overlay-panel", "flood-hover-card", className].filter(Boolean).join(" "), onPointerEnter: event => { onPointerEnter?.(event); overPanel.current = true; clear(); }, onPointerLeave: event => { onPointerLeave?.(event); overPanel.current = false; leave(); }, onFocus: event => { onFocus?.(event); focused.current = true; clear(); }, onBlur: event => { onBlur?.(event); const target = event.relatedTarget; focused.current = Boolean(panel.current?.contains(target) || anchor.current?.contains(target)); leave(); }, children: [_jsxs("div", { className: "flood-overlay-header", children: [_jsx("h2", { id: `${id}-title`, className: "flood-overlay-title", children: title }), _jsx(IconButton, { label: closeLabel, size: "xs", variant: "ghost", className: "flood-overlay-close", onClick: close, children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "m6 6 12 12M18 6 6 18" }) }) })] }), open && _jsx("div", { className: "flood-hover-card__body", children: children })] })] });
|
|
144
|
+
});
|