@phreshos/react-ui 0.1.47 → 0.1.49
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/dist/app-layout.d.ts +17 -2
- package/dist/app-layout.js +7 -6
- package/dist/context-menu.d.ts +3 -0
- package/dist/context-menu.js +3 -0
- package/dist/control/item.d.ts +5 -0
- package/dist/control/item.js +8 -1
- package/dist/control/selection.js +12 -2
- package/dist/dialog.js +5 -2
- package/dist/document-theme.d.ts +7 -2
- package/dist/document-theme.js +38 -3
- package/dist/drag-and-drop.d.ts +7 -0
- package/dist/drag-and-drop.js +7 -0
- package/dist/dropdown-menu.d.ts +3 -0
- package/dist/grid-list.js +8 -5
- package/dist/loading.d.ts +13 -10
- package/dist/loading.js +25 -16
- package/dist/main.d.ts +4 -3
- package/dist/main.js +1 -0
- package/dist/menu.d.ts +13 -0
- package/dist/menu.js +18 -4
- package/dist/table.js +6 -4
- package/dist/tree.d.ts +10 -0
- package/dist/tree.js +17 -6
- package/package.json +2 -2
package/dist/app-layout.d.ts
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
import type { CSSProperties, HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import { type SurfaceDepth } from "./surface/surface.js";
|
|
2
3
|
export interface AppLayoutProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
4
|
readonly children: ReactNode;
|
|
4
5
|
/** The sidebar's width; eighteen times the Appearance spacing by default. */
|
|
5
6
|
readonly sidebarWidth?: CSSProperties["width"];
|
|
6
7
|
}
|
|
7
8
|
export type AppLayoutRegionProps = HTMLAttributes<HTMLElement>;
|
|
9
|
+
export type AppLayoutContentProps = AppLayoutRegionProps & Readonly<{
|
|
10
|
+
/** How the content's Surface stands in the layout: recessed into it by default, or raised. */
|
|
11
|
+
depth?: SurfaceDepth;
|
|
12
|
+
}>;
|
|
13
|
+
export type AppLayoutSidebarProps = AppLayoutRegionProps & Readonly<{
|
|
14
|
+
/** What stays at the foot of the sidebar while the rest scrolls, such as work in progress. */
|
|
15
|
+
footer?: ReactNode;
|
|
16
|
+
}>;
|
|
8
17
|
export type AppLayoutTitleProps = HTMLAttributes<HTMLHeadingElement>;
|
|
9
18
|
export declare const AppLayout: import("react").ForwardRefExoticComponent<AppLayoutProps & import("react").RefAttributes<HTMLDivElement>> & {
|
|
10
19
|
Title: import("react").ForwardRefExoticComponent<AppLayoutTitleProps & import("react").RefAttributes<HTMLHeadingElement>>;
|
|
11
|
-
Sidebar: import("react").ForwardRefExoticComponent<AppLayoutRegionProps &
|
|
20
|
+
Sidebar: import("react").ForwardRefExoticComponent<AppLayoutRegionProps & Readonly<{
|
|
21
|
+
/** What stays at the foot of the sidebar while the rest scrolls, such as work in progress. */
|
|
22
|
+
footer?: ReactNode;
|
|
23
|
+
}> & import("react").RefAttributes<HTMLElement>>;
|
|
12
24
|
Header: import("react").ForwardRefExoticComponent<AppLayoutRegionProps & import("react").RefAttributes<HTMLElement>>;
|
|
13
|
-
Content: import("react").ForwardRefExoticComponent<AppLayoutRegionProps &
|
|
25
|
+
Content: import("react").ForwardRefExoticComponent<AppLayoutRegionProps & Readonly<{
|
|
26
|
+
/** How the content's Surface stands in the layout: recessed into it by default, or raised. */
|
|
27
|
+
depth?: SurfaceDepth;
|
|
28
|
+
}> & import("react").RefAttributes<HTMLElement>>;
|
|
14
29
|
Footer: import("react").ForwardRefExoticComponent<AppLayoutRegionProps & import("react").RefAttributes<HTMLElement>>;
|
|
15
30
|
};
|
package/dist/app-layout.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, forwardRef, useContext } from "react";
|
|
3
3
|
import { controlFontSizes, controlFontWeight } from "./control/control.js";
|
|
4
4
|
import { headerHeight } from "./foundation/layout.js";
|
|
@@ -54,10 +54,11 @@ const AppLayoutTitle = forwardRef(function AppLayoutTitle({ style, ...properties
|
|
|
54
54
|
...style
|
|
55
55
|
} });
|
|
56
56
|
});
|
|
57
|
-
/** The sidebar, such as a program's navigation. It scrolls on its own. */
|
|
58
|
-
const AppLayoutSidebar = forwardRef(function AppLayoutSidebar({ children, style, ...properties }, ref) {
|
|
57
|
+
/** The sidebar, such as a program's navigation. It scrolls on its own, above its footer. */
|
|
58
|
+
const AppLayoutSidebar = forwardRef(function AppLayoutSidebar({ children, footer, style, ...properties }, ref) {
|
|
59
59
|
const { spacing } = useLayout();
|
|
60
|
-
|
|
60
|
+
const padding = scale(spacing, "small");
|
|
61
|
+
return _jsxs("aside", { ...properties, ref: ref, style: { gridArea: "sidebar", minHeight: 0, display: "flex", flexDirection: "column", ...style }, children: [_jsx(ScrollArea, { style: { flex: "1 1 auto", minHeight: 0 }, children: _jsx("div", { style: { padding }, children: children }) }), footer != null && _jsx("div", { style: { flex: "none", paddingInline: padding, paddingBottom: padding }, children: footer })] });
|
|
61
62
|
});
|
|
62
63
|
/** The header row above the content, as tall as a Window or Panel header. */
|
|
63
64
|
const AppLayoutHeader = forwardRef(function AppLayoutHeader({ style, ...properties }, ref) {
|
|
@@ -73,9 +74,9 @@ const AppLayoutHeader = forwardRef(function AppLayoutHeader({ style, ...properti
|
|
|
73
74
|
} });
|
|
74
75
|
});
|
|
75
76
|
/** The content, on its Surface. It scrolls on its own, padded by the Appearance spacing. */
|
|
76
|
-
const AppLayoutContent = forwardRef(function AppLayoutContent({ children, style, ...properties }, ref) {
|
|
77
|
+
const AppLayoutContent = forwardRef(function AppLayoutContent({ children, depth = "recessed", style, ...properties }, ref) {
|
|
77
78
|
const { spacing, radius } = useLayout();
|
|
78
|
-
return _jsx(Surface, { as: "main", ...properties, ref: ref, material: "extended", radius: resolveRadius("medium", radius), style: {
|
|
79
|
+
return _jsx(Surface, { as: "main", ...properties, ref: ref, depth: depth, material: "extended", radius: resolveRadius("medium", radius), style: {
|
|
79
80
|
gridArea: "content",
|
|
80
81
|
minWidth: 0,
|
|
81
82
|
minHeight: 0,
|
package/dist/context-menu.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export declare const ContextMenu: typeof ContextMenuRoot & {
|
|
|
21
21
|
Section: <T extends object = object>(properties: import("./menu.js").MenuSectionProps<T>) => import("react").ReactElement | null;
|
|
22
22
|
Header: import("react").ForwardRefExoticComponent<import("react-aria-components").HeaderProps & import("react").RefAttributes<HTMLElement>>;
|
|
23
23
|
Separator: import("react").ForwardRefExoticComponent<import("react-aria-components").SeparatorProps & import("react").RefAttributes<HTMLElement>>;
|
|
24
|
+
Submenu: (({ children, delay }: import("./menu.js").MenuSubmenuProps) => import("react").JSX.Element) & {
|
|
25
|
+
Content: import("react").ForwardRefExoticComponent<import("./menu.js").MenuSubmenuContentProps & import("react").RefAttributes<HTMLElement>>;
|
|
26
|
+
};
|
|
24
27
|
};
|
|
25
28
|
};
|
|
26
29
|
export type ContextMenuProps = ComponentProps<typeof ContextMenuRoot>;
|
package/dist/context-menu.js
CHANGED
|
@@ -36,6 +36,9 @@ export const ContextMenuContent = forwardRef(function ContextMenuContent(propert
|
|
|
36
36
|
const target = event.target;
|
|
37
37
|
if (target instanceof Node && contentRef.current?.contains(target))
|
|
38
38
|
return;
|
|
39
|
+
// A Submenu opens in its own overlay; a press inside it is still inside this menu.
|
|
40
|
+
if (target instanceof Element && target.closest('[data-trigger="SubmenuTrigger"]'))
|
|
41
|
+
return;
|
|
39
42
|
state?.close();
|
|
40
43
|
}
|
|
41
44
|
document.addEventListener("pointerdown", dismiss, true);
|
package/dist/control/item.d.ts
CHANGED
|
@@ -35,3 +35,8 @@ export declare function itemStyle(metrics: ControlMetrics, disabled: boolean): C
|
|
|
35
35
|
export declare function SelectionMark({ visible }: Readonly<{
|
|
36
36
|
visible: boolean;
|
|
37
37
|
}>): import("react").JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* A collection that a drag would drop into as a whole, outlined as focus is, so it reads as the place
|
|
40
|
+
* that takes the drop.
|
|
41
|
+
*/
|
|
42
|
+
export declare function dropTargetOutline(metrics: ControlMetrics, dropTarget: boolean | undefined): CSSProperties;
|
package/dist/control/item.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { colorLevel, mixColor, resolveColor } from "../foundation/color.js";
|
|
2
|
+
import { colorLevel, colorOpacity, mixColor, resolveColor } from "../foundation/color.js";
|
|
3
3
|
import { clearVeil, interactionShift, surfacePaint } from "../surface/surface.js";
|
|
4
4
|
import { transition } from "./control.js";
|
|
5
5
|
import { Check } from "lucide-react";
|
|
@@ -55,3 +55,10 @@ export function itemStyle(metrics, disabled) {
|
|
|
55
55
|
export function SelectionMark({ visible }) {
|
|
56
56
|
return _jsx(Check, { ...iconProps(14), style: { flexShrink: 0, marginInlineStart: "auto", opacity: visible ? 1 : 0 } });
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* A collection that a drag would drop into as a whole, outlined as focus is, so it reads as the place
|
|
60
|
+
* that takes the drop.
|
|
61
|
+
*/
|
|
62
|
+
export function dropTargetOutline(metrics, dropTarget) {
|
|
63
|
+
return dropTarget ? { outline: `3px solid ${colorOpacity(metrics.visual.colors.primary, 0.34)}`, outlineOffset: -3 } : {};
|
|
64
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The selection React Aria reported for each value handed out. It also remembers where a range
|
|
3
|
+
* started, which the strings alone lose; when the same value comes back, React Aria gets its own
|
|
4
|
+
* selection again, so Shift extends from the entry chosen last.
|
|
5
|
+
*/
|
|
6
|
+
const reported = new WeakMap();
|
|
1
7
|
export function toAriaSelection(value) {
|
|
2
8
|
if (value === undefined)
|
|
3
9
|
return undefined;
|
|
@@ -7,7 +13,7 @@ export function toAriaSelection(value) {
|
|
|
7
13
|
return new Set();
|
|
8
14
|
if (typeof value === "string")
|
|
9
15
|
return new Set([value]);
|
|
10
|
-
return new Set(value);
|
|
16
|
+
return reported.get(value) ?? new Set(value);
|
|
11
17
|
}
|
|
12
18
|
export function stringKey(value) {
|
|
13
19
|
if (typeof value !== "string")
|
|
@@ -21,7 +27,11 @@ export function singleSelection(selection) {
|
|
|
21
27
|
return selection === "all" ? null : optionalStringKey(selection.values().next().value ?? null);
|
|
22
28
|
}
|
|
23
29
|
export function multipleSelection(selection) {
|
|
24
|
-
|
|
30
|
+
if (selection === "all")
|
|
31
|
+
return "all";
|
|
32
|
+
const value = [...selection].map(stringKey);
|
|
33
|
+
reported.set(value, selection);
|
|
34
|
+
return value;
|
|
25
35
|
}
|
|
26
36
|
export function stringKeys(values) {
|
|
27
37
|
return [...values].map(stringKey);
|
package/dist/dialog.js
CHANGED
|
@@ -53,9 +53,12 @@ export const DialogContent = forwardRef(function DialogContent({ children, class
|
|
|
53
53
|
const padding = containerPadding(visual.spacing);
|
|
54
54
|
const transition = overlayTransition(visual);
|
|
55
55
|
const direction = resolveDirection(properties.dir, useDirection());
|
|
56
|
+
// The width belongs to the centered modal, so a Dialog of any width stays centered; the Surface fills it.
|
|
57
|
+
const { width = "32rem", maxWidth, ...surfaceStyle } = style ?? {};
|
|
56
58
|
return _jsxs(_Fragment, { children: [_jsx(MotionStyle, {}), _jsx(AriaModal, { dir: direction, className: overlayMotionClass, style: {
|
|
57
59
|
...transition,
|
|
58
|
-
width
|
|
60
|
+
width,
|
|
61
|
+
maxWidth: maxWidth ?? `calc(100vw - ${inset * 2}px)`,
|
|
59
62
|
maxHeight: `calc(100vh - ${inset * 2}px)`,
|
|
60
63
|
outline: "none"
|
|
61
64
|
}, children: _jsx(Surface, { className: className, color: color, material: material,
|
|
@@ -67,7 +70,7 @@ export const DialogContent = forwardRef(function DialogContent({ children, class
|
|
|
67
70
|
maxHeight: "inherit",
|
|
68
71
|
padding,
|
|
69
72
|
overflow: "hidden",
|
|
70
|
-
...
|
|
73
|
+
...surfaceStyle
|
|
71
74
|
}, children: _jsx(AriaDialog, { ...properties, ref: ref, style: {
|
|
72
75
|
display: "grid",
|
|
73
76
|
gap: inset,
|
package/dist/document-theme.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
import { type ReactElement } from "react";
|
|
1
2
|
/**
|
|
2
3
|
* Keeps the document's color scheme on the Theme of the nearest UIProvider,
|
|
3
4
|
* or on the browser's without one. It writes the Theme into the document's
|
|
4
5
|
* `<meta name="color-scheme">`, creating the element when the document has
|
|
5
6
|
* none, before the browser paints, and follows every change. It renders
|
|
6
|
-
* nothing; place it once, where the Theme that owns the page is
|
|
7
|
+
* nothing in place; place it once, where the Theme that owns the page is
|
|
8
|
+
* provided.
|
|
7
9
|
*
|
|
8
10
|
* A page embedded in a frame needs its color scheme to match the frame's, or
|
|
9
11
|
* the browser paints the frame opaque instead of letting what is behind it
|
|
10
12
|
* show.
|
|
13
|
+
*
|
|
14
|
+
* A change of Theme takes the page there in one step; the Desktop around the
|
|
15
|
+
* page carries the movement from one Theme to the other.
|
|
11
16
|
*/
|
|
12
|
-
export declare function DocumentTheme():
|
|
17
|
+
export declare function DocumentTheme(): ReactElement;
|
package/dist/document-theme.js
CHANGED
|
@@ -1,18 +1,53 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect, useRef } from "react";
|
|
2
3
|
import { usePreferences } from "./foundation/visual.js";
|
|
4
|
+
/** Marks the document while its Theme changes, so what it paints changes in one step. */
|
|
5
|
+
const changing = "data-phreshos-theme-change";
|
|
6
|
+
/**
|
|
7
|
+
* While the Theme changes, nothing in the document eases toward the new colors: the Desktop that
|
|
8
|
+
* holds the page moves from one Theme to the other as a whole, and a page easing on its own would
|
|
9
|
+
* keep changing after the Desktop has finished. Pseudo-elements carry Surface paint, so they
|
|
10
|
+
* change at once too.
|
|
11
|
+
*/
|
|
12
|
+
const instantThemeRule = `
|
|
13
|
+
html[${changing}] *,
|
|
14
|
+
html[${changing}] *::before,
|
|
15
|
+
html[${changing}] *::after {
|
|
16
|
+
transition-delay: 0s !important;
|
|
17
|
+
transition-duration: 0s !important;
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
3
20
|
/**
|
|
4
21
|
* Keeps the document's color scheme on the Theme of the nearest UIProvider,
|
|
5
22
|
* or on the browser's without one. It writes the Theme into the document's
|
|
6
23
|
* `<meta name="color-scheme">`, creating the element when the document has
|
|
7
24
|
* none, before the browser paints, and follows every change. It renders
|
|
8
|
-
* nothing; place it once, where the Theme that owns the page is
|
|
25
|
+
* nothing in place; place it once, where the Theme that owns the page is
|
|
26
|
+
* provided.
|
|
9
27
|
*
|
|
10
28
|
* A page embedded in a frame needs its color scheme to match the frame's, or
|
|
11
29
|
* the browser paints the frame opaque instead of letting what is behind it
|
|
12
30
|
* show.
|
|
31
|
+
*
|
|
32
|
+
* A change of Theme takes the page there in one step; the Desktop around the
|
|
33
|
+
* page carries the movement from one Theme to the other.
|
|
13
34
|
*/
|
|
14
35
|
export function DocumentTheme() {
|
|
15
36
|
const { theme } = usePreferences();
|
|
37
|
+
const shown = useRef(theme);
|
|
38
|
+
useLayoutEffect(() => {
|
|
39
|
+
if (shown.current === theme)
|
|
40
|
+
return;
|
|
41
|
+
shown.current = theme;
|
|
42
|
+
// Set before the browser paints the new colors, and kept until they have been painted.
|
|
43
|
+
const root = document.documentElement;
|
|
44
|
+
root.setAttribute(changing, "");
|
|
45
|
+
let frame = requestAnimationFrame(() => { frame = requestAnimationFrame(() => root.removeAttribute(changing)); });
|
|
46
|
+
return () => {
|
|
47
|
+
cancelAnimationFrame(frame);
|
|
48
|
+
root.removeAttribute(changing);
|
|
49
|
+
};
|
|
50
|
+
}, [theme]);
|
|
16
51
|
useLayoutEffect(() => {
|
|
17
52
|
const existing = document.head.querySelector('meta[name="color-scheme" i]');
|
|
18
53
|
const meta = existing ?? document.head.appendChild(Object.assign(document.createElement("meta"), { name: "color-scheme" }));
|
|
@@ -25,5 +60,5 @@ export function DocumentTheme() {
|
|
|
25
60
|
meta.remove();
|
|
26
61
|
};
|
|
27
62
|
}, [theme]);
|
|
28
|
-
return
|
|
63
|
+
return _jsx("style", { href: "phreshos-document-theme", precedence: "phreshos", children: instantThemeRule });
|
|
29
64
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dragging entries out of a collection and dropping onto it, for Table, GridList, and Tree: pass what
|
|
3
|
+
* `useDragAndDrop` returns as the collection's `dragAndDropHooks`. Drags are the browser's own, so
|
|
4
|
+
* they reach other frames and other applications, and files dragged in from the machine arrive as
|
|
5
|
+
* drop items of kind `file` or `directory`. What a drag would drop into shows as chosen.
|
|
6
|
+
*/
|
|
7
|
+
export { useDragAndDrop, type DragAndDropHooks, type DragAndDropOptions, type DropItem, type DropOperation, type DirectoryDropItem, type FileDropItem, type TextDropItem } from "react-aria-components";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dragging entries out of a collection and dropping onto it, for Table, GridList, and Tree: pass what
|
|
3
|
+
* `useDragAndDrop` returns as the collection's `dragAndDropHooks`. Drags are the browser's own, so
|
|
4
|
+
* they reach other frames and other applications, and files dragged in from the machine arrive as
|
|
5
|
+
* drop items of kind `file` or `directory`. What a drag would drop into shows as chosen.
|
|
6
|
+
*/
|
|
7
|
+
export { useDragAndDrop } from "react-aria-components";
|
package/dist/dropdown-menu.d.ts
CHANGED
|
@@ -17,6 +17,9 @@ export declare const DropdownMenu: typeof DropdownMenuRoot & {
|
|
|
17
17
|
Section: <T extends object = object>(properties: import("./menu.js").MenuSectionProps<T>) => import("react").ReactElement | null;
|
|
18
18
|
Header: import("react").ForwardRefExoticComponent<import("react-aria-components").HeaderProps & import("react").RefAttributes<HTMLElement>>;
|
|
19
19
|
Separator: import("react").ForwardRefExoticComponent<import("react-aria-components").SeparatorProps & import("react").RefAttributes<HTMLElement>>;
|
|
20
|
+
Submenu: (({ children, delay }: import("./menu.js").MenuSubmenuProps) => import("react").JSX.Element) & {
|
|
21
|
+
Content: import("react").ForwardRefExoticComponent<import("./menu.js").MenuSubmenuContentProps & import("react").RefAttributes<HTMLElement>>;
|
|
22
|
+
};
|
|
20
23
|
};
|
|
21
24
|
};
|
|
22
25
|
export type DropdownMenuProps = ComponentProps<typeof DropdownMenuRoot>;
|
package/dist/grid-list.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import { createContext, forwardRef, useContext, useMemo } from "react";
|
|
3
3
|
import { GridList as AriaGridList, GridListHeader as AriaGridListHeader, GridListItem as AriaGridListItem, GridListSection as AriaGridListSection } from "react-aria-components";
|
|
4
4
|
import { useControlMetrics } from "./control/control.js";
|
|
5
|
-
import { itemSurface, SelectionMark } from "./control/item.js";
|
|
5
|
+
import { dropTargetOutline, itemSurface, SelectionMark } from "./control/item.js";
|
|
6
6
|
import { ariaSelection } from "./control/selection.js";
|
|
7
7
|
import { surfaceRender } from "./control/surface-render.js";
|
|
8
8
|
import { AriaDirectionBoundary } from "./foundation/aria-direction.js";
|
|
@@ -17,7 +17,7 @@ const GridListRootImplementation = forwardRef(function GridList(properties, ref)
|
|
|
17
17
|
const columns = `repeat(auto-fill, minmax(min(${typeof width === "number" ? `${width}px` : width}, 100%), 1fr))`;
|
|
18
18
|
const context = useMemo(() => ({ color, metrics, columns }), [color, metrics, columns]);
|
|
19
19
|
const direction = resolveDirection(native.dir, useDirection());
|
|
20
|
-
return _jsx(GridListStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaGridList, { ...native, ...ariaSelection(properties, "single"), ref: ref, dir: direction, layout: "grid", className: className, style: {
|
|
20
|
+
return _jsx(GridListStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaGridList, { ...native, ...ariaSelection(properties, "single"), ref: ref, dir: direction, layout: "grid", className: className, style: state => ({
|
|
21
21
|
display: "grid",
|
|
22
22
|
gridTemplateColumns: columns,
|
|
23
23
|
gap: metrics.gap * 2,
|
|
@@ -27,8 +27,10 @@ const GridListRootImplementation = forwardRef(function GridList(properties, ref)
|
|
|
27
27
|
outline: "none",
|
|
28
28
|
fontFamily: "inherit",
|
|
29
29
|
fontSize: metrics.fontSize,
|
|
30
|
+
borderRadius: metrics.radius,
|
|
31
|
+
...dropTargetOutline(metrics, state.isDropTarget),
|
|
30
32
|
...style
|
|
31
|
-
} }) }) });
|
|
33
|
+
}) }) }) });
|
|
32
34
|
});
|
|
33
35
|
/** One card. It holds whatever it is given, and shows a check in its corner when selected. */
|
|
34
36
|
const GridListItemImplementation = forwardRef(function GridListItem({ children, className, color, disabled = false, style, textValue, ...properties }, ref) {
|
|
@@ -37,7 +39,8 @@ const GridListItemImplementation = forwardRef(function GridListItem({ children,
|
|
|
37
39
|
const { metrics } = inherited;
|
|
38
40
|
return _jsx(AriaGridListItem, { ...properties, ref: ref, textValue: textValue ?? (typeof children === "string" ? children : undefined), className: className, isDisabled: disabled, render: surfaceRender("div", state => ({
|
|
39
41
|
...itemSurface(metrics.visual, itemColor, {
|
|
40
|
-
|
|
42
|
+
// What a drag would drop into shows as chosen.
|
|
43
|
+
selected: state.isSelected || state.isDropTarget === true,
|
|
41
44
|
hovered: state.isHovered,
|
|
42
45
|
pressed: state.isPressed,
|
|
43
46
|
focusVisible: state.isFocusVisible,
|
|
@@ -45,7 +48,7 @@ const GridListItemImplementation = forwardRef(function GridListItem({ children,
|
|
|
45
48
|
}, metrics.radius),
|
|
46
49
|
// Unlike a list row, a card is a whole Surface: flat, in the default color at rest, in its
|
|
47
50
|
// selection color once selected, with the default material in both.
|
|
48
|
-
...(state.isSelected ? {} : { color: "default" }),
|
|
51
|
+
...(state.isSelected || state.isDropTarget === true ? {} : { color: "default" }),
|
|
49
52
|
material: undefined
|
|
50
53
|
})), style: {
|
|
51
54
|
position: "relative",
|
package/dist/loading.d.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import type { CSSProperties } from "react";
|
|
2
2
|
import { type ReadinessProps } from "./readiness.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
export interface LoadingProps extends Pick<ReadinessProps, "children" | "delay">, SurfaceOwnProps {
|
|
3
|
+
export interface LoadingProps extends Pick<ReadinessProps, "children" | "delay"> {
|
|
4
|
+
/** Class of the layer that shows the loading. */
|
|
6
5
|
readonly className?: string;
|
|
6
|
+
/** Style of the layer that shows the loading, such as where it stands. */
|
|
7
7
|
readonly style?: CSSProperties;
|
|
8
8
|
/** Lists every requirement with a message, each with its own progress, instead of one message. */
|
|
9
9
|
readonly steps?: boolean;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* A Readiness boundary drawn the way the System draws loading:
|
|
13
|
-
*
|
|
14
|
-
* waiting requirement, or every step
|
|
15
|
-
*
|
|
12
|
+
* A Readiness boundary drawn the way the System draws loading: the waiting
|
|
13
|
+
* interface is hidden, not covered, and a Spinner with the message of the
|
|
14
|
+
* first waiting requirement, or every step, stands where it will be. Nothing
|
|
15
|
+
* is painted behind the Spinner, so the Surface the interface sits on shows
|
|
16
|
+
* through. A requirement's detail is its message when it is a string; other
|
|
17
|
+
* requirements are waited for without being shown.
|
|
16
18
|
*
|
|
17
|
-
* The
|
|
18
|
-
* fades out with the Appearance transaction
|
|
19
|
+
* The loading fills the nearest positioned ancestor. It appears at once; when
|
|
20
|
+
* everything is ready it fades out with the Appearance transaction and the
|
|
21
|
+
* interface appears whole at once.
|
|
19
22
|
*/
|
|
20
|
-
export declare function Loading({ children, delay, steps,
|
|
23
|
+
export declare function Loading({ children, delay, steps, className, style }: LoadingProps): import("react").JSX.Element;
|
package/dist/loading.js
CHANGED
|
@@ -3,23 +3,34 @@ import { useEffect, useRef, useState } from "react";
|
|
|
3
3
|
import { Check } from "lucide-react";
|
|
4
4
|
import { useControlMetrics } from "./control/control.js";
|
|
5
5
|
import { iconProps } from "./control/icon.js";
|
|
6
|
-
import { Readiness } from "./readiness.js";
|
|
6
|
+
import { Readiness, useReadiness } from "./readiness.js";
|
|
7
7
|
import { Spinner, spinnerDiameter } from "./spinner.js";
|
|
8
|
-
import { Surface } from "./surface/surface.js";
|
|
9
8
|
import { Text } from "./typography.js";
|
|
10
9
|
/**
|
|
11
|
-
* A Readiness boundary drawn the way the System draws loading:
|
|
12
|
-
*
|
|
13
|
-
* waiting requirement, or every step
|
|
14
|
-
*
|
|
10
|
+
* A Readiness boundary drawn the way the System draws loading: the waiting
|
|
11
|
+
* interface is hidden, not covered, and a Spinner with the message of the
|
|
12
|
+
* first waiting requirement, or every step, stands where it will be. Nothing
|
|
13
|
+
* is painted behind the Spinner, so the Surface the interface sits on shows
|
|
14
|
+
* through. A requirement's detail is its message when it is a string; other
|
|
15
|
+
* requirements are waited for without being shown.
|
|
15
16
|
*
|
|
16
|
-
* The
|
|
17
|
-
* fades out with the Appearance transaction
|
|
17
|
+
* The loading fills the nearest positioned ancestor. It appears at once; when
|
|
18
|
+
* everything is ready it fades out with the Appearance transaction and the
|
|
19
|
+
* interface appears whole at once.
|
|
18
20
|
*/
|
|
19
|
-
export function Loading({ children, delay, steps = false,
|
|
20
|
-
return _jsx(Readiness, { delay: delay, status: state => _jsx(
|
|
21
|
+
export function Loading({ children, delay, steps = false, className, style }) {
|
|
22
|
+
return _jsx(Readiness, { delay: delay, status: state => _jsx(LoadingStatus, { state: state, steps: steps, className: className, style: style }), children: _jsx(Hidden, { children: children }) });
|
|
21
23
|
}
|
|
22
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Hides the waiting interface while it keeps its layout, so it appears whole and in place. It
|
|
26
|
+
* draws no box of its own, so the interface stays a direct part of the layout around it; such a
|
|
27
|
+
* box cannot fade, which is why the interface appears at once.
|
|
28
|
+
*/
|
|
29
|
+
function Hidden({ children }) {
|
|
30
|
+
const { ready } = useReadiness();
|
|
31
|
+
return _jsx("div", { "data-loading-content": "", style: { display: "contents", visibility: ready ? undefined : "hidden" }, children: children });
|
|
32
|
+
}
|
|
33
|
+
function LoadingStatus({ state, steps, className, style }) {
|
|
23
34
|
const metrics = useControlMetrics();
|
|
24
35
|
const { duration, easing } = metrics.visual;
|
|
25
36
|
const { ready } = state;
|
|
@@ -39,21 +50,19 @@ function LoadingCover({ state, steps, surface }) {
|
|
|
39
50
|
shown.current = state.requirements.flatMap(requirement => typeof requirement.detail === "string" ? [{ message: requirement.detail, ready: requirement.ready }] : []);
|
|
40
51
|
if (gone)
|
|
41
52
|
return null;
|
|
42
|
-
const
|
|
43
|
-
const cover = {
|
|
53
|
+
const layer = {
|
|
44
54
|
position: "absolute",
|
|
45
55
|
inset: 0,
|
|
46
56
|
display: "grid",
|
|
47
57
|
placeItems: "center",
|
|
48
58
|
opacity: ready ? 0 : 1,
|
|
49
|
-
// New waiting
|
|
59
|
+
// New waiting shows at once; only readiness fades.
|
|
50
60
|
transition: ready ? `opacity ${duration}ms ${easing}` : "none",
|
|
51
61
|
pointerEvents: ready ? "none" : undefined,
|
|
52
62
|
...style
|
|
53
63
|
};
|
|
54
64
|
const progress = steps ? _jsx(StepList, { steps: shown.current }) : _jsx(Message, { message: shown.current.find(step => !step.ready)?.message });
|
|
55
|
-
|
|
56
|
-
return _jsx(Surface, { ...paint, depth: depth, radius: radius, role: "status", "aria-hidden": ready || undefined, style: cover, children: progress });
|
|
65
|
+
return _jsx("div", { className: className, role: "status", "aria-hidden": ready || undefined, style: layer, children: progress });
|
|
57
66
|
}
|
|
58
67
|
function Message({ message }) {
|
|
59
68
|
const metrics = useControlMetrics();
|
package/dist/main.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export { ListBox, type ListBoxProps, type ListBoxSingleSelectionProps, type List
|
|
|
36
36
|
export { GridList, type GridListProps, type GridListNoSelectionProps, type GridListSingleSelectionProps, type GridListMultipleSelectionProps, type GridListMultipleValue, type GridListItemProps, type GridListSectionProps, type GridListHeaderProps } from "./grid-list.js";
|
|
37
37
|
export { Tabs, type TabsProps, type TabsListProps, type TabsTabProps, type TabsPanelsProps, type TabsPanelProps } from "./tabs.js";
|
|
38
38
|
export { Table, type TableProps, type TableNoSelectionProps, type TableSingleSelectionProps, type TableMultipleSelectionProps, type TableMultipleValue, type TableSort, type TableSortDirection, type TableHeaderProps, type TableColumnProps, type TableBodyProps, type TableRowProps, type TableCellProps } from "./table.js";
|
|
39
|
-
export { Tree, type TreeProps, type TreeNoSelectionProps, type TreeSingleSelectionProps, type TreeMultipleSelectionProps, type TreeMultipleValue, type TreeItemProps, type TreeContentProps, type TreeCollectionProps } from "./tree.js";
|
|
39
|
+
export { Tree, type TreeProps, type TreeNoSelectionProps, type TreeSingleSelectionProps, type TreeMultipleSelectionProps, type TreeMultipleValue, type TreeItemProps, type TreeContentProps, type TreeCollectionProps, type TreeLoadMoreProps } from "./tree.js";
|
|
40
40
|
export { Slider, type SliderProps } from "./slider.js";
|
|
41
41
|
export { ProgressBar, type ProgressBarProps } from "./progress-bar.js";
|
|
42
42
|
export { Spinner, type SpinnerProps } from "./spinner.js";
|
|
@@ -53,13 +53,14 @@ export { Avatar, type AvatarProps } from "./avatar.js";
|
|
|
53
53
|
export { TagGroup, type TagGroupProps, type TagGroupTagProps } from "./tag-group.js";
|
|
54
54
|
export { Skeleton, type SkeletonProps } from "./skeleton.js";
|
|
55
55
|
export { Snippet, copyText, type SnippetProps } from "./snippet.js";
|
|
56
|
+
export { useDragAndDrop, type DragAndDropHooks, type DragAndDropOptions, type DropItem, type DropOperation, type DirectoryDropItem, type FileDropItem, type TextDropItem } from "./drag-and-drop.js";
|
|
56
57
|
export { toast, ToastRegion, type ToastContent, type ToastOptions, type ToastRegionProps } from "./toast.js";
|
|
57
58
|
export { Readiness, useReadiness, useRequirement, type ReadinessProps, type ReadinessState, type Requirement } from "./readiness.js";
|
|
58
59
|
export { Loading, type LoadingProps } from "./loading.js";
|
|
59
60
|
export { FileTrigger, type FileTriggerProps } from "./file-trigger.js";
|
|
60
61
|
export { DropZone, type DropZoneProps } from "./drop-zone.js";
|
|
61
62
|
export { Fieldset, type FieldsetProps } from "./fieldset.js";
|
|
62
|
-
export { AppLayout, type AppLayoutProps, type AppLayoutRegionProps, type AppLayoutTitleProps } from "./app-layout.js";
|
|
63
|
+
export { AppLayout, type AppLayoutContentProps, type AppLayoutProps, type AppLayoutRegionProps, type AppLayoutSidebarProps, type AppLayoutTitleProps } from "./app-layout.js";
|
|
63
64
|
export { ColorSwatch, type ColorSwatchProps } from "./color-swatch.js";
|
|
64
65
|
export { ColorSwatchPicker, type ColorSwatchPickerProps, type ColorSwatchPickerItemProps } from "./color-swatch-picker.js";
|
|
65
66
|
export { ColorSlider, type ColorSliderProps } from "./color-slider.js";
|
|
@@ -71,7 +72,7 @@ export { Toolbar, type ToolbarProps, type ToolbarGroupProps, type ToolbarSeparat
|
|
|
71
72
|
export { Disclosure, type DisclosureProps, type DisclosureTriggerProps, type DisclosureContentProps } from "./disclosure.js";
|
|
72
73
|
export { Accordion, type AccordionProps, type AccordionSingleExpansionProps, type AccordionMultipleExpansionProps, type AccordionItemProps } from "./accordion.js";
|
|
73
74
|
export { Popover, type PopoverProps, type PopoverTriggerProps, type PopoverContentProps, type PopoverDialogProps, type PopoverTitleProps, type PopoverCloseProps } from "./popover.js";
|
|
74
|
-
export { Menu, type MenuProps, type MenuNoSelectionProps, type MenuSingleSelectionProps, type MenuMultipleSelectionProps, type MenuMultipleValue, type MenuItemProps, type MenuSectionProps, type MenuHeaderProps, type MenuSeparatorProps } from "./menu.js";
|
|
75
|
+
export { Menu, type MenuProps, type MenuNoSelectionProps, type MenuSingleSelectionProps, type MenuMultipleSelectionProps, type MenuMultipleValue, type MenuItemProps, type MenuSectionProps, type MenuHeaderProps, type MenuSeparatorProps, type MenuSubmenuProps, type MenuSubmenuContentProps } from "./menu.js";
|
|
75
76
|
export { DropdownMenu, type DropdownMenuProps, type DropdownMenuTriggerProps } from "./dropdown-menu.js";
|
|
76
77
|
export { ContextMenu, type ContextMenuProps, type ContextMenuTriggerProps, type ContextMenuContentProps } from "./context-menu.js";
|
|
77
78
|
export { Dialog, type DialogProps, type DialogTriggerProps, type DialogBackdropProps, type DialogBackdropVariant, type DialogContentProps, type DialogHeaderProps, type DialogTitleProps, type DialogDescriptionProps, type DialogBodyProps, type DialogFooterProps, type DialogCloseProps } from "./dialog.js";
|
package/dist/main.js
CHANGED
|
@@ -52,6 +52,7 @@ export { Avatar } from "./avatar.js";
|
|
|
52
52
|
export { TagGroup } from "./tag-group.js";
|
|
53
53
|
export { Skeleton } from "./skeleton.js";
|
|
54
54
|
export { Snippet, copyText } from "./snippet.js";
|
|
55
|
+
export { useDragAndDrop } from "./drag-and-drop.js";
|
|
55
56
|
export { toast, ToastRegion } from "./toast.js";
|
|
56
57
|
export { Readiness, useReadiness, useRequirement } from "./readiness.js";
|
|
57
58
|
export { Loading } from "./loading.js";
|
package/dist/menu.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { type MultipleSelectionProps, type MultipleStringSelection, type NoSelec
|
|
|
4
4
|
import type { Color } from "./foundation/color.js";
|
|
5
5
|
import type { RadiusProps } from "./foundation/radius.js";
|
|
6
6
|
import type { ScaleLevel } from "./foundation/scale.js";
|
|
7
|
+
import { type PopoverContentProps } from "./popover.js";
|
|
7
8
|
type MenuRootBaseProps<T extends object> = Omit<AriaMenuProps<T>, "className" | "defaultSelectedKeys" | "disabledKeys" | "onAction" | "onSelectionChange" | "selectedKeys" | "selectionMode" | "style" | "shouldFocusWrap" | "shouldCloseOnSelect"> & RadiusProps & Readonly<{
|
|
8
9
|
className?: string;
|
|
9
10
|
/** Whether activating an Item closes the menu. Defaults to `true`. */
|
|
@@ -38,12 +39,24 @@ export type MenuItemComponent = <T = object>(properties: MenuItemProps<T> & RefA
|
|
|
38
39
|
export type MenuSectionProps<T extends object = object> = Omit<AriaMenuSectionProps<T>, "defaultSelectedKeys" | "selectedKeys" | "onSelectionChange" | "selectionMode" | "disallowEmptySelection" | "shouldCloseOnSelect">;
|
|
39
40
|
export type MenuHeaderProps = AriaHeaderProps;
|
|
40
41
|
export type MenuSeparatorProps = AriaSeparatorProps;
|
|
42
|
+
export interface MenuSubmenuProps {
|
|
43
|
+
/** The Item that opens the Submenu, then its `Menu.Submenu.Content`. */
|
|
44
|
+
readonly children: [ReactElement, ReactElement];
|
|
45
|
+
/** Milliseconds the pointer rests on the Item before the Submenu opens. */
|
|
46
|
+
readonly delay?: number;
|
|
47
|
+
}
|
|
48
|
+
/** An Item that opens another Menu beside it. */
|
|
49
|
+
declare function MenuSubmenu({ children, delay }: MenuSubmenuProps): import("react").JSX.Element;
|
|
50
|
+
export type MenuSubmenuContentProps = Omit<PopoverContentProps, "placement">;
|
|
41
51
|
/** A keyboard-navigable collection of commands or selectable options. */
|
|
42
52
|
export declare const Menu: MenuRootComponent & {
|
|
43
53
|
Item: MenuItemComponent;
|
|
44
54
|
Section: <T extends object = object>(properties: MenuSectionProps<T>) => ReactElement | null;
|
|
45
55
|
Header: import("react").ForwardRefExoticComponent<AriaHeaderProps & RefAttributes<HTMLElement>>;
|
|
46
56
|
Separator: import("react").ForwardRefExoticComponent<AriaSeparatorProps & RefAttributes<HTMLElement>>;
|
|
57
|
+
Submenu: typeof MenuSubmenu & {
|
|
58
|
+
Content: import("react").ForwardRefExoticComponent<MenuSubmenuContentProps & RefAttributes<HTMLElement>>;
|
|
59
|
+
};
|
|
47
60
|
};
|
|
48
61
|
export type MenuProps<T extends object = object> = MenuRootProps<T>;
|
|
49
62
|
export {};
|
package/dist/menu.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, forwardRef, useContext, useMemo } from "react";
|
|
3
|
-
import { Header as AriaHeader, Menu as AriaMenu, MenuItem as AriaMenuItem, MenuSection as AriaMenuSection, Separator as AriaSeparator } from "react-aria-components";
|
|
4
|
-
import {
|
|
3
|
+
import { Header as AriaHeader, Menu as AriaMenu, MenuItem as AriaMenuItem, MenuSection as AriaMenuSection, Separator as AriaSeparator, SubmenuTrigger as AriaSubmenuTrigger } from "react-aria-components";
|
|
4
|
+
import { ChevronRight } from "lucide-react";
|
|
5
|
+
import { controlOpacity, useControlMetrics } from "./control/control.js";
|
|
5
6
|
import { separatorColor } from "./control/field.js";
|
|
6
7
|
import { itemStyle, itemSurface, SelectionMark } from "./control/item.js";
|
|
7
8
|
import { ariaSelection, stringKey } from "./control/selection.js";
|
|
8
9
|
import { surfaceRender } from "./control/surface-render.js";
|
|
9
10
|
import { collectionHeaderStyle } from "./list-box.js";
|
|
11
|
+
import { resolveDirection, useDirection } from "./foundation/direction.js";
|
|
12
|
+
import { iconProps } from "./control/icon.js";
|
|
13
|
+
import { MenuContent } from "./popover.js";
|
|
10
14
|
const MenuStyleContext = createContext(null);
|
|
11
15
|
const MenuRootImplementation = forwardRef(function Menu(properties, ref) {
|
|
12
16
|
const { className, closeOnSelect, color = "primary", defaultValue: _defaultValue, focusWrap, onAction, onChange: _onChange, radius, selectionMode = "none", size, style, value: _value, ...native } = properties;
|
|
@@ -30,6 +34,7 @@ const MenuRootImplementation = forwardRef(function Menu(properties, ref) {
|
|
|
30
34
|
const MenuItemImplementation = forwardRef(function MenuItem({ children, className, closeOnSelect, color, disabled = false, style, textValue, ...properties }, ref) {
|
|
31
35
|
const { color: inherited, metrics, itemRadius, selecting } = useMenuStyle();
|
|
32
36
|
const itemColor = color ?? inherited;
|
|
37
|
+
const direction = resolveDirection(properties.dir, useDirection());
|
|
33
38
|
return _jsx(AriaMenuItem, { ...properties, shouldCloseOnSelect: closeOnSelect, ref: ref, textValue: textValue ?? (typeof children === "string" ? children : undefined), className: className, isDisabled: disabled, render: surfaceRender("div", state => itemSurface(metrics.visual, itemColor, {
|
|
34
39
|
selected: state.isSelected,
|
|
35
40
|
// Keyboard focus moves the highlight through a menu the way the pointer does;
|
|
@@ -38,7 +43,7 @@ const MenuItemImplementation = forwardRef(function MenuItem({ children, classNam
|
|
|
38
43
|
pressed: state.isPressed,
|
|
39
44
|
focusVisible: false,
|
|
40
45
|
disabled: state.isDisabled
|
|
41
|
-
}, itemRadius)), style: { ...itemStyle(metrics, disabled), ...style }, children: state => _jsxs(_Fragment, { children: [typeof children === "function" ? children(state) : children, selecting && _jsx(SelectionMark, { visible: state.isSelected })] }) });
|
|
46
|
+
}, itemRadius)), style: { ...itemStyle(metrics, disabled), ...style }, children: state => _jsxs(_Fragment, { children: [typeof children === "function" ? children(state) : children, selecting && _jsx(SelectionMark, { visible: state.isSelected }), state.hasSubmenu && _jsx(ChevronRight, { ...iconProps(14), style: { marginInlineStart: "auto", opacity: controlOpacity.secondary, rotate: direction === "rtl" ? "180deg" : undefined } })] }) });
|
|
42
47
|
});
|
|
43
48
|
const MenuHeader = forwardRef(function MenuHeader({ style, ...properties }, ref) {
|
|
44
49
|
const { metrics } = useMenuStyle();
|
|
@@ -55,6 +60,14 @@ const MenuSeparator = forwardRef(function MenuSeparator({ style, ...properties }
|
|
|
55
60
|
...style
|
|
56
61
|
} });
|
|
57
62
|
});
|
|
63
|
+
/** An Item that opens another Menu beside it. */
|
|
64
|
+
function MenuSubmenu({ children, delay }) {
|
|
65
|
+
return _jsx(AriaSubmenuTrigger, { delay: delay, children: children });
|
|
66
|
+
}
|
|
67
|
+
/** The Submenu's own Menu, opening beside its Item toward the reading direction's end. */
|
|
68
|
+
const MenuSubmenuContent = forwardRef(function MenuSubmenuContent(properties, ref) {
|
|
69
|
+
return _jsx(MenuContent, { ...properties, ref: ref, placement: "end top" });
|
|
70
|
+
});
|
|
58
71
|
function useMenuStyle() {
|
|
59
72
|
const context = useContext(MenuStyleContext);
|
|
60
73
|
if (context == null)
|
|
@@ -66,5 +79,6 @@ export const Menu = Object.assign(MenuRootImplementation, {
|
|
|
66
79
|
Item: MenuItemImplementation,
|
|
67
80
|
Section: AriaMenuSection,
|
|
68
81
|
Header: MenuHeader,
|
|
69
|
-
Separator: MenuSeparator
|
|
82
|
+
Separator: MenuSeparator,
|
|
83
|
+
Submenu: Object.assign(MenuSubmenu, { Content: MenuSubmenuContent })
|
|
70
84
|
});
|
package/dist/table.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createContext, forwardRef, useContext, useMemo } from "react";
|
|
|
3
3
|
import { Cell as AriaCell, Column as AriaColumn, Row as AriaRow, Table as AriaTable, TableBody as AriaTableBody, TableHeader as AriaTableHeader } from "react-aria-components";
|
|
4
4
|
import { controlFontWeight, controlOpacity, transition, useControlMetrics, secondaryFontSize } from "./control/control.js";
|
|
5
5
|
import { separatorColor } from "./control/field.js";
|
|
6
|
-
import { itemPaint } from "./control/item.js";
|
|
6
|
+
import { dropTargetOutline, itemPaint } from "./control/item.js";
|
|
7
7
|
import { ariaSelection, stringKey } from "./control/selection.js";
|
|
8
8
|
import { AriaDirectionBoundary } from "./foundation/aria-direction.js";
|
|
9
9
|
import { colorOpacity } from "./foundation/color.js";
|
|
@@ -18,7 +18,7 @@ const TableRoot = forwardRef(function Table(properties, ref) {
|
|
|
18
18
|
const metrics = useControlMetrics(size, radius);
|
|
19
19
|
const context = useMemo(() => ({ color, interactive: selectionMode !== "none" || onAction != null, metrics }), [color, metrics, onAction, selectionMode]);
|
|
20
20
|
const direction = resolveDirection(native.dir, useDirection());
|
|
21
|
-
return _jsx(TableStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaTable, { ...native, shouldSelectOnPressUp: selectOnPressUp, ...ariaSelection(properties, "none"), ...(sort === undefined ? {} : { sortDescriptor: sort }), ref: ref, dir: direction, className: className, onRowAction: onAction == null ? undefined : key => onAction(stringKey(key)), onSortChange: onSortChange == null ? undefined : descriptor => onSortChange(tableSort(descriptor)), style: {
|
|
21
|
+
return _jsx(TableStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaTable, { ...native, shouldSelectOnPressUp: selectOnPressUp, ...ariaSelection(properties, "none"), ...(sort === undefined ? {} : { sortDescriptor: sort }), ref: ref, dir: direction, className: className, onRowAction: onAction == null ? undefined : key => onAction(stringKey(key)), onSortChange: onSortChange == null ? undefined : descriptor => onSortChange(tableSort(descriptor)), style: state => ({
|
|
22
22
|
width: "100%",
|
|
23
23
|
minWidth: "max-content",
|
|
24
24
|
borderCollapse: "separate",
|
|
@@ -29,8 +29,9 @@ const TableRoot = forwardRef(function Table(properties, ref) {
|
|
|
29
29
|
overflow: "hidden",
|
|
30
30
|
fontFamily: "inherit",
|
|
31
31
|
fontSize: metrics.fontSize,
|
|
32
|
+
...dropTargetOutline(metrics, state.isDropTarget),
|
|
32
33
|
...style
|
|
33
|
-
} }) }) });
|
|
34
|
+
}) }) }) });
|
|
34
35
|
});
|
|
35
36
|
function tableSort(descriptor) {
|
|
36
37
|
return { column: stringKey(descriptor.column), direction: descriptor.direction };
|
|
@@ -68,7 +69,8 @@ const TableRowImplementation = forwardRef(function TableRow({ className, disable
|
|
|
68
69
|
return _jsx(AriaRow, { ...properties, ref: ref, className: state => dimmedClass(state.isDisabled, className ?? state.defaultClassName) ?? "", isDisabled: disabled, onAction: onAction, style: state => ({
|
|
69
70
|
...transition(metrics.visual, "background-color, color, outline-color"),
|
|
70
71
|
...itemPaint(metrics.visual, color, {
|
|
71
|
-
|
|
72
|
+
// What a drag would drop into shows as chosen.
|
|
73
|
+
selected: state.isSelected || state.isDropTarget === true,
|
|
72
74
|
hovered: responds && state.isHovered,
|
|
73
75
|
pressed: responds && state.isPressed,
|
|
74
76
|
focusVisible: false,
|
package/dist/tree.d.ts
CHANGED
|
@@ -41,11 +41,21 @@ export interface TreeContentProps extends AriaTreeItemContentProps {
|
|
|
41
41
|
readonly children: AriaTreeItemContentProps["children"];
|
|
42
42
|
}
|
|
43
43
|
export type TreeCollectionProps<T extends object = object> = AriaCollectionProps<T>;
|
|
44
|
+
export type TreeLoadMoreProps = Readonly<{
|
|
45
|
+
/** Asks for more Items once the end of the list comes near while scrolling. */
|
|
46
|
+
onLoadMore: () => void;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* The end of a list shown in parts, such as a long folder: when scrolling brings it near, the
|
|
50
|
+
* list is asked for more. It is placed after the Items it follows, at their level, and draws nothing.
|
|
51
|
+
*/
|
|
52
|
+
declare function TreeLoadMore({ onLoadMore }: TreeLoadMoreProps): import("react").JSX.Element;
|
|
44
53
|
/** Hierarchical navigation with independently controlled expansion, selection, and actions. */
|
|
45
54
|
export declare const Tree: TreeRootComponent & {
|
|
46
55
|
Item: TreeItemComponent;
|
|
47
56
|
Content: import("react").ForwardRefExoticComponent<TreeContentProps & RefAttributes<Element>>;
|
|
48
57
|
Collection: typeof AriaCollection;
|
|
58
|
+
LoadMore: typeof TreeLoadMore;
|
|
49
59
|
};
|
|
50
60
|
export type TreeProps<T extends object = object> = TreeRootProps<T>;
|
|
51
61
|
export {};
|
package/dist/tree.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, forwardRef, useContext, useMemo } from "react";
|
|
3
|
-
import { Button as AriaButton, Collection as AriaCollection, Tree as AriaTree, TreeItem as AriaTreeItem, TreeItemContent as AriaTreeItemContent } from "react-aria-components";
|
|
3
|
+
import { Button as AriaButton, Collection as AriaCollection, Tree as AriaTree, TreeItem as AriaTreeItem, TreeItemContent as AriaTreeItemContent, TreeLoadMoreItem as AriaTreeLoadMoreItem } from "react-aria-components";
|
|
4
4
|
import { proportionalRadius, transition, useControlMetrics } from "./control/control.js";
|
|
5
|
-
import { itemPaint, itemStyle } from "./control/item.js";
|
|
5
|
+
import { dropTargetOutline, itemPaint, itemStyle } from "./control/item.js";
|
|
6
6
|
import { ariaSelection, stringKey, stringKeys } from "./control/selection.js";
|
|
7
7
|
import { AriaDirectionBoundary } from "./foundation/aria-direction.js";
|
|
8
8
|
import { colorOpacity } from "./foundation/color.js";
|
|
@@ -18,7 +18,7 @@ const TreeRootImplementation = forwardRef(function Tree(properties, ref) {
|
|
|
18
18
|
const itemRadius = metrics.radius;
|
|
19
19
|
const direction = resolveDirection(native.dir, useDirection());
|
|
20
20
|
const context = useMemo(() => ({ color, direction, interactive: selectionMode !== "none" || onAction != null, metrics, itemRadius }), [color, direction, metrics, itemRadius, onAction, selectionMode]);
|
|
21
|
-
return _jsx(TreeStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaTree, { ...native, shouldSelectOnPressUp: selectOnPressUp, ...ariaSelection(properties, "none"), ...(expanded !== undefined ? { expandedKeys: new Set(expanded) } : {}), ...(defaultExpanded !== undefined ? { defaultExpandedKeys: new Set(defaultExpanded) } : {}), ...(onExpandedChange !== undefined ? { onExpandedChange: (keys) => onExpandedChange(stringKeys(keys)) } : {}), ref: ref, dir: direction, className: className, onAction: onAction == null ? undefined : key => onAction(stringKey(key)), style: {
|
|
21
|
+
return _jsx(TreeStyleContext.Provider, { value: context, children: _jsx(AriaDirectionBoundary, { direction: direction, children: _jsx(AriaTree, { ...native, shouldSelectOnPressUp: selectOnPressUp, ...ariaSelection(properties, "none"), ...(expanded !== undefined ? { expandedKeys: new Set(expanded) } : {}), ...(defaultExpanded !== undefined ? { defaultExpandedKeys: new Set(defaultExpanded) } : {}), ...(onExpandedChange !== undefined ? { onExpandedChange: (keys) => onExpandedChange(stringKeys(keys)) } : {}), ref: ref, dir: direction, className: className, onAction: onAction == null ? undefined : key => onAction(stringKey(key)), style: state => ({
|
|
22
22
|
display: "grid",
|
|
23
23
|
alignContent: "start",
|
|
24
24
|
gap: 2,
|
|
@@ -28,8 +28,10 @@ const TreeRootImplementation = forwardRef(function Tree(properties, ref) {
|
|
|
28
28
|
outline: "none",
|
|
29
29
|
fontFamily: "inherit",
|
|
30
30
|
fontSize: metrics.fontSize,
|
|
31
|
+
borderRadius: metrics.radius,
|
|
32
|
+
...dropTargetOutline(metrics, state.isDropTarget),
|
|
31
33
|
...style
|
|
32
|
-
} }) }) });
|
|
34
|
+
}) }) }) });
|
|
33
35
|
});
|
|
34
36
|
/** Tree entries use the collection Item treatment as their own paint. */
|
|
35
37
|
const TreeItemImplementation = forwardRef(function TreeItem({ arrowNavigation, className, disabled = false, expandable, onAction, style, ...properties }, ref) {
|
|
@@ -39,7 +41,8 @@ const TreeItemImplementation = forwardRef(function TreeItem({ arrowNavigation, c
|
|
|
39
41
|
return {
|
|
40
42
|
...itemStyle(metrics, state.isDisabled),
|
|
41
43
|
...itemPaint(metrics.visual, color, {
|
|
42
|
-
|
|
44
|
+
// What a drag would drop into shows as chosen.
|
|
45
|
+
selected: state.isSelected || state.isDropTarget === true,
|
|
43
46
|
hovered: responds && state.isHovered,
|
|
44
47
|
pressed: responds && state.isPressed,
|
|
45
48
|
focusVisible: false,
|
|
@@ -75,6 +78,13 @@ const TreeContent = forwardRef(function TreeContent({ children }, ref) {
|
|
|
75
78
|
}), children: _jsx(ChevronRight, { ...iconProps(14), style: { ...transition(metrics.visual, "rotate"), rotate: state.isExpanded ? "90deg" : direction === "rtl" ? "180deg" : "0deg" } }) })
|
|
76
79
|
: _jsx("span", { "aria-hidden": "true", style: { flex: `0 0 ${box}px` } }), _jsx("span", { style: { flex: "1 1 auto", minWidth: 0, display: "flex", alignItems: "center", gap: metrics.gap }, children: typeof children === "function" ? children(state) : children })] }) });
|
|
77
80
|
});
|
|
81
|
+
/**
|
|
82
|
+
* The end of a list shown in parts, such as a long folder: when scrolling brings it near, the
|
|
83
|
+
* list is asked for more. It is placed after the Items it follows, at their level, and draws nothing.
|
|
84
|
+
*/
|
|
85
|
+
function TreeLoadMore({ onLoadMore }) {
|
|
86
|
+
return _jsx(AriaTreeLoadMoreItem, { onLoadMore: onLoadMore });
|
|
87
|
+
}
|
|
78
88
|
function useTreeStyle() {
|
|
79
89
|
const context = useContext(TreeStyleContext);
|
|
80
90
|
if (context == null)
|
|
@@ -85,5 +95,6 @@ function useTreeStyle() {
|
|
|
85
95
|
export const Tree = Object.assign(TreeRootImplementation, {
|
|
86
96
|
Item: TreeItemImplementation,
|
|
87
97
|
Content: TreeContent,
|
|
88
|
-
Collection: AriaCollection
|
|
98
|
+
Collection: AriaCollection,
|
|
99
|
+
LoadMore: TreeLoadMore
|
|
89
100
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/react-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"description": "React components for coherent PhreshOS Program interfaces.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@base-ui/react": "^1.7.0",
|
|
59
59
|
"@internationalized/date": "^3.12.3",
|
|
60
|
-
"@phreshos/core": "^0.1.
|
|
60
|
+
"@phreshos/core": "^0.1.66",
|
|
61
61
|
"colorjs.io": "^0.7.1",
|
|
62
62
|
"lucide-react": "^1.48.0",
|
|
63
63
|
"react-aria": "^3.51.0",
|