@godxjp/ui 20.2.1 → 21.0.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 (59) hide show
  1. package/dist/components/data-display/chat-bubble.d.ts +30 -0
  2. package/dist/components/data-display/chat-bubble.js +229 -0
  3. package/dist/components/data-display/descriptions.js +4 -1
  4. package/dist/components/data-display/index.d.ts +4 -2
  5. package/dist/components/data-display/index.js +5 -2
  6. package/dist/components/data-display/popover.js +3 -2
  7. package/dist/components/data-display/scroll-area.js +26 -1
  8. package/dist/components/data-display/tree.d.ts +8 -0
  9. package/dist/components/data-display/tree.js +426 -0
  10. package/dist/components/data-entry/chat-composer.d.ts +50 -0
  11. package/dist/components/data-entry/chat-composer.js +163 -0
  12. package/dist/components/data-entry/chat-suggestion.d.ts +28 -0
  13. package/dist/components/data-entry/chat-suggestion.js +285 -0
  14. package/dist/components/data-entry/index.d.ts +4 -0
  15. package/dist/components/data-entry/index.js +4 -0
  16. package/dist/components/data-entry/textarea.js +3 -1
  17. package/dist/components/data-entry/tree-utils.d.ts +10 -48
  18. package/dist/components/data-entry/tree-utils.js +1 -154
  19. package/dist/i18n/messages/en.json +45 -0
  20. package/dist/i18n/messages/ja.json +43 -0
  21. package/dist/i18n/messages/vi.json +44 -0
  22. package/dist/lib/tree.d.ts +53 -0
  23. package/dist/lib/tree.js +155 -0
  24. package/dist/props/components/data-display.prop.d.ts +187 -1
  25. package/dist/props/components/data-entry.prop.d.ts +127 -0
  26. package/dist/props/registry.d.ts +140 -3
  27. package/dist/props/registry.js +202 -3
  28. package/dist/styles/control.css +7 -0
  29. package/dist/styles/data-display-layout.css +309 -55
  30. package/dist/styles/data-entry-layout.css +64 -0
  31. package/dist/styles/shell-layout.css +2 -1
  32. package/dist/tokens/base.css +3 -0
  33. package/dist/tokens/components/chat-bubble.css +36 -0
  34. package/dist/tokens/components/chat-composer.css +19 -0
  35. package/dist/tokens/components/data-display.css +0 -6
  36. package/dist/tokens/components/descriptions.css +4 -0
  37. package/dist/tokens/components/shell.css +1 -0
  38. package/dist/tokens/components/tree.css +27 -0
  39. package/docs/FRAME-COVERAGE-LEDGER.md +1 -1
  40. package/docs/FRAME-COVERAGE-REPORT.md +8 -3
  41. package/docs/data-display/chat-bubble.tsx +397 -0
  42. package/docs/data-display/timeline.tsx +46 -0
  43. package/docs/data-display/tree.tsx +394 -0
  44. package/docs/data-entry/chat-composer.tsx +464 -0
  45. package/docs/data-entry/chat-suggestion.tsx +301 -0
  46. package/docs/roadmap/ai-chat-components.md +207 -0
  47. package/docs/roadmap/antd-parity.md +154 -0
  48. package/docs/roadmap/badge-tag-chip-count.md +172 -0
  49. package/docs/roadmap/list-masonry.md +159 -0
  50. package/docs/roadmap/parity-audit-data-display-feedback.md +567 -0
  51. package/docs/roadmap/parity-audit-data-entry.md +344 -0
  52. package/docs/roadmap/parity-audit-layout-navigation-general.md +464 -0
  53. package/docs/roadmap/parity-backlog.md +79 -0
  54. package/docs/roadmap/tree-components.md +151 -0
  55. package/docs/showcase/table-tree-rows.tsx +4 -4
  56. package/package.json +5 -3
  57. package/dist/components/data-display/tree-list.d.ts +0 -13
  58. package/dist/components/data-display/tree-list.js +0 -26
  59. package/docs/data-display/tree-list.tsx +0 -107
