@bysages/react 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/dist/components/ai/index.d.mts +2 -2
- package/dist/components/ai/index.mjs +10 -10
- package/dist/components/avatar/index.d.mts +4 -1
- package/dist/components/avatar/index.mjs +3 -2
- package/dist/components/bento/index.d.mts +26 -0
- package/dist/components/bento/index.mjs +41 -0
- package/dist/components/block-ui/index.d.mts +12 -0
- package/dist/components/block-ui/index.mjs +24 -0
- package/dist/components/browser/index.d.mts +23 -0
- package/dist/components/browser/index.mjs +70 -0
- package/dist/components/cascade-select/index.mjs +9 -3
- package/dist/components/data-view/index.d.mts +18 -0
- package/dist/components/data-view/index.mjs +64 -0
- package/dist/components/deferred-content/index.d.mts +16 -0
- package/dist/components/deferred-content/index.mjs +34 -0
- package/dist/components/descriptions/index.d.mts +13 -5
- package/dist/components/descriptions/index.mjs +20 -2
- package/dist/components/dock/index.d.mts +25 -0
- package/dist/components/dock/index.mjs +51 -0
- package/dist/components/dynamic-input/index.mjs +1 -1
- package/dist/components/form/index.mjs +1 -1
- package/dist/components/icon/index.d.mts +10 -5
- package/dist/components/icon/index.mjs +7 -7
- package/dist/components/input/index.d.mts +4 -1
- package/dist/components/input/index.mjs +1 -20
- package/dist/components/order-list/index.d.mts +21 -0
- package/dist/components/order-list/index.mjs +162 -0
- package/dist/components/result/index.d.mts +31 -0
- package/dist/components/result/index.mjs +59 -0
- package/dist/components/select/index.d.mts +2 -17
- package/dist/components/select/index.mjs +2 -18
- package/dist/components/spotlight/index.d.mts +12 -0
- package/dist/components/spotlight/index.mjs +33 -0
- package/dist/components/table/index.mjs +1 -1
- package/dist/components/tabs/index.d.mts +3 -1
- package/dist/components/tabs/index.mjs +3 -2
- package/dist/components/terminal/index.d.mts +17 -0
- package/dist/components/terminal/index.mjs +65 -0
- package/dist/components/timeline/index.d.mts +13 -11
- package/dist/components/timeline/index.mjs +11 -1
- package/dist/components/toolbar/index.d.mts +17 -0
- package/dist/components/toolbar/index.mjs +29 -0
- package/dist/components/transfer/index.mjs +1 -1
- package/dist/components/tree-select/index.mjs +1 -1
- package/dist/components/user/index.d.mts +20 -0
- package/dist/components/user/index.mjs +42 -0
- package/dist/components/virtual-list/index.d.mts +17 -0
- package/dist/components/virtual-list/index.mjs +52 -0
- package/dist/{index-DaAbbSz9.d.mts → index-CsfxYv6J.d.mts} +741 -3774
- package/dist/index-DFN9F5Zt.d.mts +42 -0
- package/dist/index.d.mts +16 -3
- package/dist/index.mjs +26 -13
- package/dist/input-2oezH-dY.mjs +58 -0
- package/dist/select-D1xiT1oJ.mjs +68 -0
- package/package.json +30 -9
package/README.md
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
> By Sages Elements for React —
|
|
7
|
+
> By Sages Elements for React — 140+ accessible component families, headless by construction, dressed by the paper-and-ink style layer. Ported from the Vue reference implementation, API for API.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- 🧩 **
|
|
11
|
+
- 🧩 **140+ families** — actions, forms, overlays, navigation, data, layout, an AI conversation family on ai-sdk formats, and a full generative vocabulary
|
|
12
12
|
- 🏛️ **Headless inside** — interaction, state, ARIA, and positioning come from proven headless state machines; wrappers add API narrowing and style injection, no DOM of their own
|
|
13
13
|
- 🎨 **Token-styled** — every visual value is a CSS custom property from `@bysages/core`; light/dark, accent pigments, contrast and density tiers are data, never hardcoded styles
|
|
14
14
|
- 📦 **Container-driven** — components respond to `@container`, not the viewport; the same component composes in a sidebar, a card, or a page
|
|
@@ -66,6 +66,20 @@ export function App() {
|
|
|
66
66
|
}
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
## Generative UI
|
|
70
|
+
|
|
71
|
+
Every family carries a generative face — a zod-typed catalog entry that
|
|
72
|
+
lives beside the component. The faces compose into a
|
|
73
|
+
[json-render](https://json-render.dev) catalog and render through the
|
|
74
|
+
same package:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { catalog } from "@bysages/react/generative";
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Point an AI SDK stream at the renderer and a prompt becomes real,
|
|
81
|
+
on-brand components — constrained to the families you registered.
|
|
82
|
+
|
|
69
83
|
## Documentation
|
|
70
84
|
|
|
71
85
|
The [documentation site](https://elements.bysages.com) carries every family with live demos and props tables.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { Ai, type DataUIPart, type FileUIPart, type ReasoningUIPart, type SourceDocumentUIPart, type SourceUrlUIPart, type StepStartUIPart, type TextUIPart, type ToolUIPart, type UIMessage, type UIMessagePart };
|
|
1
|
+
import { a as AiLoader, c as ReasoningUIPart, d as StepStartUIPart, f as TextUIPart, h as UIMessagePart, i as AiConversation, l as SourceDocumentUIPart, m as UIMessage, n as AiActions, o as DataUIPart, p as ToolUIPart, r as AiContent, s as FileUIPart, t as Ai, u as SourceUrlUIPart } from "../../index-CsfxYv6J.mjs";
|
|
2
|
+
export { Ai, AiActions, AiContent, AiConversation, AiLoader, type DataUIPart, type FileUIPart, type ReasoningUIPart, type SourceDocumentUIPart, type SourceUrlUIPart, type StepStartUIPart, type TextUIPart, type ToolUIPart, type UIMessage, type UIMessagePart };
|
|
@@ -29,27 +29,27 @@ function part(name, tag, extra = {}) {
|
|
|
29
29
|
}
|
|
30
30
|
/** The log itself: the column every stroke lands in, a landmark to
|
|
31
31
|
* screen readers. */
|
|
32
|
-
const
|
|
32
|
+
const AiConversation = part("Conversation", "div", {
|
|
33
33
|
role: "log",
|
|
34
34
|
"aria-label": "Conversation"
|
|
35
35
|
});
|
|
36
36
|
/** The bubble's inner measure — content that belongs to neither side
|
|
37
37
|
* specifically. */
|
|
38
|
-
const
|
|
38
|
+
const AiContent = part("Content", "div");
|
|
39
39
|
/** The quiet row under a message — copy, retry, feedback. */
|
|
40
|
-
const
|
|
40
|
+
const AiActions = part("Actions", "div");
|
|
41
41
|
/** The while-it-works whisper for the in-flight turns. */
|
|
42
|
-
const
|
|
42
|
+
const AiLoader = part("Loader", "span", {
|
|
43
43
|
role: "status",
|
|
44
44
|
"aria-label": "Loading"
|
|
45
45
|
});
|
|
46
46
|
/** The whole family under one handle — `Ai.Conversation`,
|
|
47
47
|
* `Ai.Message`, and the rest, exactly as before the split. */
|
|
48
|
-
const Ai = Object.assign(
|
|
49
|
-
Conversation,
|
|
50
|
-
MessageContent,
|
|
51
|
-
Actions,
|
|
52
|
-
Loader,
|
|
48
|
+
const Ai = Object.assign(AiConversation, {
|
|
49
|
+
Conversation: AiConversation,
|
|
50
|
+
MessageContent: AiContent,
|
|
51
|
+
Actions: AiActions,
|
|
52
|
+
Loader: AiLoader,
|
|
53
53
|
Message,
|
|
54
54
|
Response,
|
|
55
55
|
Reasoning,
|
|
@@ -62,4 +62,4 @@ const Ai = Object.assign(Conversation, {
|
|
|
62
62
|
});
|
|
63
63
|
injectComponentStyle("ai");
|
|
64
64
|
//#endregion
|
|
65
|
-
export { Ai };
|
|
65
|
+
export { Ai, AiActions, AiContent, AiConversation, AiLoader };
|
|
@@ -12,8 +12,11 @@ export interface AvatarProps extends ComponentProps<typeof Avatar$1.Root> {
|
|
|
12
12
|
* default (large) stands as tall as the biggest control so an avatar
|
|
13
13
|
* rides a row without stretching it. */
|
|
14
14
|
size?: AvatarSize;
|
|
15
|
+
/** The corner: round by default; square cuts it sharp, a stamp
|
|
16
|
+
* beside a round portrait. */
|
|
17
|
+
shape?: "circle" | "square";
|
|
15
18
|
}
|
|
16
|
-
declare function AvatarRoot({ size, ...rest }: AvatarProps): import("react").JSX.Element;
|
|
19
|
+
declare function AvatarRoot({ size, shape, ...rest }: AvatarProps): import("react").JSX.Element;
|
|
17
20
|
export declare const Avatar: typeof Avatar$1 & {
|
|
18
21
|
Root: typeof AvatarRoot;
|
|
19
22
|
};
|
|
@@ -2,10 +2,11 @@ import { injectComponentStyle } from "@bysages/core";
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { Avatar as Avatar$1 } from "@ark-ui/react/avatar";
|
|
4
4
|
//#region src/components/avatar/index.tsx
|
|
5
|
-
function AvatarRoot({ size, ...rest }) {
|
|
5
|
+
function AvatarRoot({ size, shape = "circle", ...rest }) {
|
|
6
6
|
return /* @__PURE__ */ jsx(Avatar$1.Root, {
|
|
7
7
|
...rest,
|
|
8
|
-
"data-size": size
|
|
8
|
+
"data-size": size,
|
|
9
|
+
"data-shape": shape
|
|
9
10
|
});
|
|
10
11
|
}
|
|
11
12
|
const Avatar = Object.assign({}, Avatar$1, { Root: AvatarRoot });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
//#region src/components/bento/index.d.ts
|
|
3
|
+
export interface BentoProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Tracks across the lattice. */
|
|
5
|
+
columns?: number;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export interface BentoCellProps extends HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
/** Columns this tile claims. */
|
|
10
|
+
span?: number;
|
|
11
|
+
/** Rows this tile claims. */
|
|
12
|
+
rowSpan?: number;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
/** The bento lattice: a grid of unequal tiles that reads as one plate.
|
|
16
|
+
* The container owns the track count; each cell claims its own span. */
|
|
17
|
+
export declare function BentoRoot({ columns, children, ...rest }: BentoProps): import("react").JSX.Element;
|
|
18
|
+
/** One tile: `span` claims columns, `rowSpan` claims rows — the rest
|
|
19
|
+
* of the plate stays in measure. */
|
|
20
|
+
export declare function BentoCell({ span, rowSpan, children, ...rest }: BentoCellProps): import("react").JSX.Element;
|
|
21
|
+
/** The whole family under one handle — Bento.Root, Bento.Cell. */
|
|
22
|
+
export declare const Bento: typeof BentoRoot & {
|
|
23
|
+
Root: typeof BentoRoot;
|
|
24
|
+
Cell: typeof BentoCell;
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { injectComponentStyle } from "@bysages/core";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/bento/index.tsx
|
|
4
|
+
/** The bento lattice: a grid of unequal tiles that reads as one plate.
|
|
5
|
+
* The container owns the track count; each cell claims its own span. */
|
|
6
|
+
function BentoRoot({ columns = 3, children, ...rest }) {
|
|
7
|
+
injectComponentStyle("bento");
|
|
8
|
+
return /* @__PURE__ */ jsx("div", {
|
|
9
|
+
...rest,
|
|
10
|
+
"data-scope": "bento",
|
|
11
|
+
"data-part": "root",
|
|
12
|
+
style: {
|
|
13
|
+
...rest.style,
|
|
14
|
+
"--bs-bento-columns": String(columns)
|
|
15
|
+
},
|
|
16
|
+
children
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** One tile: `span` claims columns, `rowSpan` claims rows — the rest
|
|
20
|
+
* of the plate stays in measure. */
|
|
21
|
+
function BentoCell({ span = 1, rowSpan = 1, children, ...rest }) {
|
|
22
|
+
injectComponentStyle("bento");
|
|
23
|
+
return /* @__PURE__ */ jsx("div", {
|
|
24
|
+
...rest,
|
|
25
|
+
"data-scope": "bento",
|
|
26
|
+
"data-part": "cell",
|
|
27
|
+
style: {
|
|
28
|
+
...rest.style,
|
|
29
|
+
"--bs-bento-span-x": String(span),
|
|
30
|
+
"--bs-bento-span-y": String(rowSpan)
|
|
31
|
+
},
|
|
32
|
+
children
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/** The whole family under one handle — Bento.Root, Bento.Cell. */
|
|
36
|
+
const Bento = Object.assign(BentoRoot, {
|
|
37
|
+
Root: BentoRoot,
|
|
38
|
+
Cell: BentoCell
|
|
39
|
+
});
|
|
40
|
+
//#endregion
|
|
41
|
+
export { Bento, BentoCell, BentoRoot };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
//#region src/components/block-ui/index.d.ts
|
|
3
|
+
export interface BlockUIProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Whether the curtain is drawn. */
|
|
5
|
+
blocked?: boolean;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** A curtain over content that must wait: the blocked region keeps its
|
|
9
|
+
* shape and dims under frosted paper while a quiet wheel reports the
|
|
10
|
+
* wait. Callers own the state; the curtain only answers it. */
|
|
11
|
+
export declare function BlockUI({ blocked, children, ...rest }: BlockUIProps): import("react").JSX.Element;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Spinner } from "../spinner/index.mjs";
|
|
2
|
+
import { injectComponentStyle } from "@bysages/core";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/block-ui/index.tsx
|
|
5
|
+
/** A curtain over content that must wait: the blocked region keeps its
|
|
6
|
+
* shape and dims under frosted paper while a quiet wheel reports the
|
|
7
|
+
* wait. Callers own the state; the curtain only answers it. */
|
|
8
|
+
function BlockUI({ blocked = false, children, ...rest }) {
|
|
9
|
+
injectComponentStyle("block-ui");
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11
|
+
...rest,
|
|
12
|
+
"data-scope": "block-ui",
|
|
13
|
+
"data-part": "root",
|
|
14
|
+
"data-blocked": blocked ? "" : void 0,
|
|
15
|
+
"aria-busy": blocked || void 0,
|
|
16
|
+
children: [children, blocked ? /* @__PURE__ */ jsx("div", {
|
|
17
|
+
"data-scope": "block-ui",
|
|
18
|
+
"data-part": "mask",
|
|
19
|
+
children: /* @__PURE__ */ jsx(Spinner, { size: "lg" })
|
|
20
|
+
}) : null]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { BlockUI };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
//#region src/components/browser/index.d.ts
|
|
3
|
+
export interface BrowserPartProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/** The three lamps are the system's own fixed pigments — the same
|
|
7
|
+
* semantics reserved for danger, warning, and success. */
|
|
8
|
+
export declare function BrowserDots(props: BrowserPartProps): import("react").JSX.Element;
|
|
9
|
+
export declare function BrowserRoot(props: BrowserPartProps): import("react").JSX.Element;
|
|
10
|
+
export declare function BrowserTitleBar(props: BrowserPartProps): import("react").JSX.Element;
|
|
11
|
+
export declare function BrowserUrlBar(props: BrowserPartProps): import("react").JSX.Element;
|
|
12
|
+
export declare function BrowserBody(props: BrowserPartProps): import("react").JSX.Element;
|
|
13
|
+
/** A browser window as a vessel: title bar, the three lamps, the
|
|
14
|
+
* address well, and a body that carries whatever the site hangs in
|
|
15
|
+
* it — an iframe, a screenshot, a live page. */
|
|
16
|
+
export declare const Browser: typeof BrowserRoot & {
|
|
17
|
+
Root: typeof BrowserRoot;
|
|
18
|
+
TitleBar: typeof BrowserTitleBar;
|
|
19
|
+
Dots: typeof BrowserDots;
|
|
20
|
+
UrlBar: typeof BrowserUrlBar;
|
|
21
|
+
Body: typeof BrowserBody;
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { injectComponentStyle } from "@bysages/core";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/browser/index.tsx
|
|
4
|
+
/** The three lamps are the system's own fixed pigments — the same
|
|
5
|
+
* semantics reserved for danger, warning, and success. */
|
|
6
|
+
function BrowserDots(props) {
|
|
7
|
+
injectComponentStyle("browser");
|
|
8
|
+
return /* @__PURE__ */ jsx("div", {
|
|
9
|
+
...props,
|
|
10
|
+
"data-scope": "browser",
|
|
11
|
+
"data-part": "dots",
|
|
12
|
+
children: [
|
|
13
|
+
"danger",
|
|
14
|
+
"warning",
|
|
15
|
+
"success"
|
|
16
|
+
].map((tone) => /* @__PURE__ */ jsx("span", {
|
|
17
|
+
"data-scope": "browser",
|
|
18
|
+
"data-part": "dot",
|
|
19
|
+
"data-tone": tone
|
|
20
|
+
}, tone))
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function BrowserRoot(props) {
|
|
24
|
+
injectComponentStyle("browser");
|
|
25
|
+
return /* @__PURE__ */ jsx("div", {
|
|
26
|
+
...props,
|
|
27
|
+
"data-scope": "browser",
|
|
28
|
+
"data-part": "root",
|
|
29
|
+
children: props.children
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function BrowserTitleBar(props) {
|
|
33
|
+
injectComponentStyle("browser");
|
|
34
|
+
return /* @__PURE__ */ jsx("div", {
|
|
35
|
+
...props,
|
|
36
|
+
"data-scope": "browser",
|
|
37
|
+
"data-part": "titlebar",
|
|
38
|
+
children: props.children
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function BrowserUrlBar(props) {
|
|
42
|
+
injectComponentStyle("browser");
|
|
43
|
+
return /* @__PURE__ */ jsx("div", {
|
|
44
|
+
...props,
|
|
45
|
+
"data-scope": "browser",
|
|
46
|
+
"data-part": "urlbar",
|
|
47
|
+
children: props.children
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function BrowserBody(props) {
|
|
51
|
+
injectComponentStyle("browser");
|
|
52
|
+
return /* @__PURE__ */ jsx("div", {
|
|
53
|
+
...props,
|
|
54
|
+
"data-scope": "browser",
|
|
55
|
+
"data-part": "body",
|
|
56
|
+
children: props.children
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** A browser window as a vessel: title bar, the three lamps, the
|
|
60
|
+
* address well, and a body that carries whatever the site hangs in
|
|
61
|
+
* it — an iframe, a screenshot, a live page. */
|
|
62
|
+
const Browser = Object.assign(BrowserRoot, {
|
|
63
|
+
Root: BrowserRoot,
|
|
64
|
+
TitleBar: BrowserTitleBar,
|
|
65
|
+
Dots: BrowserDots,
|
|
66
|
+
UrlBar: BrowserUrlBar,
|
|
67
|
+
Body: BrowserBody
|
|
68
|
+
});
|
|
69
|
+
//#endregion
|
|
70
|
+
export { Browser, BrowserBody, BrowserDots, BrowserRoot, BrowserTitleBar, BrowserUrlBar };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Input } from "
|
|
1
|
+
import { t as Input } from "../../input-2oezH-dY.mjs";
|
|
2
2
|
import { injectComponentStyle } from "@bysages/core";
|
|
3
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { useId, useMemo, useState } from "react";
|
|
5
5
|
import { Portal } from "@ark-ui/react/portal";
|
|
6
6
|
import { useEnvironmentContext } from "@ark-ui/react/environment";
|
|
@@ -151,6 +151,7 @@ function CascadeSelect({ value, data, placeholder = "Select…", highlightTrigge
|
|
|
151
151
|
children: item.label
|
|
152
152
|
}),
|
|
153
153
|
itemState.hasChildren ? /* @__PURE__ */ jsx("span", {
|
|
154
|
+
"data-scope": "cascade-select",
|
|
154
155
|
"data-part": "branch-indicator",
|
|
155
156
|
"aria-hidden": "true",
|
|
156
157
|
children: chevronRight
|
|
@@ -164,7 +165,8 @@ function CascadeSelect({ value, data, placeholder = "Select…", highlightTrigge
|
|
|
164
165
|
})
|
|
165
166
|
});
|
|
166
167
|
const next = nodeState.highlightedChild;
|
|
167
|
-
|
|
168
|
+
const child = next != null && collection.isBranchNode(next) ? renderColumn(next, [...indexPath, nodeState.highlightedIndex], [...valuePath, collection.getNodeValue(next)]) : null;
|
|
169
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [list, child] });
|
|
168
170
|
}
|
|
169
171
|
return /* @__PURE__ */ jsxs("div", {
|
|
170
172
|
...rest,
|
|
@@ -193,6 +195,7 @@ function CascadeSelect({ value, data, placeholder = "Select…", highlightTrigge
|
|
|
193
195
|
...api.getContentProps(),
|
|
194
196
|
"data-size": size,
|
|
195
197
|
children: [filterable ? /* @__PURE__ */ jsx("div", {
|
|
198
|
+
"data-scope": "cascade-select",
|
|
196
199
|
"data-part": "search",
|
|
197
200
|
children: /* @__PURE__ */ jsx(Input, {
|
|
198
201
|
size: "sm",
|
|
@@ -202,13 +205,16 @@ function CascadeSelect({ value, data, placeholder = "Select…", highlightTrigge
|
|
|
202
205
|
"aria-label": "Filter options"
|
|
203
206
|
})
|
|
204
207
|
}) : null, /* @__PURE__ */ jsx("div", {
|
|
208
|
+
"data-scope": "cascade-select",
|
|
205
209
|
"data-part": "corridor",
|
|
206
210
|
"data-flow": filtering ? "flat" : "columns",
|
|
207
211
|
children: filtering ? matchPaths.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
212
|
+
"data-scope": "cascade-select",
|
|
208
213
|
"data-part": "empty",
|
|
209
214
|
children: "Nothing matches"
|
|
210
215
|
}) : matchPaths.map((hit) => /* @__PURE__ */ jsx("button", {
|
|
211
216
|
type: "button",
|
|
217
|
+
"data-scope": "cascade-select",
|
|
212
218
|
"data-part": "match",
|
|
213
219
|
"data-selected": isSelected(hit.path) || void 0,
|
|
214
220
|
onClick: () => pickMatch(hit.path),
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
//#region src/components/data-view/index.d.ts
|
|
3
|
+
export interface DataViewProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
items: unknown[];
|
|
5
|
+
/** Ledger rows or a lattice of cards. */
|
|
6
|
+
layout?: "list" | "grid";
|
|
7
|
+
/** Records per page; leave unset to show everything at once. */
|
|
8
|
+
pageSize?: number;
|
|
9
|
+
/** Renders one record; the view lays the returned nodes out. */
|
|
10
|
+
renderItem?: (item: unknown, index: number) => ReactNode;
|
|
11
|
+
header?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/** One vessel, two layouts: the caller renders each record through
|
|
14
|
+
* renderItem, the view lays the records out as a ledger or a lattice
|
|
15
|
+
* and — when a page size is given — pages them with the pagination
|
|
16
|
+
* family's own parts rather than a second implementation. */
|
|
17
|
+
export declare function DataView({ items, layout, pageSize, renderItem, header, ...rest }: DataViewProps): import("react").JSX.Element;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Pagination } from "../pagination/index.mjs";
|
|
2
|
+
import { injectComponentStyle } from "@bysages/core";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
//#region src/components/data-view/index.tsx
|
|
6
|
+
/** One vessel, two layouts: the caller renders each record through
|
|
7
|
+
* renderItem, the view lays the records out as a ledger or a lattice
|
|
8
|
+
* and — when a page size is given — pages them with the pagination
|
|
9
|
+
* family's own parts rather than a second implementation. */
|
|
10
|
+
function DataView({ items, layout = "list", pageSize, renderItem, header, ...rest }) {
|
|
11
|
+
injectComponentStyle("data-view");
|
|
12
|
+
const [page, setPage] = useState(1);
|
|
13
|
+
const pageCount = pageSize ? Math.max(1, Math.ceil(items.length / pageSize)) : 1;
|
|
14
|
+
const visible = pageSize ? items.slice((page - 1) * pageSize, page * pageSize) : items;
|
|
15
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
16
|
+
...rest,
|
|
17
|
+
"data-scope": "data-view",
|
|
18
|
+
"data-part": "root",
|
|
19
|
+
children: [
|
|
20
|
+
header,
|
|
21
|
+
/* @__PURE__ */ jsx("div", {
|
|
22
|
+
"data-scope": "data-view",
|
|
23
|
+
"data-part": "content",
|
|
24
|
+
"data-layout": layout,
|
|
25
|
+
children: visible.map((item, index) => /* @__PURE__ */ jsx("div", {
|
|
26
|
+
"data-scope": "data-view",
|
|
27
|
+
"data-part": "cell",
|
|
28
|
+
children: renderItem?.(item, index)
|
|
29
|
+
}, index))
|
|
30
|
+
}),
|
|
31
|
+
pageSize && pageCount > 1 ? /* @__PURE__ */ jsx("div", {
|
|
32
|
+
"data-scope": "data-view",
|
|
33
|
+
"data-part": "pager",
|
|
34
|
+
children: /* @__PURE__ */ jsxs(Pagination.Root, {
|
|
35
|
+
count: items.length,
|
|
36
|
+
pageSize,
|
|
37
|
+
page,
|
|
38
|
+
siblingCount: 1,
|
|
39
|
+
onPageChange: (details) => setPage(details.page),
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ jsx(Pagination.PrevTrigger, {
|
|
42
|
+
"aria-label": "Previous page",
|
|
43
|
+
children: "‹"
|
|
44
|
+
}),
|
|
45
|
+
/* @__PURE__ */ jsx(Pagination.Context, { children: (pagination) => pagination.pages.map((entry, index) => entry.type === "ellipsis" ? /* @__PURE__ */ jsx(Pagination.Ellipsis, {
|
|
46
|
+
index,
|
|
47
|
+
children: "…"
|
|
48
|
+
}, `e${index}`) : /* @__PURE__ */ jsx(Pagination.Item, {
|
|
49
|
+
type: "page",
|
|
50
|
+
value: entry.value,
|
|
51
|
+
children: entry.value
|
|
52
|
+
}, entry.value)) }),
|
|
53
|
+
/* @__PURE__ */ jsx(Pagination.NextTrigger, {
|
|
54
|
+
"aria-label": "Next page",
|
|
55
|
+
children: "›"
|
|
56
|
+
})
|
|
57
|
+
]
|
|
58
|
+
})
|
|
59
|
+
}) : null
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { DataView };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
//#region src/components/deferred-content/index.d.ts
|
|
3
|
+
export interface DeferredContentProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** How much of the placeholder must be visible before the content
|
|
5
|
+
* mounts, from 0 (any pixel) to 1 (the whole box). */
|
|
6
|
+
threshold?: number;
|
|
7
|
+
/** Drawn until the box approaches the viewport. */
|
|
8
|
+
placeholder?: ReactNode;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/** Content that waits to be worth rendering: the slot stays off the
|
|
12
|
+
* tree until the placeholder scrolls near the viewport, then mounts
|
|
13
|
+
* once and stays. The placeholder is drawn by the caller, so the late
|
|
14
|
+
* arrival costs no layout shift it cannot predict. */
|
|
15
|
+
export declare function DeferredContent({ threshold, placeholder, children, ...rest }: DeferredContentProps): import("react").JSX.Element;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { injectComponentStyle } from "@bysages/core";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
//#region src/components/deferred-content/index.tsx
|
|
5
|
+
/** Content that waits to be worth rendering: the slot stays off the
|
|
6
|
+
* tree until the placeholder scrolls near the viewport, then mounts
|
|
7
|
+
* once and stays. The placeholder is drawn by the caller, so the late
|
|
8
|
+
* arrival costs no layout shift it cannot predict. */
|
|
9
|
+
function DeferredContent({ threshold = .2, placeholder, children, ...rest }) {
|
|
10
|
+
injectComponentStyle("deferred-content");
|
|
11
|
+
const host = useRef(null);
|
|
12
|
+
const [active, setActive] = useState(false);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const node = host.current;
|
|
15
|
+
if (!node) return;
|
|
16
|
+
const observer = new IntersectionObserver((entries) => {
|
|
17
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
18
|
+
setActive(true);
|
|
19
|
+
observer.disconnect();
|
|
20
|
+
}
|
|
21
|
+
}, { threshold });
|
|
22
|
+
observer.observe(node);
|
|
23
|
+
return () => observer.disconnect();
|
|
24
|
+
}, [threshold]);
|
|
25
|
+
return /* @__PURE__ */ jsx("div", {
|
|
26
|
+
ref: host,
|
|
27
|
+
...rest,
|
|
28
|
+
"data-scope": "deferred-content",
|
|
29
|
+
"data-part": "root",
|
|
30
|
+
children: active ? children : placeholder
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { DeferredContent };
|
|
@@ -5,14 +5,22 @@ import { HTMLAttributes } from "react";
|
|
|
5
5
|
* stacks each pair for narrow measures. */
|
|
6
6
|
export interface DescriptionsRootProps extends HTMLAttributes<HTMLDListElement> {
|
|
7
7
|
layout?: "horizontal" | "vertical";
|
|
8
|
+
/** The framed register: one hairline round the whole, terms on
|
|
9
|
+
* inset paper. */
|
|
10
|
+
bordered?: boolean;
|
|
11
|
+
/** Pairs across the grid: one ledger per column. */
|
|
12
|
+
column?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function DescriptionsRoot({ layout, bordered, column, children, ...rest }: DescriptionsRootProps): import("react").JSX.Element;
|
|
15
|
+
declare function DescriptionsItem({ span, children, ...rest }: HTMLAttributes<HTMLDivElement> & {
|
|
16
|
+
span?: number;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
18
|
+
declare namespace DescriptionsItem {
|
|
19
|
+
var displayName: string;
|
|
8
20
|
}
|
|
9
|
-
export declare function DescriptionsRoot({ layout, children, ...rest }: DescriptionsRootProps): import("react").JSX.Element;
|
|
10
21
|
export declare const Descriptions: {
|
|
11
22
|
Root: typeof DescriptionsRoot;
|
|
12
|
-
Item:
|
|
13
|
-
({ children, ...rest }: HTMLAttributes<HTMLElement>): import("react").JSX.Element;
|
|
14
|
-
displayName: string;
|
|
15
|
-
};
|
|
23
|
+
Item: typeof DescriptionsItem;
|
|
16
24
|
Term: {
|
|
17
25
|
({ children, ...rest }: HTMLAttributes<HTMLElement>): import("react").JSX.Element;
|
|
18
26
|
displayName: string;
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { injectComponentStyle } from "@bysages/core";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/descriptions/index.tsx
|
|
4
|
-
function DescriptionsRoot({ layout = "horizontal", children, ...rest }) {
|
|
4
|
+
function DescriptionsRoot({ layout = "horizontal", bordered = false, column = 1, children, ...rest }) {
|
|
5
5
|
injectComponentStyle("descriptions");
|
|
6
6
|
return /* @__PURE__ */ jsx("dl", {
|
|
7
7
|
...rest,
|
|
8
8
|
"data-scope": "descriptions",
|
|
9
9
|
"data-part": "root",
|
|
10
10
|
"data-layout": layout,
|
|
11
|
+
"data-bordered": bordered || void 0,
|
|
12
|
+
style: {
|
|
13
|
+
...rest.style,
|
|
14
|
+
"--bs-desc-columns": String(column)
|
|
15
|
+
},
|
|
11
16
|
children
|
|
12
17
|
});
|
|
13
18
|
}
|
|
@@ -22,9 +27,22 @@ function part(name, tag) {
|
|
|
22
27
|
Component.displayName = "Descriptions" + name;
|
|
23
28
|
return Component;
|
|
24
29
|
}
|
|
30
|
+
function DescriptionsItem({ span = 1, children, ...rest }) {
|
|
31
|
+
return /* @__PURE__ */ jsx("div", {
|
|
32
|
+
...rest,
|
|
33
|
+
style: {
|
|
34
|
+
...rest.style,
|
|
35
|
+
"--bs-desc-span": String(span * 2)
|
|
36
|
+
},
|
|
37
|
+
"data-scope": "descriptions",
|
|
38
|
+
"data-part": "item",
|
|
39
|
+
children
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
DescriptionsItem.displayName = "DescriptionsItem";
|
|
25
43
|
const Descriptions = {
|
|
26
44
|
Root: DescriptionsRoot,
|
|
27
|
-
Item:
|
|
45
|
+
Item: DescriptionsItem,
|
|
28
46
|
Term: part("Term", "dt"),
|
|
29
47
|
Detail: part("Detail", "dd")
|
|
30
48
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
//#region src/components/dock/index.d.ts
|
|
3
|
+
export interface DockProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** The tallest an item swells under the hand — 1 stands still. */
|
|
5
|
+
maxScale?: number;
|
|
6
|
+
/** How far the hand reaches, in px, before an item stops answering. */
|
|
7
|
+
radius?: number;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export interface DockItemProps extends HTMLAttributes<HTMLDivElement> {
|
|
11
|
+
children?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
/** The magnifying dock: a floating rail whose icons swell toward the
|
|
14
|
+
* hand. The wrapper measures per item and writes --bs-dock-scale; CSS
|
|
15
|
+
* eases the chase, so no spring engine rides along. */
|
|
16
|
+
export declare function DockRoot({ maxScale, radius, children, ...rest }: DockProps): import("react").JSX.Element;
|
|
17
|
+
/** One moored place in the rail: whatever slots in grows from the
|
|
18
|
+
* floor, never from its center. */
|
|
19
|
+
export declare function DockItem({ children, ...rest }: DockItemProps): import("react").JSX.Element;
|
|
20
|
+
/** The whole family under one handle — Dock.Root, Dock.Item. */
|
|
21
|
+
export declare const Dock: typeof DockRoot & {
|
|
22
|
+
Root: typeof DockRoot;
|
|
23
|
+
Item: typeof DockItem;
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { injectComponentStyle } from "@bysages/core";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/dock/index.tsx
|
|
4
|
+
const ITEM = "[data-scope=\"dock\"][data-part=\"item\"]";
|
|
5
|
+
/** The magnifying dock: a floating rail whose icons swell toward the
|
|
6
|
+
* hand. The wrapper measures per item and writes --bs-dock-scale; CSS
|
|
7
|
+
* eases the chase, so no spring engine rides along. */
|
|
8
|
+
function DockRoot({ maxScale = 1.5, radius = 96, children, ...rest }) {
|
|
9
|
+
injectComponentStyle("dock");
|
|
10
|
+
const magnify = (event) => {
|
|
11
|
+
for (const item of event.currentTarget.querySelectorAll(ITEM)) {
|
|
12
|
+
const rect = item.getBoundingClientRect();
|
|
13
|
+
const dist = Math.abs(event.clientX - (rect.left + rect.width / 2));
|
|
14
|
+
const t = Math.max(0, 1 - dist / radius);
|
|
15
|
+
item.style.setProperty("--bs-dock-scale", (1 + (maxScale - 1) * t * t).toFixed(4));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const reset = (event) => {
|
|
19
|
+
for (const item of event.currentTarget.querySelectorAll(ITEM)) item.style.removeProperty("--bs-dock-scale");
|
|
20
|
+
};
|
|
21
|
+
return /* @__PURE__ */ jsx("div", {
|
|
22
|
+
...rest,
|
|
23
|
+
"data-scope": "dock",
|
|
24
|
+
"data-part": "root",
|
|
25
|
+
style: {
|
|
26
|
+
...rest.style,
|
|
27
|
+
"--bs-dock-max-scale": maxScale
|
|
28
|
+
},
|
|
29
|
+
onPointerMove: magnify,
|
|
30
|
+
onPointerLeave: reset,
|
|
31
|
+
children
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** One moored place in the rail: whatever slots in grows from the
|
|
35
|
+
* floor, never from its center. */
|
|
36
|
+
function DockItem({ children, ...rest }) {
|
|
37
|
+
injectComponentStyle("dock");
|
|
38
|
+
return /* @__PURE__ */ jsx("div", {
|
|
39
|
+
...rest,
|
|
40
|
+
"data-scope": "dock",
|
|
41
|
+
"data-part": "item",
|
|
42
|
+
children
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** The whole family under one handle — Dock.Root, Dock.Item. */
|
|
46
|
+
const Dock = Object.assign(DockRoot, {
|
|
47
|
+
Root: DockRoot,
|
|
48
|
+
Item: DockItem
|
|
49
|
+
});
|
|
50
|
+
//#endregion
|
|
51
|
+
export { Dock, DockItem, DockRoot };
|