@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.
Files changed (56) hide show
  1. package/README.md +16 -2
  2. package/dist/components/ai/index.d.mts +2 -2
  3. package/dist/components/ai/index.mjs +10 -10
  4. package/dist/components/avatar/index.d.mts +4 -1
  5. package/dist/components/avatar/index.mjs +3 -2
  6. package/dist/components/bento/index.d.mts +26 -0
  7. package/dist/components/bento/index.mjs +41 -0
  8. package/dist/components/block-ui/index.d.mts +12 -0
  9. package/dist/components/block-ui/index.mjs +24 -0
  10. package/dist/components/browser/index.d.mts +23 -0
  11. package/dist/components/browser/index.mjs +70 -0
  12. package/dist/components/cascade-select/index.mjs +9 -3
  13. package/dist/components/data-view/index.d.mts +18 -0
  14. package/dist/components/data-view/index.mjs +64 -0
  15. package/dist/components/deferred-content/index.d.mts +16 -0
  16. package/dist/components/deferred-content/index.mjs +34 -0
  17. package/dist/components/descriptions/index.d.mts +13 -5
  18. package/dist/components/descriptions/index.mjs +20 -2
  19. package/dist/components/dock/index.d.mts +25 -0
  20. package/dist/components/dock/index.mjs +51 -0
  21. package/dist/components/dynamic-input/index.mjs +1 -1
  22. package/dist/components/form/index.mjs +1 -1
  23. package/dist/components/icon/index.d.mts +10 -5
  24. package/dist/components/icon/index.mjs +7 -7
  25. package/dist/components/input/index.d.mts +4 -1
  26. package/dist/components/input/index.mjs +1 -20
  27. package/dist/components/order-list/index.d.mts +21 -0
  28. package/dist/components/order-list/index.mjs +162 -0
  29. package/dist/components/result/index.d.mts +31 -0
  30. package/dist/components/result/index.mjs +59 -0
  31. package/dist/components/select/index.d.mts +2 -17
  32. package/dist/components/select/index.mjs +2 -18
  33. package/dist/components/spotlight/index.d.mts +12 -0
  34. package/dist/components/spotlight/index.mjs +33 -0
  35. package/dist/components/table/index.mjs +1 -1
  36. package/dist/components/tabs/index.d.mts +3 -1
  37. package/dist/components/tabs/index.mjs +3 -2
  38. package/dist/components/terminal/index.d.mts +17 -0
  39. package/dist/components/terminal/index.mjs +65 -0
  40. package/dist/components/timeline/index.d.mts +13 -11
  41. package/dist/components/timeline/index.mjs +11 -1
  42. package/dist/components/toolbar/index.d.mts +17 -0
  43. package/dist/components/toolbar/index.mjs +29 -0
  44. package/dist/components/transfer/index.mjs +1 -1
  45. package/dist/components/tree-select/index.mjs +1 -1
  46. package/dist/components/user/index.d.mts +20 -0
  47. package/dist/components/user/index.mjs +42 -0
  48. package/dist/components/virtual-list/index.d.mts +17 -0
  49. package/dist/components/virtual-list/index.mjs +52 -0
  50. package/dist/{index-DaAbbSz9.d.mts → index-CsfxYv6J.d.mts} +741 -3774
  51. package/dist/index-DFN9F5Zt.d.mts +42 -0
  52. package/dist/index.d.mts +16 -3
  53. package/dist/index.mjs +26 -13
  54. package/dist/input-2oezH-dY.mjs +58 -0
  55. package/dist/select-D1xiT1oJ.mjs +68 -0
  56. package/package.json +30 -9
package/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
  ![npm downloads](https://img.shields.io/npm/dw/@bysages/react)
5
5
  ![npm license](https://img.shields.io/npm/l/@bysages/react)
6
6
 
7
- > By Sages Elements for React — 90+ accessible component families, headless by construction, dressed by the paper-and-ink style layer. Ported from the Vue reference implementation, API for API.
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
- - 🧩 **90+ families** — actions, forms, overlays, navigation, data, layout, and an AI conversation family on ai-sdk formats
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 SourceDocumentUIPart, c as TextUIPart, d as UIMessagePart, i as ReasoningUIPart, l as ToolUIPart, n as DataUIPart, o as SourceUrlUIPart, r as FileUIPart, s as StepStartUIPart, t as Ai, u as UIMessage } from "../../index-DaAbbSz9.mjs";
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 Conversation = part("Conversation", "div", {
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 MessageContent = part("Content", "div");
38
+ const AiContent = part("Content", "div");
39
39
  /** The quiet row under a message — copy, retry, feedback. */
40
- const Actions = part("Actions", "div");
40
+ const AiActions = part("Actions", "div");
41
41
  /** The while-it-works whisper for the in-flight turns. */
42
- const Loader = part("Loader", "span", {
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(Conversation, {
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 "../input/index.mjs";
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
- return [list, next != null && collection.isBranchNode(next) ? renderColumn(next, [...indexPath, nodeState.highlightedIndex], [...valuePath, collection.getNodeValue(next)]) : null];
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: part("Item", "div"),
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 };