@@ -0,0 +1,30 @@
1
+ import * as React from "react";
2
+ import type { ChatBubbleListProp, ChatBubbleProp } from "../../props/components/data-display.prop.js";
3
+ export type { ChatBubbleListProp, ChatBubblePlacementProp, ChatBubbleProp, ChatBubbleToneProp, ChatBubbleTypingProp, ChatBubbleVariantProp, ChatMessageProp, } from "../../props/components/data-display.prop.js";
4
+ export type ChatBubbleProps = ChatBubbleProp & Omit<React.HTMLAttributes<HTMLElement>, keyof ChatBubbleProp>;
5
+ /**
6
+ * ChatBubble — ONE message in a conversation: an optional author mark, a header naming the turn,
7
+ * the message body, and a footer for timestamps or per-message actions.
8
+ *
9
+ * It is an `<article>` inside the feed's `role="log"`, and it deliberately owns NO live region of
10
+ * its own: one live region per bubble floods a screen reader on every token of a stream. The feed
11
+ * (`ChatBubbleList`) owns the single `aria-live="polite"` region; a bubble only ever says "I am
12
+ * still being produced" through `aria-busy`.
13
+ */
14
+ export declare const ChatBubble: React.ForwardRefExoticComponent<ChatBubbleProp & Omit<React.HTMLAttributes<HTMLElement>, keyof ChatBubbleProp> & React.RefAttributes<HTMLElement>>;
15
+ export type ChatBubbleListProps = ChatBubbleListProp & Omit<React.HTMLAttributes<HTMLDivElement>, keyof ChatBubbleListProp>;
16
+ /**
17
+ * ChatBubbleList — the message feed.
18
+ *
19
+ * The behaviour that earns this a component rather than a `ScrollArea` + `map` is STICK-TO-BOTTOM:
20
+ * new messages keep the viewport pinned only while the reader is ALREADY at the bottom. The moment
21
+ * they scroll up to re-read something the pin is revoked and stays revoked until they ask for it
22
+ * back — silently yanking a reader to the newest message mid-sentence is a change of context they
23
+ * did not request (WCAG 3.2.5), and it is the classic chat-UI defect. The way back is a real,
24
+ * focusable button that also says how many messages arrived while they were away.
25
+ *
26
+ * GIVE IT A DEFINITE HEIGHT — `className="h-96"`, or a flex/grid parent that hands it a track.
27
+ * The feed scrolls INSIDE itself; with no height it simply grows to its content, nothing ever
28
+ * overflows, and every behaviour above has nothing to act on.
29
+ */
30
+ export declare const ChatBubbleList: React.ForwardRefExoticComponent<ChatBubbleListProp & Omit<React.HTMLAttributes<HTMLDivElement>, keyof ChatBubbleListProp> & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,229 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { ArrowDown } from "lucide-react";
5
+ import { useTranslation } from "../../i18n/use-translation.js";
6
+ import { useMediaQuery } from "../../lib/hooks.js";
7
+ import { cn } from "../../lib/utils.js";
8
+ import { Skeleton } from "../feedback/skeleton.js";
9
+ import { Button } from "../general/button.js";
10
+ import { Text } from "../general/typography.js";
11
+ import { VisuallyHidden } from "../general/visually-hidden.js";
12
+ import { ScrollArea } from "./scroll-area.js";
13
+ const BODY_SIZE = {
14
+ xs: "2xs",
15
+ sm: "xs",
16
+ md: "sm",
17
+ lg: "lg"
18
+ };
19
+ const META_SIZE = {
20
+ xs: "2xs",
21
+ sm: "2xs",
22
+ md: "xs",
23
+ lg: "sm"
24
+ };
25
+ const TYPING_STEP = 1;
26
+ const TYPING_INTERVAL = 50;
27
+ function resolveTyping(typing) {
28
+ if (typing === void 0 || typing === false) {
29
+ return { enabled: false, step: TYPING_STEP, interval: TYPING_INTERVAL };
30
+ }
31
+ if (typing === true) return { enabled: true, step: TYPING_STEP, interval: TYPING_INTERVAL };
32
+ return {
33
+ enabled: true,
34
+ // A non-positive step would never reach the end of the string and a non-positive interval
35
+ // would spin the timer — both are "the animation never completes", which is the one outcome
36
+ // a reader can neither read nor dismiss.
37
+ step: typing.step != null && typing.step > 0 ? Math.floor(typing.step) : TYPING_STEP,
38
+ interval: typing.interval != null && typing.interval > 0 ? typing.interval : TYPING_INTERVAL
39
+ };
40
+ }
41
+ function useRevealedLength(text, enabled, step, interval) {
42
+ const full = text?.length ?? 0;
43
+ const [revealed, setRevealed] = React.useState(() => enabled ? 0 : full);
44
+ React.useEffect(() => {
45
+ if (!enabled || text === void 0) {
46
+ setRevealed(text?.length ?? 0);
47
+ return void 0;
48
+ }
49
+ setRevealed(0);
50
+ let shown = 0;
51
+ const timer = setInterval(() => {
52
+ shown = Math.min(text.length, shown + step);
53
+ setRevealed(shown);
54
+ if (shown >= text.length) clearInterval(timer);
55
+ }, interval);
56
+ return () => {
57
+ clearInterval(timer);
58
+ };
59
+ }, [text, enabled, step, interval]);
60
+ return Math.min(revealed, full);
61
+ }
62
+ const TONE_KEY = {
63
+ info: "chat.bubble.tone.info",
64
+ success: "chat.bubble.tone.success",
65
+ warning: "chat.bubble.tone.warning",
66
+ destructive: "chat.bubble.tone.destructive"
67
+ };
68
+ const ChatBubble = React.forwardRef(
69
+ ({
70
+ children,
71
+ placement = "start",
72
+ variant = "filled",
73
+ avatar,
74
+ header,
75
+ footer,
76
+ loading = false,
77
+ typing,
78
+ size = "md",
79
+ tone = "default",
80
+ className,
81
+ id,
82
+ ...props
83
+ }, ref) => {
84
+ const { t } = useTranslation();
85
+ const generatedId = React.useId();
86
+ const headerId = `${id ?? generatedId}-header`;
87
+ const reduceMotion = useMediaQuery("(prefers-reduced-motion: reduce)");
88
+ const text = typeof children === "string" ? children : void 0;
89
+ const { enabled, step, interval } = resolveTyping(typing);
90
+ const animates = enabled && !loading && text !== void 0 && !reduceMotion;
91
+ const revealed = useRevealedLength(text, animates, step, interval);
92
+ const streaming = animates && revealed < (text?.length ?? 0);
93
+ const body = loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
94
+ /* @__PURE__ */ jsxs("div", { className: "ui-chat-bubble-skeleton", "aria-hidden": "true", children: [
95
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-chat-bubble-skeleton-line" }),
96
+ /* @__PURE__ */ jsx(Skeleton, { className: "ui-chat-bubble-skeleton-line ui-chat-bubble-skeleton-line--short" })
97
+ ] }),
98
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: t("chat.bubble.loading") })
99
+ ] }) : streaming ? /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ /* @__PURE__ */ jsxs(Text, { as: "div", size: BODY_SIZE[size], whitespace: "pre-wrap", "aria-hidden": "true", children: [
101
+ text?.slice(0, revealed),
102
+ /* @__PURE__ */ jsx("span", { className: "ui-chat-bubble-caret" })
103
+ ] }),
104
+ /* @__PURE__ */ jsx(VisuallyHidden, { children: t("chat.bubble.typing") })
105
+ ] }) : /* @__PURE__ */ jsx(
106
+ Text,
107
+ {
108
+ as: "div",
109
+ size: BODY_SIZE[size],
110
+ whitespace: text !== void 0 ? "pre-wrap" : void 0,
111
+ children
112
+ }
113
+ );
114
+ return /* @__PURE__ */ jsxs(
115
+ "article",
116
+ {
117
+ ref,
118
+ id,
119
+ "data-slot": "chat-bubble",
120
+ "data-placement": placement,
121
+ "data-variant": variant,
122
+ "data-size": size,
123
+ "data-tone": tone,
124
+ "aria-busy": loading || streaming ? true : void 0,
125
+ "aria-labelledby": header != null ? headerId : void 0,
126
+ className: cn("ui-chat-bubble", className),
127
+ ...props,
128
+ children: [
129
+ avatar != null ? /* @__PURE__ */ jsx("span", { "data-slot": "chat-bubble-avatar", className: "ui-chat-bubble-avatar", children: avatar }) : null,
130
+ /* @__PURE__ */ jsxs("div", { "data-slot": "chat-bubble-column", className: "ui-chat-bubble-column", children: [
131
+ header != null ? /* @__PURE__ */ jsx(
132
+ Text,
133
+ {
134
+ as: "div",
135
+ id: headerId,
136
+ className: "ui-chat-bubble-header",
137
+ size: META_SIZE[size],
138
+ tone: "muted",
139
+ weight: "medium",
140
+ children: header
141
+ }
142
+ ) : null,
143
+ /* @__PURE__ */ jsxs("div", { "data-slot": "chat-bubble-body", className: "ui-chat-bubble-body", children: [
144
+ tone !== "default" ? /* @__PURE__ */ jsx(VisuallyHidden, { children: t(TONE_KEY[tone]) }) : null,
145
+ body
146
+ ] }),
147
+ footer != null ? /* @__PURE__ */ jsx(Text, { as: "div", className: "ui-chat-bubble-footer", size: META_SIZE[size], tone: "muted", children: footer }) : null
148
+ ] })
149
+ ]
150
+ }
151
+ );
152
+ }
153
+ );
154
+ ChatBubble.displayName = "ChatBubble";
155
+ const ChatBubbleList = React.forwardRef(
156
+ ({ items, roles, autoScroll = true, label, className, id, ...props }, ref) => {
157
+ const { t } = useTranslation();
158
+ const viewportRef = React.useRef(null);
159
+ const [anchored, setAnchored] = React.useState(true);
160
+ const seen = React.useRef(items.length);
161
+ React.useEffect(() => {
162
+ if (anchored) seen.current = items.length;
163
+ }, [anchored, items.length]);
164
+ const pending = anchored ? 0 : Math.max(0, items.length - seen.current);
165
+ const jumpToLatest = React.useCallback(() => {
166
+ const viewport = viewportRef.current;
167
+ if (viewport) {
168
+ const bottom = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
169
+ if (typeof viewport.scrollTo === "function") {
170
+ viewport.scrollTo({ top: bottom, behavior: "instant" });
171
+ } else {
172
+ viewport.scrollTop = bottom;
173
+ }
174
+ }
175
+ setAnchored(true);
176
+ }, []);
177
+ return /* @__PURE__ */ jsxs(
178
+ "div",
179
+ {
180
+ ref,
181
+ id,
182
+ "data-slot": "chat-bubble-list",
183
+ "data-anchored": anchored ? "" : void 0,
184
+ className: cn("ui-chat-bubble-list", className),
185
+ ...props,
186
+ children: [
187
+ /* @__PURE__ */ jsx(
188
+ ScrollArea,
189
+ {
190
+ className: "ui-chat-bubble-list-scroller",
191
+ anchor: autoScroll ? "bottom" : "none",
192
+ viewportRef,
193
+ onAnchoredChange: setAnchored,
194
+ children: /* @__PURE__ */ jsx(
195
+ "div",
196
+ {
197
+ role: "log",
198
+ "aria-live": "polite",
199
+ "aria-label": label ?? t("chat.list.label"),
200
+ "data-slot": "chat-bubble-list-feed",
201
+ className: "ui-chat-bubble-list-feed",
202
+ children: items.map(({ id: messageId, role, content, ...message }) => /* @__PURE__ */ jsx(
203
+ ChatBubble,
204
+ {
205
+ id: messageId,
206
+ ...role != null ? roles?.[role] : void 0,
207
+ ...message,
208
+ children: content
209
+ },
210
+ messageId
211
+ ))
212
+ }
213
+ )
214
+ }
215
+ ),
216
+ anchored ? null : /* @__PURE__ */ jsx("div", { "data-slot": "chat-bubble-list-jump", className: "ui-chat-bubble-list-jump", children: /* @__PURE__ */ jsxs(Button, { type: "button", size: "sm", variant: "secondary", shape: "pill", onClick: jumpToLatest, children: [
217
+ /* @__PURE__ */ jsx(ArrowDown, { "aria-hidden": "true" }),
218
+ pending > 0 ? t("chat.list.newMessages", { count: pending }) : t("chat.list.jumpToLatest")
219
+ ] }) })
220
+ ]
221
+ }
222
+ );
223
+ }
224
+ );
225
+ ChatBubbleList.displayName = "ChatBubbleList";
226
+ export {
227
+ ChatBubble,
228
+ ChatBubbleList
229
+ };
@@ -104,7 +104,10 @@ function DescriptionsItem({ label, mono, span, className, children }) {
104
104
  "data-slot": "descriptions-label",
105
105
  "data-label-align": endAlignedLabel ? "end" : void 0,
106
106
  className: cn(
107
- "text-muted-foreground text-xs",
107
+ // Size comes from the token pair, NOT from `text-xs`: a hard-coded utility here left the
108
+ // label one type step below the value beside it, and out of reach of a service theme.
109
+ // The muted colour is what distinguishes a label from its value.
110
+ "text-muted-foreground text-[length:var(--descriptions-label-font-size)] leading-[var(--descriptions-label-line-height)]",
108
111
  // `end`-align only ever applies in horizontal layout — same guard `Form` uses, so a
109
112
  endAlignedLabel && "text-end"
110
113
  ),
@@ -26,8 +26,6 @@ export type { CodeBlockProp, CodeBlockProps } from "./code-block.js";
26
26
  export { Prose } from "./prose.js";
27
27
  export type { ProseProp, ProseProps } from "./prose.js";
28
28
  export type { ProgressProps, ProgressSegment, ProgressTone } from "./progress.js";
29
- export { TreeList } from "./tree-list.js";
30
- export type { TreeListItem, TreeListProps } from "./tree-list.js";
31
29
  export { Timeline } from "./timeline.js";
32
30
  export type { TimelineItem, TimelineProps } from "./timeline.js";
33
31
  export { TimelineGrid } from "./timeline-grid.js";
@@ -43,3 +41,7 @@ export { PermissionMatrix } from "./permission-matrix.js";
43
41
  export type { PermissionMatrixGrantsProp, PermissionMatrixPermissionProp, PermissionMatrixProp, PermissionMatrixProps, PermissionMatrixRoleProp, } from "./permission-matrix.js";
44
42
  export { RangeTimeline } from "./range-timeline.js";
45
43
  export type { RangeTimelineProps, RangeTimelineRow } from "./range-timeline.js";
44
+ export { ChatBubble, ChatBubbleList } from "./chat-bubble.js";
45
+ export type { ChatBubbleListProp, ChatBubbleListProps, ChatBubblePlacementProp, ChatBubbleProp, ChatBubbleProps, ChatBubbleToneProp, ChatBubbleTypingProp, ChatBubbleVariantProp, ChatMessageProp, } from "./chat-bubble.js";
46
+ export { Tree } from "./tree.js";
47
+ export type { TreeNodeProp, TreeProp, TreeProps } from "./tree.js";
@@ -28,7 +28,6 @@ import { EmptyState } from "./empty-state.js";
28
28
  import { Progress } from "./progress.js";
29
29
  import { CodeBlock } from "./code-block.js";
30
30
  import { Prose } from "./prose.js";
31
- import { TreeList } from "./tree-list.js";
32
31
  import { Timeline } from "./timeline.js";
33
32
  import { TimelineGrid } from "./timeline-grid.js";
34
33
  import {
@@ -55,6 +54,8 @@ import {
55
54
  } from "./carousel.js";
56
55
  import { PermissionMatrix } from "./permission-matrix.js";
57
56
  import { RangeTimeline } from "./range-timeline.js";
57
+ import { ChatBubble, ChatBubbleList } from "./chat-bubble.js";
58
+ import { Tree } from "./tree.js";
58
59
  export {
59
60
  Accordion,
60
61
  AccordionContent,
@@ -79,6 +80,8 @@ export {
79
80
  CarouselItem,
80
81
  CarouselNext,
81
82
  CarouselPrevious,
83
+ ChatBubble,
84
+ ChatBubbleList,
82
85
  CodeBlock,
83
86
  Collapsible,
84
87
  CollapsibleContent,
@@ -119,7 +122,7 @@ export {
119
122
  TableRow,
120
123
  Timeline,
121
124
  TimelineGrid,
122
- TreeList,
125
+ Tree,
123
126
  flexRender,
124
127
  useCarousel
125
128
  };
@@ -165,7 +165,7 @@ function PopoverContent({
165
165
  }
166
166
  }
167
167
  }, [root.open]);
168
- const { open, setOpen, triggerRef } = root;
168
+ const { open, setOpen, triggerRef, anchorRef, anchored } = root;
169
169
  React.useEffect(() => {
170
170
  if (!open) return;
171
171
  const onPointerDown = (event) => {
@@ -173,11 +173,12 @@ function PopoverContent({
173
173
  if (!target) return;
174
174
  if (contentRef.current?.contains(target)) return;
175
175
  if (triggerRef.current?.contains(target)) return;
176
+ if (anchored && anchorRef.current?.contains(target)) return;
176
177
  setOpen(false);
177
178
  };
178
179
  document.addEventListener("pointerdown", onPointerDown);
179
180
  return () => document.removeEventListener("pointerdown", onPointerDown);
180
- }, [open, setOpen, triggerRef]);
181
+ }, [open, setOpen, triggerRef, anchorRef, anchored]);
181
182
  const overlayPortalContainer = useOverlayPortalContainer(portalContainer);
182
183
  return /* @__PURE__ */ jsx(
183
184
  AriaPopover,
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useLayoutEffect } from "@react-aria/utils";
3
4
  import * as React from "react";
4
5
  import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
5
6
  import { cn } from "../../lib/utils.js";
@@ -112,6 +113,18 @@ function useBottomAnchor(viewport, enabled, offset, onAnchoredChange) {
112
113
  };
113
114
  }, [viewport, enabled, offset]);
