@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.
- package/dist/components/data-display/chat-bubble.d.ts +30 -0
- package/dist/components/data-display/chat-bubble.js +229 -0
- package/dist/components/data-display/descriptions.js +4 -1
- package/dist/components/data-display/index.d.ts +4 -2
- package/dist/components/data-display/index.js +5 -2
- package/dist/components/data-display/popover.js +3 -2
- package/dist/components/data-display/scroll-area.js +26 -1
- package/dist/components/data-display/tree.d.ts +8 -0
- package/dist/components/data-display/tree.js +426 -0
- package/dist/components/data-entry/chat-composer.d.ts +50 -0
- package/dist/components/data-entry/chat-composer.js +163 -0
- package/dist/components/data-entry/chat-suggestion.d.ts +28 -0
- package/dist/components/data-entry/chat-suggestion.js +285 -0
- package/dist/components/data-entry/index.d.ts +4 -0
- package/dist/components/data-entry/index.js +4 -0
- package/dist/components/data-entry/textarea.js +3 -1
- package/dist/components/data-entry/tree-utils.d.ts +10 -48
- package/dist/components/data-entry/tree-utils.js +1 -154
- package/dist/i18n/messages/en.json +45 -0
- package/dist/i18n/messages/ja.json +43 -0
- package/dist/i18n/messages/vi.json +44 -0
- package/dist/lib/tree.d.ts +53 -0
- package/dist/lib/tree.js +155 -0
- package/dist/props/components/data-display.prop.d.ts +187 -1
- package/dist/props/components/data-entry.prop.d.ts +127 -0
- package/dist/props/registry.d.ts +140 -3
- package/dist/props/registry.js +202 -3
- package/dist/styles/control.css +7 -0
- package/dist/styles/data-display-layout.css +309 -55
- package/dist/styles/data-entry-layout.css +64 -0
- package/dist/styles/shell-layout.css +2 -1
- package/dist/tokens/base.css +3 -0
- package/dist/tokens/components/chat-bubble.css +36 -0
- package/dist/tokens/components/chat-composer.css +19 -0
- package/dist/tokens/components/data-display.css +0 -6
- package/dist/tokens/components/descriptions.css +4 -0
- package/dist/tokens/components/shell.css +1 -0
- package/dist/tokens/components/tree.css +27 -0
- package/docs/FRAME-COVERAGE-LEDGER.md +1 -1
- package/docs/FRAME-COVERAGE-REPORT.md +8 -3
- package/docs/data-display/chat-bubble.tsx +397 -0
- package/docs/data-display/timeline.tsx +46 -0
- package/docs/data-display/tree.tsx +394 -0
- package/docs/data-entry/chat-composer.tsx +464 -0
- package/docs/data-entry/chat-suggestion.tsx +301 -0
- package/docs/roadmap/ai-chat-components.md +207 -0
- package/docs/roadmap/antd-parity.md +154 -0
- package/docs/roadmap/badge-tag-chip-count.md +172 -0
- package/docs/roadmap/list-masonry.md +159 -0
- package/docs/roadmap/parity-audit-data-display-feedback.md +567 -0
- package/docs/roadmap/parity-audit-data-entry.md +344 -0
- package/docs/roadmap/parity-audit-layout-navigation-general.md +464 -0
- package/docs/roadmap/parity-backlog.md +79 -0
- package/docs/roadmap/tree-components.md +151 -0
- package/docs/showcase/table-tree-rows.tsx +4 -4
- package/package.json +5 -3
- package/dist/components/data-display/tree-list.d.ts +0 -13
- package/dist/components/data-display/tree-list.js +0 -26
- package/docs/data-display/tree-list.tsx +0 -107
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Tree components — audit + normalized spec
|
|
2
|
+
|
|
3
|
+
> **Status:** audit complete 2026-09-10. `Tree` is NOT implemented. Read this before touching
|
|
4
|
+
> anything under `src/components/**/tree-*`.
|
|
5
|
+
> **Contract:** `.claude/skills/godxjp-ui-component/SKILL.md` is the hard gate. This document only
|
|
6
|
+
> normalizes *what* to build; the skill owns *how*.
|
|
7
|
+
|
|
8
|
+
## 1. What exists today (measured, not eyeballed)
|
|
9
|
+
|
|
10
|
+
| Thing | File | What it actually is |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `TreeSelect` | `src/components/data-entry/tree-select.tsx` (499 L) | A real tree, but only **inside a dropdown**. Ant-aligned API. |
|
|
13
|
+
| `TreeList` | `src/components/data-display/tree-list.tsx` (41 L) | **Not a tree.** A flat `<ul>` where `depth` is a number that only drives `margin-inline-start`. |
|
|
14
|
+
| `tree-utils` | `src/components/data-entry/tree-utils.ts` (216 L) | Normalize / flatten / filter / descendants. Sound, reusable. Currently private to `data-entry`. |
|
|
15
|
+
| `Tree` | — | **Does not exist.** |
|
|
16
|
+
|
|
17
|
+
### 1a. `TreeSelect` is fine — leave it alone
|
|
18
|
+
|
|
19
|
+
It is genuinely modeled on Ant Design: `treeData`, `fieldNames`, `treeCheckable`, `treeCheckStrictly`,
|
|
20
|
+
`showCheckedStrategy` (`SHOW_PARENT` / `SHOW_CHILD` / `SHOW_ALL`), `loadData`, `treeTitleRender`,
|
|
21
|
+
`maxTagCount`, `notFoundContent`. Markup carries `role="tree"` / `role="treeitem"` with
|
|
22
|
+
`aria-expanded` / `aria-selected` / `aria-multiselectable`. It is not the problem.
|
|
23
|
+
|
|
24
|
+
### 1b. `TreeList` is the problem — it promises a tree and delivers indentation
|
|
25
|
+
|
|
26
|
+
Verified against the source, the CSS (`src/styles/data-display-layout.css:282-334`) and its tests:
|
|
27
|
+
|
|
28
|
+
| Gap | Evidence |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| No nested data model | `items: TreeListItem[]` only — the caller must pre-flatten; there is no `children`. |
|
|
31
|
+
| No expand / collapse | No disclosure control anywhere in the component. NameThatUI calls this the **disclosure triangle**; an indented tree that expands is an **Outline View**. `TreeList` has neither. |
|
|
32
|
+
| No ARIA tree semantics | Only `aria-current`. No `role="tree"` / `role="treeitem"` / `aria-expanded` / `aria-level` / `aria-setsize` / `aria-posinset` / `aria-selected`. **Violates the mandatory WAI-ARIA APG gate.** |
|
|
33
|
+
| No keyboard | No arrows, Home/End, `*`, type-ahead. Rows are not focusable at all. |
|
|
34
|
+
| No selection contract | No `value` / `defaultValue` / `onValueChange`. **Violates the controlled-vocabulary rule (§2d).** |
|
|
35
|
+
| No `size`, no `ref`, no `className`/`...props` | Props are literally `{ items }`. **Violates §2d.** |
|
|
36
|
+
| Depth is uncapped but unstyled past 2 | Its own docs page says "Indentation is defined for depth 0-2, so flatten deeper branches". `tree-list-depth.test.tsx` asserts depth `5` sets the CSS var — which then renders at an indent nobody designed. |
|
|
37
|
+
| Missing every Ant affordance | no icons, no `showLine`, no drag & drop, no virtual scroll, no async `loadData`, no search/filter highlight, no `blockNode`, no DirectoryTree. |
|
|
38
|
+
|
|
39
|
+
**Conclusion:** the "tree components don't look like Ant Design" complaint is correct, and it is
|
|
40
|
+
localized: `TreeSelect` is fine, `TreeList` is a cosmetic indented list, and the standalone `Tree`
|
|
41
|
+
that every Ant-shaped app reaches for was never built.
|
|
42
|
+
|
|
43
|
+
## 2. GATE 0 ledger — `Tree` (required before any `src/components/**` addition)
|
|
44
|
+
|
|
45
|
+
| # | Criterion | Verdict | Why |
|
|
46
|
+
| --- | --- | --- | --- |
|
|
47
|
+
| C1 | Universal, not design-specific | **PASS** | File explorers, org charts, category pickers, permission trees, nav outlines. |
|
|
48
|
+
| C2 | Encapsulates reusable behavior | **PASS** | Roving tabindex, arrow/Home/End/`*` navigation, type-ahead, expand state, tri-state check propagation, async load. |
|
|
49
|
+
| C3 | Not composable from existing primitives | **PASS** | `Accordion` is single-level disclosure; `Timeline`/`NavList`/`ListRow` are flat. No primitive owns tree keyboard navigation on a page. |
|
|
50
|
+
| C4 | Single responsibility + controlled-vocabulary API | **PASS** | One job (render + navigate a hierarchy); maps cleanly onto the triads in §3. |
|
|
51
|
+
| C5 | Fully token-themeable | **PASS** | Indent, rail, glyph, row height all become `--tree-*` component tokens. |
|
|
52
|
+
| C6 | Earns the international contract | **PASS** | Needs correct APG semantics and RTL indentation; used everywhere. |
|
|
53
|
+
| C7 | Earns its bundle cost | **PASS** | Broad; also lets `TreeSelect` and `Tree` share one node renderer. |
|
|
54
|
+
|
|
55
|
+
**ALL PASS → `Tree` is a framework component.**
|
|
56
|
+
|
|
57
|
+
## 3. Normalized API — Ant Design name → godx controlled vocabulary
|
|
58
|
+
|
|
59
|
+
`Tree` mirrors Ant Design's *capabilities*, never its *prop names* where they conflict with
|
|
60
|
+
`docs/PROPS-VOCABULARY.md`. This mapping is the contract; do not invent a third spelling.
|
|
61
|
+
|
|
62
|
+
| Capability | Ant Design | **godx `Tree`** |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| Data | `treeData` | `treeData: TreeOptionProp[]` (reuse the existing `TreeOptionProp` + `TreeFieldNamesProp`) |
|
|
65
|
+
| Field remap | `fieldNames` | `fieldNames` (unchanged — already in the registry) |
|
|
66
|
+
| Selection | `selectedKeys` / `defaultSelectedKeys` / `onSelect` | `value` / `defaultValue` / `onValueChange` |
|
|
67
|
+
| Multi-select | `multiple` | `multiple` |
|
|
68
|
+
| Checkboxes | `checkedKeys` / `onCheck` | `checkedValues` / `defaultCheckedValues` / `onCheckedValuesChange` |
|
|
69
|
+
| Checkbox mode | `checkable` | `checkable` |
|
|
70
|
+
| Independent checks | `checkStrictly` | `checkStrictly` |
|
|
71
|
+
| Expansion | `expandedKeys` / `onExpand` | `expandedValues` / `defaultExpandedValues` / `onExpandedValuesChange` |
|
|
72
|
+
| Expand all | `defaultExpandAll` | `defaultExpandAll` |
|
|
73
|
+
| Async children | `loadData` | `loadData` (same signature as `TreeSelect`'s) |
|
|
74
|
+
| Node label render | `titleRender` | `titleRender` |
|
|
75
|
+
| Connector lines | `showLine` | `showLine` |
|
|
76
|
+
| Node icons | `showIcon` / `icon` | `showIcon`, per-node `icon` |
|
|
77
|
+
| Full-width row | `blockNode` | *dropped* — always full-width row; that is the only correct hit area under WCAG 2.5.8 |
|
|
78
|
+
| Disclosure glyph | `switcherIcon` | *dropped* — the glyph is a token (`--tree-switcher-*`), not a prop |
|
|
79
|
+
| Density | — | `size: xs \| sm \| lg` (`md` is the default, never `"default"`) |
|
|
80
|
+
| Directory variant | `<DirectoryTree>` | `variant="directory"` |
|
|
81
|
+
| Drag & drop | `draggable` | **out of scope for v1** — file a follow-up issue |
|
|
82
|
+
| Virtual scroll | `virtual` / `height` | **out of scope for v1** — cap with `ScrollArea`; file a follow-up issue |
|
|
83
|
+
|
|
84
|
+
Plus the house rules: forward `ref`, spread `...props`, accept `className` + `id`, export
|
|
85
|
+
`TreeProp` and `TreeProp as TreeProps` from `src/props/components/data-display.prop.ts`, and
|
|
86
|
+
**register it in `src/props/registry.ts`**.
|
|
87
|
+
|
|
88
|
+
## 4. Required semantics (WAI-ARIA APG "Tree View")
|
|
89
|
+
|
|
90
|
+
- Container `role="tree"`, `aria-multiselectable` when `multiple` or `checkable`.
|
|
91
|
+
- Each node `role="treeitem"` with `aria-level` (1-based), `aria-setsize`, `aria-posinset`,
|
|
92
|
+
`aria-selected`, and `aria-expanded` **only on nodes that have children**.
|
|
93
|
+
- Grouping wrapper `role="group"`.
|
|
94
|
+
- **Roving tabindex** — exactly one node has `tabIndex={0}`; all others `-1`.
|
|
95
|
+
- Keyboard: `↓`/`↑` next/previous *visible* node · `→` expand, then move to first child ·
|
|
96
|
+
`←` collapse, then move to parent · `Home`/`End` first/last visible · `Enter`/`Space` select
|
|
97
|
+
(or toggle the checkbox when `checkable`) · `*` expand all siblings at the current level ·
|
|
98
|
+
type-ahead jumps to the next node whose label starts with the typed characters.
|
|
99
|
+
- Under `dir="rtl"`, `→`/`←` swap meaning and indentation flips — logical CSS only
|
|
100
|
+
(`margin-inline-start`, `padding-inline-start`), never `ml-`/`pl-`/`left-`.
|
|
101
|
+
- Tri-state parent checkbox: checked / unchecked / **indeterminate** when only some descendants
|
|
102
|
+
are checked (skip propagation entirely when `checkStrictly`).
|
|
103
|
+
- Ships `tree.a11y.test.tsx` with `expectNoA11yViolations` — 0 violations.
|
|
104
|
+
|
|
105
|
+
## 5. Tokens (tier: `src/tokens/components/tree.css`, `@import`ed from `src/tokens/base.css`)
|
|
106
|
+
|
|
107
|
+
Names must pass `pnpm check:token-tiers` (`--{component}-{part}-{property}`):
|
|
108
|
+
`--tree-node-height` (from the `--control-height` tier — never a literal), `--tree-indent-width`,
|
|
109
|
+
`--tree-switcher-size`, `--tree-switcher-color`, `--tree-line-color`, `--tree-node-selected-background`,
|
|
110
|
+
`--tree-node-hover-background`, `--tree-icon-size`. Row hit area ≥ 24×24px (WCAG 2.5.8).
|
|
111
|
+
|
|
112
|
+
## 6. i18n keys (`src/i18n/messages/{en,vi,ja}.json`)
|
|
113
|
+
|
|
114
|
+
`tree.expand`, `tree.collapse`, `tree.loading`, `tree.empty`, `tree.selected` (sr-only status —
|
|
115
|
+
selection must never be colour-only, WCAG 1.4.1). Every `aria-label` goes through `t()`.
|
|
116
|
+
|
|
117
|
+
## 7. `TreeList` — what happened to it
|
|
118
|
+
|
|
119
|
+
**Superseded here, then REMOVED in 21.0.0.** The plan above ("stays exported, it has consumers")
|
|
120
|
+
was written while it still had them. It stopped: the last two call sites in `godx-task`
|
|
121
|
+
(`pages/tests/show.tsx`, `pages/documents/index.tsx`) moved to `Tree`, and a sweep of all four
|
|
122
|
+
consumer repos (godx-task, godx-chat, ql, platform) found none left. A superseded export that
|
|
123
|
+
nobody calls is not a compatibility surface, it is a second answer to a question that already has
|
|
124
|
+
one — and the catalog blurb it shipped with promised a "chevron + package icon" the component
|
|
125
|
+
never rendered.
|
|
126
|
+
|
|
127
|
+
So it is gone, with no deprecated shim: component, types, barrel entries, tests, frame, catalog
|
|
128
|
+
entry, `--tree-item-*` tokens and `.ui-tree-item` CSS. `Tree` is the replacement, and the Tree
|
|
129
|
+
catalog entry carries the migration (`id`->`value`, `title`->`label`, `depth`->nesting).
|
|
130
|
+
`check-mcp-pattern-imports.mjs` now denylists an import of, or JSX for, the removed export, the
|
|
131
|
+
same way it denylists `Stack`/`Inline`.
|
|
132
|
+
|
|
133
|
+
## 8. Shared code
|
|
134
|
+
|
|
135
|
+
Move `src/components/data-entry/tree-utils.ts` to a location both groups can import
|
|
136
|
+
(`src/lib/tree.ts`), re-export from the old path so `TreeSelect` keeps working, and have `Tree`
|
|
137
|
+
consume the same `normalizeTreeOptions` / `flattenVisibleTree` / `getDescendantValues`.
|
|
138
|
+
**One tree model, two surfaces** — do not fork the traversal logic.
|
|
139
|
+
|
|
140
|
+
## 9. Definition of done
|
|
141
|
+
|
|
142
|
+
Cheap gates, then this component's tests only:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
pnpm typecheck && pnpm lint && pnpm run audit \
|
|
146
|
+
&& pnpm check:prop-vocabulary && pnpm check:mcp-sync && pnpm check:mcp-orphans \
|
|
147
|
+
&& pnpm check:token-tiers && pnpm check:control-sizing && pnpm check:example-imports
|
|
148
|
+
pnpm vitest run src/components/data-display/__tests__ --maxWorkers=2
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`pnpm test` / bare `pnpm vitest run` are **forbidden** — the full suite is CI's job.
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Tree / hierarchical rows inside the real @godxjp/ui DataTable.
|
|
5
5
|
*
|
|
6
|
-
* The lib's `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* The lib's `Tree` owns the standalone tree view, but it is single-column — it
|
|
7
|
+
* cannot express a *tabular* hierarchy with per-row metrics, a parent-only
|
|
8
|
+
* disclosure twirl, and DataTable chrome (sticky header, density, sortable
|
|
9
|
+
* columns). So this composes the behaviour from real primitives:
|
|
10
10
|
*
|
|
11
11
|
* row model ........ flatten an org tree to rows carrying { depth, hasChildren,
|
|
12
12
|
* expanded }, then derive `visibleRows` from the open set.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui",
|
|
3
|
-
"version": "
|
|
4
|
-
"godxUiMcp": "
|
|
3
|
+
"version": "21.0.0",
|
|
4
|
+
"godxUiMcp": "21.0.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -351,9 +351,11 @@
|
|
|
351
351
|
"check:display-runtime-evidence": "node scripts/check-display-runtime-evidence.mjs",
|
|
352
352
|
"check:data-table-pagination-wrap": "node scripts/check-data-table-pagination-wrap.mjs",
|
|
353
353
|
"check:button-icon-xs": "node scripts/check-button-icon-xs.mjs",
|
|
354
|
+
"check:timeline-title-fill": "node scripts/check-timeline-title-fill.mjs",
|
|
355
|
+
"check:descriptions-label-value-step": "node scripts/check-descriptions-label-value-step.mjs",
|
|
354
356
|
"check:frame-contracts": "pnpm check:component-api-manifest && pnpm audit:component-cases && pnpm check:frame-coverage && pnpm check:frame-coverage-ledger && pnpm check:screen-reader-evidence && pnpm check:data-entry-owner-source && pnpm check:display-runtime-evidence",
|
|
355
357
|
"check:final-touch-rtl": "node scripts/check-final-touch-rtl.mjs",
|
|
356
|
-
"check:frame-runtime": "pnpm check:data-entry-frame-runtime && pnpm check:data-entry-touch-aria && pnpm check:layout-nav-frames && pnpm check:provider-feedback-query-runtime && pnpm check:layout-nav-closure && pnpm check:final-touch-rtl && pnpm check:data-table-pagination-wrap && pnpm check:button-icon-xs",
|
|
358
|
+
"check:frame-runtime": "pnpm check:data-entry-frame-runtime && pnpm check:data-entry-touch-aria && pnpm check:layout-nav-frames && pnpm check:provider-feedback-query-runtime && pnpm check:layout-nav-closure && pnpm check:final-touch-rtl && pnpm check:data-table-pagination-wrap && pnpm check:button-icon-xs && pnpm check:timeline-title-fill && pnpm check:descriptions-label-value-step",
|
|
357
359
|
"verify": "pnpm typecheck && pnpm lint && pnpm format && pnpm build && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:no-external-assets && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:frame-coverage && pnpm test",
|
|
358
360
|
"verify:static": "pnpm build && pnpm check:packed-public-contract && pnpm typecheck && pnpm typecheck:docs && pnpm lint && pnpm preview:build && pnpm check:example-imports && pnpm check:core-isolation && pnpm check:no-consumer-coupling && pnpm check:use-client && pnpm check:prop-vocabulary && pnpm check:token-tiers && pnpm check:token-scale-bypass && pnpm check:dist-tokens-resolve && pnpm check:no-hardcoded-geometry && pnpm check:no-hardcoded-css-values && pnpm check:no-inline-magic-numbers && pnpm check:no-tailwind-class-assertions && pnpm check:control-sizing && pnpm check:rtl && pnpm check:typography && pnpm check:mcp-lockstep && pnpm check:mcp-sync && pnpm check:doc-prop-existence && pnpm check:mcp-catalog-coverage && pnpm check:mcp-orphans && pnpm check:mcp-pattern-imports && pnpm check:audit-sync && pnpm check:mcp-prop-sync && pnpm check:contrast && pnpm check:visual-audit && pnpm test",
|
|
359
361
|
"verify:ci": "pnpm verify:ci:static && pnpm check:frame-contracts && pnpm test",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
export type TreeListItem = {
|
|
3
|
-
id: string;
|
|
4
|
-
title: ReactNode;
|
|
5
|
-
description?: ReactNode;
|
|
6
|
-
depth?: number;
|
|
7
|
-
active?: boolean;
|
|
8
|
-
badge?: ReactNode;
|
|
9
|
-
};
|
|
10
|
-
export type TreeListProps = {
|
|
11
|
-
items: TreeListItem[];
|
|
12
|
-
};
|
|
13
|
-
export declare function TreeList({ items }: TreeListProps): import("react").JSX.Element;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Badge } from "./badge.js";
|
|
4
|
-
function TreeList({ items }) {
|
|
5
|
-
return /* @__PURE__ */ jsx("ul", { className: "ui-tree-list", children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
6
|
-
"li",
|
|
7
|
-
{
|
|
8
|
-
className: "ui-tree-item",
|
|
9
|
-
"data-active": item.active ? "true" : void 0,
|
|
10
|
-
"data-depth": Math.max(0, item.depth ?? 0),
|
|
11
|
-
style: { "--tree-item-depth": Math.max(0, item.depth ?? 0) },
|
|
12
|
-
"aria-current": item.active ? "true" : void 0,
|
|
13
|
-
children: [
|
|
14
|
-
/* @__PURE__ */ jsxs("div", { className: "ui-tree-item-body", children: [
|
|
15
|
-
/* @__PURE__ */ jsx("div", { className: "ui-tree-item-title", children: item.title }),
|
|
16
|
-
item.description ? /* @__PURE__ */ jsx("div", { className: "ui-tree-item-description", children: item.description }) : null
|
|
17
|
-
] }),
|
|
18
|
-
item.badge != null ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: item.badge }) : null
|
|
19
|
-
]
|
|
20
|
-
},
|
|
21
|
-
item.id
|
|
22
|
-
)) });
|
|
23
|
-
}
|
|
24
|
-
export {
|
|
25
|
-
TreeList
|
|
26
|
-
};
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Badge,
|
|
3
|
-
Card,
|
|
4
|
-
CardContent,
|
|
5
|
-
CardDescription,
|
|
6
|
-
CardHeader,
|
|
7
|
-
CardTitle,
|
|
8
|
-
EmptyState,
|
|
9
|
-
TreeList,
|
|
10
|
-
} from "@godxjp/ui/data-display";
|
|
11
|
-
import { Flex, PageContainer } from "@godxjp/ui/layout";
|
|
12
|
-
import { FolderTree } from "lucide-react";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* TreeList — a flat array rendered as an indented hierarchy; depth is data-driven
|
|
16
|
-
* (never nest DOM). active highlights a row (aria-current); badge surfaces a
|
|
17
|
-
* secondary label. Indentation is defined for depth 0-2, so flatten deeper
|
|
18
|
-
* branches before rendering. Composed only from real @godxjp/ui components.
|
|
19
|
-
*/
|
|
20
|
-
const accounts = [
|
|
21
|
-
{ id: "1000", title: "資産", depth: 0, badge: "親科目" },
|
|
22
|
-
{ id: "1100", title: "流動資産", depth: 1, description: "1年以内に現金化" },
|
|
23
|
-
{
|
|
24
|
-
id: "1110",
|
|
25
|
-
title: "現金及び預金",
|
|
26
|
-
description: "普通・当座・小口",
|
|
27
|
-
depth: 2,
|
|
28
|
-
badge: "3 口座",
|
|
29
|
-
active: true,
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
id: "1120",
|
|
33
|
-
title: "売掛金",
|
|
34
|
-
description: "得意先への未回収債権",
|
|
35
|
-
depth: 2,
|
|
36
|
-
badge: (
|
|
37
|
-
<Badge variant="outline" tone="warning">
|
|
38
|
-
要確認
|
|
39
|
-
</Badge>
|
|
40
|
-
),
|
|
41
|
-
},
|
|
42
|
-
{ id: "2000", title: "負債", depth: 0, badge: "親科目" },
|
|
43
|
-
{ id: "2100", title: "流動負債", depth: 1, description: "1年以内に支払" },
|
|
44
|
-
{ id: "2110", title: "買掛金", depth: 2, badge: "12 件" },
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
// Independent data: active is allowed on any depth, including a top-level parent.
|
|
48
|
-
const departments = [
|
|
49
|
-
{ id: "d0", title: "本社", depth: 0, active: true, badge: "選択中" },
|
|
50
|
-
{ id: "d1", title: "営業部", depth: 1, description: "首都圏・関西" },
|
|
51
|
-
{ id: "d2", title: "開発部", depth: 1, description: "プロダクト・基盤" },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
export default function Demo() {
|
|
55
|
-
return (
|
|
56
|
-
<PageContainer
|
|
57
|
-
title="TreeList"
|
|
58
|
-
subtitle="Hierarchical list · depth lives in the data, not the DOM"
|
|
59
|
-
>
|
|
60
|
-
<Flex direction="col" gap="lg">
|
|
61
|
-
<Card>
|
|
62
|
-
<CardHeader>
|
|
63
|
-
<CardTitle level={2}>勘定科目ツリー</CardTitle>
|
|
64
|
-
<CardDescription>
|
|
65
|
-
Pre-filter server-side; each item still carries its depth (0-2). An active leaf
|
|
66
|
-
carries aria-current; badges accept a string or a nested Badge node.
|
|
67
|
-
</CardDescription>
|
|
68
|
-
</CardHeader>
|
|
69
|
-
<CardContent>
|
|
70
|
-
<TreeList items={accounts} />
|
|
71
|
-
</CardContent>
|
|
72
|
-
</Card>
|
|
73
|
-
|
|
74
|
-
<Card>
|
|
75
|
-
<CardHeader>
|
|
76
|
-
<CardTitle level={2}>組織ツリー(親を選択中)</CardTitle>
|
|
77
|
-
<CardDescription>
|
|
78
|
-
active is data-driven and works at any depth. Here the depth-0 parent is the current
|
|
79
|
-
row.
|
|
80
|
-
</CardDescription>
|
|
81
|
-
</CardHeader>
|
|
82
|
-
<CardContent>
|
|
83
|
-
<TreeList items={departments} />
|
|
84
|
-
</CardContent>
|
|
85
|
-
</Card>
|
|
86
|
-
|
|
87
|
-
<Card>
|
|
88
|
-
<CardHeader>
|
|
89
|
-
<CardTitle level={2}>空の状態</CardTitle>
|
|
90
|
-
<CardDescription>
|
|
91
|
-
An empty items={"{[]}"} array renders an empty list. Pair it with an EmptyState
|
|
92
|
-
placeholder.
|
|
93
|
-
</CardDescription>
|
|
94
|
-
</CardHeader>
|
|
95
|
-
<CardContent>
|
|
96
|
-
<TreeList items={[]} />
|
|
97
|
-
<EmptyState
|
|
98
|
-
icon={FolderTree}
|
|
99
|
-
title="科目がありません"
|
|
100
|
-
description="フィルター条件に一致する勘定科目が見つかりませんでした。"
|
|
101
|
-
/>
|
|
102
|
-
</CardContent>
|
|
103
|
-
</Card>
|
|
104
|
-
</Flex>
|
|
105
|
-
</PageContainer>
|
|
106
|
-
);
|
|
107
|
-
}
|