114
115
  }
116
+ function useAmbientDirection(root, provided) {
117
+ const [ambient, setAmbient] = React.useState(void 0);
118
+ useLayoutEffect(() => {
119
+ if (provided !== void 0) return;
120
+ const parent = root?.parentElement;
121
+ if (!parent || typeof window === "undefined" || typeof window.getComputedStyle !== "function") {
122
+ return;
123
+ }
124
+ setAmbient(window.getComputedStyle(parent).direction === "rtl" ? "rtl" : "ltr");
125
+ }, [root, provided]);
126
+ return provided ?? ambient;
127
+ }
115
128
  const ScrollArea = React.forwardRef(
116
129
  ({
117
130
  className,
@@ -121,9 +134,20 @@ const ScrollArea = React.forwardRef(
121
134
  anchorOffset,
122
135
  onAnchoredChange,
123
136
  orientation = "vertical",
137
+ dir,
124
138
  ...props
125
139
  }, ref) => {
126
140
  const [viewport, setViewport] = React.useState(null);
141
+ const [root, setRoot] = React.useState(null);
142
+ const attachRoot = React.useCallback(
143
+ (node) => {
144
+ setRoot(node);
145
+ if (typeof ref === "function") ref(node);
146
+ else if (ref) ref.current = node;
147
+ },
148
+ [ref]
149
+ );
150
+ const direction = useAmbientDirection(root, dir);
127
151
  const attachViewport = React.useCallback(
128
152
  (node) => {
129
153
  setViewport(node);
@@ -137,7 +161,8 @@ const ScrollArea = React.forwardRef(
137
161
  return /* @__PURE__ */ jsxs(
138
162
  ScrollAreaPrimitive.Root,
139
163
  {
140
- ref,
164
+ ref: attachRoot,
165
+ dir: direction,
141
166
  className: cn("relative overflow-hidden", className),
142
167
  ...props,
143
168
  children: [
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+ import type { TreeProp } from "../../props/components/data-display.prop.js";
3
+ export type { TreeNodeProp, TreeProp, TreeProp as TreeProps, } from "../../props/components/data-display.prop.js";
4
+ /**
5
+ * `ref` reaches the `role="tree"` container — the element a page scrolls to, measures, or
6
+ * focus-manages. Every unknown prop (`aria-*`, `data-*`) rides `...ariaProps` onto the same node.
7
+ */
8
+ export declare const Tree: React.ForwardRefExoticComponent<TreeProp & React.RefAttributes<HTMLDivElement>>;