@godxjp/ui 31.4.0 → 31.6.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/agent/START-HERE.md +6 -6
- package/agent/components/BranchScopePicker.json +5 -0
- package/agent/components/Cascader.json +1 -1
- package/agent/components/CodeBlock.json +7 -1
- package/agent/components/DataTable.json +2 -2
- package/agent/components/InfiniteQueryState.json +6 -1
- package/agent/components/OrgChart.json +59 -0
- package/agent/components/RangeTimeline.json +6 -0
- package/agent/components/RecordPicker.json +10 -0
- package/agent/components/Transfer.json +5 -0
- package/agent/components/Tree.json +21 -4
- package/agent/components/TreeSelect.json +1 -1
- package/agent/components-index.json +5 -0
- package/agent/components.json +123 -10
- package/agent/index.json +7 -7
- package/agent/llms.txt +7 -7
- package/agent/tokens.json +114 -0
- package/dist/components/data-display/code-block.js +90 -4
- package/dist/components/data-display/data-table.d.ts +3 -0
- package/dist/components/data-display/data-table.js +415 -370
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/org-chart.d.ts +5 -0
- package/dist/components/data-display/org-chart.js +169 -0
- package/dist/components/data-display/range-timeline.d.ts +20 -0
- package/dist/components/data-display/range-timeline.js +217 -197
- package/dist/components/data-display/tree.js +179 -23
- package/dist/components/data-entry/branch-scope-picker.d.ts +1 -0
- package/dist/components/data-entry/branch-scope-picker.js +2 -1
- package/dist/components/data-entry/cascader.js +4 -5
- package/dist/components/data-entry/record-picker.d.ts +2 -0
- package/dist/components/data-entry/record-picker.js +22 -3
- package/dist/components/data-entry/transfer.d.ts +1 -1
- package/dist/components/data-entry/transfer.js +5 -2
- package/dist/components/data-entry/tree-select.js +14 -5
- package/dist/components/general/typography.d.ts +32 -0
- package/dist/components/general/typography.js +11 -2
- package/dist/components/query/infinite-query-state.d.ts +1 -1
- package/dist/components/query/infinite-query-state.js +2 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +26 -2
- package/dist/i18n/messages/ja.json +17 -2
- package/dist/i18n/messages/vi.json +17 -2
- package/dist/lib/hooks.d.ts +8 -4
- package/dist/lib/hooks.js +5 -2
- package/dist/lib/tree.d.ts +23 -0
- package/dist/lib/tree.js +29 -0
- package/dist/props/components/data-display.prop.d.ts +72 -3
- package/dist/props/components/data-entry.prop.d.ts +31 -4
- package/dist/props/components/query.prop.d.ts +8 -1
- package/dist/props/registry.d.ts +63 -6
- package/dist/props/registry.js +90 -4
- package/dist/props/vocabulary/data.prop.d.ts +32 -2
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/styles/data-display-layout.css +225 -0
- package/dist/styles/layers.json +14 -1
- package/dist/styles/table-layout.css +16 -1
- package/dist/tokens/base.css +1 -0
- package/dist/tokens/components/org-chart.css +27 -0
- package/dist/tokens/components/tree.css +2 -0
- package/docs/FRAME-COVERAGE-REPORT.md +3 -2
- package/docs/data-display/code-block.tsx +27 -0
- package/docs/data-display/data-table/examples/server-paged.tsx +23 -0
- package/docs/data-display/data-table/index.md +2 -0
- package/docs/data-display/org-chart.tsx +165 -0
- package/docs/data-display/timeline.tsx +33 -0
- package/docs/data-display/tree.tsx +154 -0
- package/docs/data-entry/branch-scope-picker.tsx +6 -1
- package/docs/data-entry/record-picker.tsx +1 -0
- package/docs/data-entry/transfer.tsx +1 -0
- package/docs/i18n/messages/en.json +19 -0
- package/docs/i18n/messages/ja.json +18 -0
- package/docs/i18n/messages/vi.json +18 -0
- package/docs/navigation/tabs.tsx +17 -15
- package/docs/query/data-state.tsx +2 -4
- package/docs/query/infinite-query-state.tsx +5 -1
- package/docs/roadmap/tree-components.md +2 -1
- package/docs/showcase/table-view-tabs.tsx +1 -1
- package/package.json +2 -2
- package/scripts/ui-audit.mjs +15 -5
package/agent/START-HERE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
You are about to write code against a design system you did not author. This file is the whole
|
|
4
4
|
contract. Read it before you write JSX.
|
|
5
5
|
|
|
6
|
-
**This catalog describes `@godxjp/ui` 31.
|
|
6
|
+
**This catalog describes `@godxjp/ui` 31.6.0.** If the project you are editing has a different
|
|
7
7
|
version in its `package.json`, read the pinned catalog for THAT version instead
|
|
8
8
|
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
|
|
9
9
|
not exist yet; older, and it hides props that do. Neither failure announces itself.
|
|
@@ -47,19 +47,19 @@ Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `li
|
|
|
47
47
|
task is a task** — "build a settings page", "confirm a destructive delete", "a list page with
|
|
48
48
|
filters" — start HERE, not at the components. Then fetch `patterns/<name>.json` for complete,
|
|
49
49
|
copy-paste-ready code. A component index answers "does X exist"; it cannot answer "build Y".
|
|
50
|
-
1. `components-index.json` — 47 KB, all
|
|
50
|
+
1. `components-index.json` — 47 KB, all 177 components as name + group +
|
|
51
51
|
tagline. Read this when you already know the SHAPE you need. Each entry may carry `absorbed`:
|
|
52
52
|
names that **do not exist** and map to it — `Combobox`, `Autocomplete`, `CountrySelect` and
|
|
53
53
|
`SearchSelect` are all `Select`. If you are about to hand-roll something, search this field
|
|
54
54
|
first; it exists because that is the mistake.
|
|
55
|
-
2. `components/<Name>.json` — one file per component (1 KB–
|
|
55
|
+
2. `components/<Name>.json` — one file per component (1 KB–36 KB, median 6 KB), carrying its props,
|
|
56
56
|
its `importPath`, and its examples. Fetch only the handful you picked in step 1.
|
|
57
57
|
3. `rules.json` — 50 cardinal rules. The ones about raw HTML and hardcoded colour are not
|
|
58
58
|
style advice.
|
|
59
|
-
4. `tokens.json` —
|
|
59
|
+
4. `tokens.json` — 2099 design tokens, each tagged with its `tier`. **If you were handed a
|
|
60
60
|
brand, read the 211 `foundation` entries first** — `--primary`, `--background`,
|
|
61
61
|
`--radius`, `--font-size-base` are the handful everything else derives from. The
|
|
62
|
-
|
|
62
|
+
1784 `component` entries are per-part knobs; reach for one only when a role is
|
|
63
63
|
right everywhere except one component.
|
|
64
64
|
5. `anti-ai-tells.json` — 26 shapes that make generated UI look generated, each with the
|
|
65
65
|
fix. Read before you reach for a gradient hero or a wall of coloured chips.
|
|
@@ -145,7 +145,7 @@ has stopped following the brand.
|
|
|
145
145
|
|---|---|---|---|
|
|
146
146
|
| `foundation` | 211 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** Handed a brand colour, this is where it goes: `:root { --primary: <H> <S>% <L>%; }` (HSL components, no `hsl()` wrapper) |
|
|
147
147
|
| `semantic` | 104 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
|
|
148
|
-
| `component` |
|
|
148
|
+
| `component` | 1784 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
|
|
149
149
|
|
|
150
150
|
A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
|
|
151
151
|
value, so the real default is computed where the element paints it. Set it and yours wins.
|
|
@@ -59,6 +59,11 @@
|
|
|
59
59
|
"name": "searchable",
|
|
60
60
|
"type": "boolean"
|
|
61
61
|
},
|
|
62
|
+
{
|
|
63
|
+
"description": "antd `notFoundContent` — shown when the branch SEARCH matches nothing (default: localized `dataEntry.branchScope.noMatches`). An empty `branches` list is `empty`'s job, not this.",
|
|
64
|
+
"name": "notFoundContent",
|
|
65
|
+
"type": "ReactNode"
|
|
66
|
+
},
|
|
62
67
|
{
|
|
63
68
|
"description": "Override the localized radio labels (e.g. domain wording like 全店舗).",
|
|
64
69
|
"name": "allLabel / selectedLabel",
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
"type": "\"SHOW_CHILD\" | \"SHOW_PARENT\""
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
|
-
"description": "antd `loadData` — lazy children. Called
|
|
155
|
+
"description": "antd `loadData` — lazy children. Called when a branch that has no children and isLeaf !== true is expanded, and never again once its promise resolves; push the fetched children into options. A rejected promise is forgotten, so the next activation of the branch asks again (gh#1041).",
|
|
156
156
|
"name": "loadData",
|
|
157
157
|
"type": "(selectedOptions: TreeOptionProp[]) => void | Promise<void>"
|
|
158
158
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { CodeBlock } from \"@godxjp/ui/data-display\";\n\n<CodeBlock maxHeight=\"sm\" language=\"json\" aria-label=\"Response body\">{body}</CodeBlock>\n<CodeBlock size=\"xs\" maxHeight=\"md\" aria-label=\"Console\">{consoleText}</CodeBlock>",
|
|
2
|
+
"example": "import { CodeBlock } from \"@godxjp/ui/data-display\";\n\n<CodeBlock maxHeight=\"sm\" language=\"json\" aria-label=\"Response body\">{body}</CodeBlock>\n<CodeBlock size=\"xs\" maxHeight=\"md\" aria-label=\"Console\">{consoleText}</CodeBlock>\n<CodeBlock copyable language=\"bash\">pnpm add @godxjp/ui</CodeBlock>",
|
|
3
3
|
"group": "data-display",
|
|
4
4
|
"importPath": "@godxjp/ui/data-display",
|
|
5
5
|
"name": "CodeBlock",
|
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
"name": "language",
|
|
32
32
|
"type": "string"
|
|
33
33
|
},
|
|
34
|
+
{
|
|
35
|
+
"description": "antd Typography's `copyable`, same name and semantics (gh#1032): a copy button in the block's inline-end corner. `true` copies the block's text content (highlighter spans included); `text` overrides it. The block reserves the button's column, the confirmed state is announced politely, and `onCopy` fires only after the clipboard write succeeds.",
|
|
36
|
+
"name": "copyable",
|
|
37
|
+
"type": "boolean | { text?: string | (() => string | Promise<string>); onCopy?: (event) => void; tooltips?: ReactNode | [ReactNode, ReactNode] | false; icon?: ReactNode | [ReactNode, ReactNode]; format?: \"text/plain\" | \"text/html\"; tabIndex?: number }"
|
|
38
|
+
},
|
|
34
39
|
{
|
|
35
40
|
"description": "Extra classes on the `pre`.",
|
|
36
41
|
"name": "className",
|
|
@@ -52,6 +57,7 @@
|
|
|
52
57
|
"DO cap the height of anything that can be large (a 64 KB response body, a console dump) with `maxHeight`; the page keeps its rhythm and the block scrolls.",
|
|
53
58
|
"DON'T hand-roll `<pre className=\"max-h-64 overflow-auto rounded bg-muted p-2 whitespace-pre-wrap\">`: every one of those values is a copy of a token this component reads.",
|
|
54
59
|
"DON'T reach for `Text as=\"code\"` for a block: that is inline monospace with no wrapping axis. Use `Text as=\"code\"` for an identifier inside a sentence, CodeBlock for a block.",
|
|
60
|
+
"DO use `copyable` for a command or snippet the reader will paste (gh#1032). DON'T hand-roll a copy Button next to or over a CodeBlock: `copyable` owns the clipboard call, the confirmed state, the placement and the polite announcement.",
|
|
55
61
|
"DON'T use CodeBlock for a single value in a Descriptions row: `Descriptions.Item mono` owns that (it breaks the value, not the row).",
|
|
56
62
|
"SYNTAX COLOUR (gh#784): CodeBlock does not highlight, but it DOES own the palette. Tag each span from your highlighter with `data-code-token` — the twelve names are Shiki createCssVariablesTheme's verbatim (comment, keyword, string, string-expression, function, constant, parameter, punctuation, link, inserted, deleted, changed, plus the block foreground) — and the package colours them. DON'T put `style={{ color }}` or a palette `className` on the spans: both are visual overrides, and the colour is not the consumer's to choose. Retheme with the `--code-block-token-*-color` knobs, which are role-mirrors, so light and dark follow the theme with no second palette."
|
|
57
63
|
],
|
|
@@ -159,9 +159,9 @@
|
|
|
159
159
|
"type": "() => void"
|
|
160
160
|
},
|
|
161
161
|
{
|
|
162
|
-
"description": "Full row-selection configuration (antd rowSelection). Supersedes — and can be mixed with — selectable/selected/onSelectChange, which drive the same state. type:'radio' makes the column single-choice (no header checkbox at all). getCheckboxProps is the declared home for 'this row cannot be selected' (disabled) and for a per-row accessible name. preserveSelectedRowKeys keeps a key selected after its row leaves `data` (server paging / a filter), which is the only way a select-across-pages bulk action can be correct. selections adds bulk entries under the header checkbox (true = the built-in all · invert · none).",
|
|
162
|
+
"description": "Full row-selection configuration (antd rowSelection). Supersedes — and can be mixed with — selectable/selected/onSelectChange, which drive the same state. type:'radio' makes the column single-choice (no header checkbox at all). getCheckboxProps is the declared home for 'this row cannot be selected' (disabled) and for a per-row accessible name. preserveSelectedRowKeys keeps a key selected after its row leaves `data` (server paging / a filter), which is the only way a select-across-pages bulk action can be correct. selections adds bulk entries under the header checkbox (true = the built-in all · invert · none; a list mixes antd's DataTable.SELECTION_ALL / SELECTION_INVERT / SELECTION_NONE with custom entries in the order given). selectAllLabel names the header checkbox — say what it really selects (on a server-paged table: the page) instead of replacing it through columnTitle. matching (no antd equivalent; Gmail/Jira/GitHub) is the server-paged 'select all N matching' banner: once the whole page is ticked and total exceeds the page, a polite status above the header offers 'Select all N matching rows'; choosing it reports onSelectedChange(true) — send your FILTER, not the ids, for the bulk write — and while selected every row of any page shows ticked. Unticking a row or 'Clear selection' reports false. With matching set, the header checkbox defaults to 'Select all rows on this page'.",
|
|
163
163
|
"name": "rowSelection",
|
|
164
|
-
"type": "{ type?: 'checkbox'|'radio'; selectedRowKeys?: string[]; defaultSelectedRowKeys?: string[]; onChange?: (keys, rows) => void; getCheckboxProps?: (row) => { disabled?, 'aria-label'? }; preserveSelectedRowKeys?: boolean; selections?: true | { key, text, onSelect }[]; hideSelectAll?: boolean; columnTitle?: ReactNode }"
|
|
164
|
+
"type": "{ type?: 'checkbox'|'radio'; selectedRowKeys?: string[]; defaultSelectedRowKeys?: string[]; onChange?: (keys, rows) => void; getCheckboxProps?: (row) => { disabled?, 'aria-label'? }; preserveSelectedRowKeys?: boolean; selections?: true | ({ key, text, onSelect } | DataTable.SELECTION_ALL | DataTable.SELECTION_INVERT | DataTable.SELECTION_NONE)[]; hideSelectAll?: boolean; columnTitle?: ReactNode; selectAllLabel?: string; matching?: { total: number; selected: boolean; onSelectedChange: (selected: boolean) => void } }"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"description": "Expandable detail rows (antd expandable). Supplying expandedRowRender adds a leading expand column before the selection column and renders the panel in a real <tr> spanning every column, so the table's grid semantics survive. rowExpandable gates the affordance per row; expandedRowKeys + onExpandedRowsChange make it controlled.",
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"name": "children",
|
|
28
28
|
"required": true,
|
|
29
29
|
"type": "(flat, helpers) => ReactNode"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"description": "Idle text of the built-in load-more button (default: localized `query.loadMore`, 「さらに読み込む」) — e.g. 「さらに表示」「さらに古い版を表示」. The button, its pending label and disabled-while-fetching stay the component's. Ignored when `loadMore` replaces the footer.",
|
|
33
|
+
"name": "loadMoreLabel",
|
|
34
|
+
"type": "ReactNode"
|
|
30
35
|
}
|
|
31
36
|
],
|
|
32
37
|
"related": [
|
|
@@ -43,7 +48,7 @@
|
|
|
43
48
|
"DO: Always pass `skeleton` (e.g. `<SkeletonTable />` or `<SkeletonStat />`). It shows on initial `isPending`, on refetch-after-error, and whenever `data` is absent. Never show a blank area while loading.",
|
|
44
49
|
"DO: Pass `empty` (an `<EmptyState>` node) to handle the zero-results case — without it the children render-prop is called with an empty array and you get a silent blank screen. Provide a custom `isEmpty` only when `TFlat` is not an array.",
|
|
45
50
|
"DO: Let errors remain cause-aware. Retry is automatic only for classified transient/network/5xx failures. Unknown errors do not get a blind retry unless `showRetry` or `onRetry` is explicitly supplied; a 401 is handled by the app-root `AuthExpiryProvider` (auto, once, skeleton + live region) or, without one, by the `onAuthError` sign-in button; raw backend/token text is never rendered.",
|
|
46
|
-
"DON'T: Hand-roll a load-more button. The component renders a default centered outline Button when `hasNextPage` is true.
|
|
51
|
+
"DON'T: Hand-roll a load-more button. The component renders a default centered outline Button when `hasNextPage` is true. Rename it with `loadMoreLabel` (keeps the pending state); replace it only via `loadMore` (custom node) or `showLoadMore={false}` (hide entirely). Never call `query.fetchNextPage()` outside the component for pagination.",
|
|
47
52
|
"DON'T: Use `InfiniteQueryState` for a `useQuery` result — it expects `UseInfiniteQueryResult` shape (`pages`, `hasNextPage`, `fetchNextPage`, `isFetchingNextPage`). For regular `useQuery` use `DataState` instead.",
|
|
48
53
|
"DON'T: Confuse the two generics: `TPage` is the raw page shape from the API, `TFlat` is what `flatten` returns (usually `TItem[]`). The `children` render-prop receives `TFlat`, not `TPage`. Pass `isEmpty` if `TFlat` is not a plain array so empty detection works correctly."
|
|
49
54
|
],
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"docPath": "data-display/org-chart.tsx",
|
|
3
|
+
"example": "import { Avatar, AvatarFallback, Badge, OrgChart } from \"@godxjp/ui/data-display\";\n\n<OrgChart\n label=\"Company org chart\"\n data={[\n {\n key: \"ceo\", name: \"Haruka Tanaka\", title: \"CEO\",\n avatar: <Avatar size=\"sm\"><AvatarFallback>HT</AvatarFallback></Avatar>,\n children: [\n { key: \"cto\", name: \"Kenji Watanabe\", title: \"CTO\" },\n { key: \"bot\", name: \"Review Agent\", title: \"Code review\", variant: \"agent\",\n extra: <Badge tone=\"success\">Running</Badge> },\n ],\n },\n ]}\n/>",
|
|
4
|
+
"group": "data-display",
|
|
5
|
+
"importPath": "@godxjp/ui/data-display",
|
|
6
|
+
"name": "OrgChart",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"description": "The hierarchy: { key, name, title?, avatar?, extra?, variant?: \"person\" | \"agent\", children? }. `key` is unique across the chart. `avatar` is usually an <Avatar>; `extra` a Badge or status.",
|
|
10
|
+
"name": "data",
|
|
11
|
+
"type": "OrgChartNodeProp[]"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Replace a box's content. The box, its border, the connectors and the keyboard stay the library's; the narrow Tree form uses it too.",
|
|
15
|
+
"name": "renderNode",
|
|
16
|
+
"type": "(node: OrgChartNodeProp) => ReactNode"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Accessible name of the role=\"tree\" (a plain string). Localized default \"Organization chart\".",
|
|
20
|
+
"name": "label",
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "DOM id of the root.",
|
|
25
|
+
"name": "id",
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"description": "Root class.",
|
|
30
|
+
"name": "className",
|
|
31
|
+
"type": "string"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"related": [
|
|
35
|
+
"Tree — the indented, collapsible outline. OrgChart renders it as its narrow form.",
|
|
36
|
+
"Avatar — the mark in each box.",
|
|
37
|
+
"Badge — a status in a box's `extra` slot."
|
|
38
|
+
],
|
|
39
|
+
"rules": [
|
|
40
|
+
2,
|
|
41
|
+
6,
|
|
42
|
+
23,
|
|
43
|
+
44,
|
|
44
|
+
45
|
|
45
|
+
],
|
|
46
|
+
"storyPath": "data-display/OrgChart.stories.tsx",
|
|
47
|
+
"tagline": "An organization chart: boxes (avatar, name, title, extra) joined by CSS connector lines, top-down; `agent` nodes are dashed. Scrolls horizontally in its own named region when wider than its container, and turns into an indented Tree when the CONTAINER is under 40rem. APG tree view (tree/treeitem/group, roving tabindex, arrow keys).",
|
|
48
|
+
"usage": [
|
|
49
|
+
"DO mark AI agents with `variant: \"agent\"` — the box is dashed AND its accessible name ends in a localized \"AI agent\", so the kind is never carried by the stroke alone.",
|
|
50
|
+
"DO give it the width it has; the breakpoint is a container query, so a chart in a narrow side panel switches to the Tree form on a wide screen too.",
|
|
51
|
+
"DO retune boxes and lines through the --org-chart-* tokens (node size, gaps, line width/colour, agent border style).",
|
|
52
|
+
"DON'T wrap it in your own overflow-x scroller — it owns its scroll region, which only becomes a named tab stop when the chart actually overflows.",
|
|
53
|
+
"DON'T use it for an outline users expand and collapse — that is Tree. OrgChart always shows every node."
|
|
54
|
+
],
|
|
55
|
+
"useCases": [
|
|
56
|
+
"A company or team org chart with people and AI agents side by side.",
|
|
57
|
+
"Reporting lines on an admin screen, falling back to an indented list in a narrow panel or on a phone."
|
|
58
|
+
]
|
|
59
|
+
}
|
|
@@ -64,6 +64,12 @@
|
|
|
64
64
|
"description": "Fires with the next expanded parent ids when a disclosure is toggled, for controlled and uncontrolled timelines alike.",
|
|
65
65
|
"name": "onExpandedValuesChange",
|
|
66
66
|
"type": "(values: string[]) => void"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"defaultValue": "false",
|
|
70
|
+
"description": "antd Table `sticky` — keep the axis header (bands + ticks) on screen while the PAGE scrolls a long schedule. `offsetHeader` is px from the top of the scrolling viewport (the height of a fixed app topbar). The header moves out of the horizontal scroller and follows its scrollLeft; the section becomes `overflow: clip` and the body scroller takes the keyboard tab stop. Like antd, it needs no clipping ancestor between the timeline and the page scroller: `Card` is `overflow: hidden`, so a sticky timeline goes in the page as its own section, not inside a Card. antd's `offsetScroll` / `getContainer` (sticky horizontal scrollbar) are not ported.",
|
|
71
|
+
"name": "sticky",
|
|
72
|
+
"type": "boolean | { offsetHeader?: number }"
|
|
67
73
|
}
|
|
68
74
|
],
|
|
69
75
|
"rules": [],
|
|
@@ -82,6 +82,16 @@
|
|
|
82
82
|
"name": "dialogTitle",
|
|
83
83
|
"type": "string"
|
|
84
84
|
},
|
|
85
|
+
{
|
|
86
|
+
"description": "antd `notFoundContent` — shown when the search finds nothing, in the dropdown shape and the dialog alike (default: localized `dataEntry.recordPicker.empty`). Say WHAT has no match, e.g. 「該当するファイルはありません」.",
|
|
87
|
+
"name": "notFoundContent",
|
|
88
|
+
"type": "ReactNode"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"description": "Text of the dialog's load-more button (default: localized `dataEntry.recordPicker.more`). Only the label — the button still appears only while the server returns a `nextCursor`.",
|
|
92
|
+
"name": "loadMoreLabel",
|
|
93
|
+
"type": "ReactNode"
|
|
94
|
+
},
|
|
85
95
|
{
|
|
86
96
|
"description": "Control height of the trigger, on the shared control ladder.",
|
|
87
97
|
"name": "size",
|
|
@@ -109,6 +109,11 @@
|
|
|
109
109
|
"name": "onSelectChange",
|
|
110
110
|
"type": "(sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void"
|
|
111
111
|
},
|
|
112
|
+
{
|
|
113
|
+
"description": "antd `locale`, ported for `notFoundContent` only: what an empty or search-emptied pane shows (default: localized `dataEntry.transfer.empty`). A `[source, target]` pair sets each pane separately, as in antd.",
|
|
114
|
+
"name": "locale",
|
|
115
|
+
"type": "{ notFoundContent?: ReactNode | [ReactNode, ReactNode] }"
|
|
116
|
+
},
|
|
112
117
|
{
|
|
113
118
|
"description": "Fires when items move between panels; you own `targetKeys` state.",
|
|
114
119
|
"name": "onValueChange",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"type": "boolean"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
"description": "Lazy children (antd `loadData`). Called
|
|
89
|
+
"description": "Lazy children (antd `loadData`). Called when a branch with no `children` and `isLeaf !== true` is expanded, and never again once its promise RESOLVES; a Skeleton row and `aria-busy` cover the wait. Push the fetched children into `treeData`. A REJECTED promise is not a load (rc-tree, gh#1041): the branch folds back shut (uncontrolled expansion) and the next expand asks again, up to 10 attempts.",
|
|
90
90
|
"name": "loadData",
|
|
91
91
|
"type": "(node: TreeNodeProp) => void | Promise<void>"
|
|
92
92
|
},
|
|
@@ -95,6 +95,22 @@
|
|
|
95
95
|
"name": "titleRender",
|
|
96
96
|
"type": "(node: TreeNodeProp) => ReactNode"
|
|
97
97
|
},
|
|
98
|
+
{
|
|
99
|
+
"description": "Highlight the nodes this returns true for (antd `filterTreeNode`, gh#1043) — the match of a search box above the tree. Matching rows are MARKED, not hidden: `data-filter-node=\"true\"`, the label in `--tree-node-filter-foreground` (default `hsl(var(--primary))`) at the medium weight, plus sr-only \"matches the filter\" text. Outline, keyboard and ARIA are unchanged. To also open the branches that hold a match, drive `expandedValues`.",
|
|
100
|
+
"name": "filterTreeNode",
|
|
101
|
+
"type": "(node: TreeNodeProp) => boolean"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"description": "Viewport height in px (antd `height`, gh#1042). The tree scrolls inside it and, unless `virtual={false}`, renders only the rows in view plus a small overscan — the windowed rows stay a flat run of treeitems whose `aria-level`/`aria-setsize`/`aria-posinset` still describe the whole outline. Rows must share one height (the `size` tier).",
|
|
105
|
+
"name": "height",
|
|
106
|
+
"type": "number"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"defaultValue": "true",
|
|
110
|
+
"description": "Set `false` to keep the `height` viewport but render every row (antd `virtual`).",
|
|
111
|
+
"name": "virtual",
|
|
112
|
+
"type": "boolean"
|
|
113
|
+
},
|
|
98
114
|
{
|
|
99
115
|
"defaultValue": "false",
|
|
100
116
|
"description": "Draw the connector rails between a parent and its children (antd `showLine`). Off by default — a rail is chrome, and chrome defaults quiet.",
|
|
@@ -152,7 +168,7 @@
|
|
|
152
168
|
"TreeSelect — the same hierarchy INSIDE a Popover, as a form field. Use TreeSelect when the answer is a value in a form; use Tree when the hierarchy itself is the page.",
|
|
153
169
|
"Cascader — a path picker across columns. Use it when the user walks one path to a leaf; use Tree when several branches are open at once.",
|
|
154
170
|
"Accordion — single-level disclosure with rich panel content. It is not a hierarchy and has no tree keyboard model.",
|
|
155
|
-
"ScrollArea —
|
|
171
|
+
"ScrollArea — not needed around Tree: pass `height`, and the tree is its own (windowed) scroll viewport."
|
|
156
172
|
],
|
|
157
173
|
"rules": [
|
|
158
174
|
2,
|
|
@@ -172,8 +188,9 @@
|
|
|
172
188
|
"DON'T nest a Button, Checkbox, Link or any focusable control inside a node label. A tree item owns exactly ONE tab stop; the disclosure triangle and the tick box are decorative glyphs for that reason. Put row actions in a sibling column outside the tree, or open a detail pane on selection.",
|
|
173
189
|
"DON'T hand-roll an indented `<ul>` (or a NavList / ListRow stack with a per-depth margin) for a hierarchy. A flat indented list only LOOKS like a tree: no expand/collapse, no `role=\"tree\"`, no keyboard model, no selection contract. `TreeList` was exactly that list and was REMOVED in 21.0.0 — Tree is what replaced it, and it is the one to reach for whenever nodes expand, collapse or are keyboard-navigated.",
|
|
174
190
|
"DO pass `divided` when the tree IS the navigation of a page — a wiki/document outline or a section index sitting in a `Card` (`Card` > `CardContent flush` > `Tree divided`). Without a rule the rows run together and the outline reads as one block; with it, it reads as the ruled list ListRow and Table already give a flat list. Retint it per theme with `--tree-divider-color`, never with a per-page utility class.",
|
|
175
|
-
"DO
|
|
176
|
-
"DO push fetched children into `treeData` from `loadData`; the tree calls it once per node and shows a Skeleton row until the data lands."
|
|
191
|
+
"DO pass `height` for a long tree (antd `height` + `virtual`): the tree scrolls inside that height and keeps only the rows in view in the DOM, so a 421-child level renders a few dozen rows. Do not wrap it in `ScrollArea` as well — the tree is its own viewport.",
|
|
192
|
+
"DO push fetched children into `treeData` from `loadData`; the tree calls it once per node that loads and shows a Skeleton row until the data lands. Reject the promise on failure — the branch folds shut and the next expand retries.",
|
|
193
|
+
"DON'T wait for a paged \"load more\" node — antd's Tree has none, and `height` covers a long list. If the API itself is paged, append a leaf node such as `{ value: `${parent}::more`, label: t(\"…load more\"), isLeaf: true }` to the loaded children and fetch the next page from `onValueChange` when it is selected: it is a real treeitem, so it is keyboard-reachable and announced."
|
|
177
194
|
],
|
|
178
195
|
"useCases": [
|
|
179
196
|
"A permission tree: modules → resources → actions with tri-state checkboxes, where ticking a module ticks everything under it and a partly-granted module shows the dash.",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"type": "boolean"
|
|
180
180
|
},
|
|
181
181
|
{
|
|
182
|
-
"description": "antd `loadData` — lazy children. Called
|
|
182
|
+
"description": "antd `loadData` — lazy children. Called when a node that has no children and isLeaf !== true is expanded, and never again once its promise resolves; push the fetched children into treeData. A rejected promise folds the branch shut and the next expand asks again, up to 10 attempts (rc-tree, gh#1041). Such a node still reads as expandable (aria-expanded + a working expander).",
|
|
183
183
|
"name": "loadData",
|
|
184
184
|
"type": "(node: TreeOptionProp) => void | Promise<void>"
|
|
185
185
|
},
|
|
@@ -886,6 +886,11 @@
|
|
|
886
886
|
"name": "ThoughtChain",
|
|
887
887
|
"tagline": "The assistant's reasoning, step by step (Ant Design X ThoughtChain): an ORDERED list of steps, each with an ordinal or a glyph, a status, and a body it can collapse — where Ant X's own step is a <div onClick> with no role and no aria-expanded."
|
|
888
888
|
},
|
|
889
|
+
{
|
|
890
|
+
"group": "data-display",
|
|
891
|
+
"name": "OrgChart",
|
|
892
|
+
"tagline": "An organization chart: boxes (avatar, name, title, extra) joined by CSS connector lines, top-down; `agent` nodes are dashed. Scrolls horizontally in its own named region when wider than its container, and turns into an indented Tree when the CONTAINER is under 40rem. APG tree view (tree/treeitem/group, roving tabindex, arrow keys)."
|
|
893
|
+
},
|
|
889
894
|
{
|
|
890
895
|
"group": "data-entry",
|
|
891
896
|
"name": "Attachments",
|
package/agent/components.json
CHANGED
|
@@ -590,6 +590,12 @@
|
|
|
590
590
|
"description": "Fires with the next expanded parent ids when a disclosure is toggled, for controlled and uncontrolled timelines alike.",
|
|
591
591
|
"name": "onExpandedValuesChange",
|
|
592
592
|
"type": "(values: string[]) => void"
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
"defaultValue": "false",
|
|
596
|
+
"description": "antd Table `sticky` — keep the axis header (bands + ticks) on screen while the PAGE scrolls a long schedule. `offsetHeader` is px from the top of the scrolling viewport (the height of a fixed app topbar). The header moves out of the horizontal scroller and follows its scrollLeft; the section becomes `overflow: clip` and the body scroller takes the keyboard tab stop. Like antd, it needs no clipping ancestor between the timeline and the page scroller: `Card` is `overflow: hidden`, so a sticky timeline goes in the page as its own section, not inside a Card. antd's `offsetScroll` / `getContainer` (sticky horizontal scrollbar) are not ported.",
|
|
597
|
+
"name": "sticky",
|
|
598
|
+
"type": "boolean | { offsetHeader?: number }"
|
|
593
599
|
}
|
|
594
600
|
],
|
|
595
601
|
"rules": [],
|
|
@@ -3525,9 +3531,9 @@
|
|
|
3525
3531
|
"type": "() => void"
|
|
3526
3532
|
},
|
|
3527
3533
|
{
|
|
3528
|
-
"description": "Full row-selection configuration (antd rowSelection). Supersedes — and can be mixed with — selectable/selected/onSelectChange, which drive the same state. type:'radio' makes the column single-choice (no header checkbox at all). getCheckboxProps is the declared home for 'this row cannot be selected' (disabled) and for a per-row accessible name. preserveSelectedRowKeys keeps a key selected after its row leaves `data` (server paging / a filter), which is the only way a select-across-pages bulk action can be correct. selections adds bulk entries under the header checkbox (true = the built-in all · invert · none).",
|
|
3534
|
+
"description": "Full row-selection configuration (antd rowSelection). Supersedes — and can be mixed with — selectable/selected/onSelectChange, which drive the same state. type:'radio' makes the column single-choice (no header checkbox at all). getCheckboxProps is the declared home for 'this row cannot be selected' (disabled) and for a per-row accessible name. preserveSelectedRowKeys keeps a key selected after its row leaves `data` (server paging / a filter), which is the only way a select-across-pages bulk action can be correct. selections adds bulk entries under the header checkbox (true = the built-in all · invert · none; a list mixes antd's DataTable.SELECTION_ALL / SELECTION_INVERT / SELECTION_NONE with custom entries in the order given). selectAllLabel names the header checkbox — say what it really selects (on a server-paged table: the page) instead of replacing it through columnTitle. matching (no antd equivalent; Gmail/Jira/GitHub) is the server-paged 'select all N matching' banner: once the whole page is ticked and total exceeds the page, a polite status above the header offers 'Select all N matching rows'; choosing it reports onSelectedChange(true) — send your FILTER, not the ids, for the bulk write — and while selected every row of any page shows ticked. Unticking a row or 'Clear selection' reports false. With matching set, the header checkbox defaults to 'Select all rows on this page'.",
|
|
3529
3535
|
"name": "rowSelection",
|
|
3530
|
-
"type": "{ type?: 'checkbox'|'radio'; selectedRowKeys?: string[]; defaultSelectedRowKeys?: string[]; onChange?: (keys, rows) => void; getCheckboxProps?: (row) => { disabled?, 'aria-label'? }; preserveSelectedRowKeys?: boolean; selections?: true | { key, text, onSelect }[]; hideSelectAll?: boolean; columnTitle?: ReactNode }"
|
|
3536
|
+
"type": "{ type?: 'checkbox'|'radio'; selectedRowKeys?: string[]; defaultSelectedRowKeys?: string[]; onChange?: (keys, rows) => void; getCheckboxProps?: (row) => { disabled?, 'aria-label'? }; preserveSelectedRowKeys?: boolean; selections?: true | ({ key, text, onSelect } | DataTable.SELECTION_ALL | DataTable.SELECTION_INVERT | DataTable.SELECTION_NONE)[]; hideSelectAll?: boolean; columnTitle?: ReactNode; selectAllLabel?: string; matching?: { total: number; selected: boolean; onSelectedChange: (selected: boolean) => void } }"
|
|
3531
3537
|
},
|
|
3532
3538
|
{
|
|
3533
3539
|
"description": "Expandable detail rows (antd expandable). Supplying expandedRowRender adds a leading expand column before the selection column and renders the panel in a real <tr> spanning every column, so the table's grid semantics survive. rowExpandable gates the affordance per row; expandedRowKeys + onExpandedRowsChange make it controlled.",
|
|
@@ -4808,7 +4814,7 @@
|
|
|
4808
4814
|
]
|
|
4809
4815
|
},
|
|
4810
4816
|
{
|
|
4811
|
-
"example": "import { CodeBlock } from \"@godxjp/ui/data-display\";\n\n<CodeBlock maxHeight=\"sm\" language=\"json\" aria-label=\"Response body\">{body}</CodeBlock>\n<CodeBlock size=\"xs\" maxHeight=\"md\" aria-label=\"Console\">{consoleText}</CodeBlock>",
|
|
4817
|
+
"example": "import { CodeBlock } from \"@godxjp/ui/data-display\";\n\n<CodeBlock maxHeight=\"sm\" language=\"json\" aria-label=\"Response body\">{body}</CodeBlock>\n<CodeBlock size=\"xs\" maxHeight=\"md\" aria-label=\"Console\">{consoleText}</CodeBlock>\n<CodeBlock copyable language=\"bash\">pnpm add @godxjp/ui</CodeBlock>",
|
|
4812
4818
|
"group": "data-display",
|
|
4813
4819
|
"importPath": "@godxjp/ui/data-display",
|
|
4814
4820
|
"name": "CodeBlock",
|
|
@@ -4840,6 +4846,11 @@
|
|
|
4840
4846
|
"name": "language",
|
|
4841
4847
|
"type": "string"
|
|
4842
4848
|
},
|
|
4849
|
+
{
|
|
4850
|
+
"description": "antd Typography's `copyable`, same name and semantics (gh#1032): a copy button in the block's inline-end corner. `true` copies the block's text content (highlighter spans included); `text` overrides it. The block reserves the button's column, the confirmed state is announced politely, and `onCopy` fires only after the clipboard write succeeds.",
|
|
4851
|
+
"name": "copyable",
|
|
4852
|
+
"type": "boolean | { text?: string | (() => string | Promise<string>); onCopy?: (event) => void; tooltips?: ReactNode | [ReactNode, ReactNode] | false; icon?: ReactNode | [ReactNode, ReactNode]; format?: \"text/plain\" | \"text/html\"; tabIndex?: number }"
|
|
4853
|
+
},
|
|
4843
4854
|
{
|
|
4844
4855
|
"description": "Extra classes on the `pre`.",
|
|
4845
4856
|
"name": "className",
|
|
@@ -4861,6 +4872,7 @@
|
|
|
4861
4872
|
"DO cap the height of anything that can be large (a 64 KB response body, a console dump) with `maxHeight`; the page keeps its rhythm and the block scrolls.",
|
|
4862
4873
|
"DON'T hand-roll `<pre className=\"max-h-64 overflow-auto rounded bg-muted p-2 whitespace-pre-wrap\">`: every one of those values is a copy of a token this component reads.",
|
|
4863
4874
|
"DON'T reach for `Text as=\"code\"` for a block: that is inline monospace with no wrapping axis. Use `Text as=\"code\"` for an identifier inside a sentence, CodeBlock for a block.",
|
|
4875
|
+
"DO use `copyable` for a command or snippet the reader will paste (gh#1032). DON'T hand-roll a copy Button next to or over a CodeBlock: `copyable` owns the clipboard call, the confirmed state, the placement and the polite announcement.",
|
|
4864
4876
|
"DON'T use CodeBlock for a single value in a Descriptions row: `Descriptions.Item mono` owns that (it breaks the value, not the row).",
|
|
4865
4877
|
"SYNTAX COLOUR (gh#784): CodeBlock does not highlight, but it DOES own the palette. Tag each span from your highlighter with `data-code-token` — the twelve names are Shiki createCssVariablesTheme's verbatim (comment, keyword, string, string-expression, function, constant, parameter, punctuation, link, inserted, deleted, changed, plus the block foreground) — and the package colours them. DON'T put `style={{ color }}` or a palette `className` on the spans: both are visual overrides, and the colour is not the consumer's to choose. Retheme with the `--code-block-token-*-color` knobs, which are role-mirrors, so light and dark follow the theme with no second palette."
|
|
4866
4878
|
],
|
|
@@ -5340,6 +5352,11 @@
|
|
|
5340
5352
|
"name": "children",
|
|
5341
5353
|
"required": true,
|
|
5342
5354
|
"type": "(flat, helpers) => ReactNode"
|
|
5355
|
+
},
|
|
5356
|
+
{
|
|
5357
|
+
"description": "Idle text of the built-in load-more button (default: localized `query.loadMore`, 「さらに読み込む」) — e.g. 「さらに表示」「さらに古い版を表示」. The button, its pending label and disabled-while-fetching stay the component's. Ignored when `loadMore` replaces the footer.",
|
|
5358
|
+
"name": "loadMoreLabel",
|
|
5359
|
+
"type": "ReactNode"
|
|
5343
5360
|
}
|
|
5344
5361
|
],
|
|
5345
5362
|
"related": [
|
|
@@ -5356,7 +5373,7 @@
|
|
|
5356
5373
|
"DO: Always pass `skeleton` (e.g. `<SkeletonTable />` or `<SkeletonStat />`). It shows on initial `isPending`, on refetch-after-error, and whenever `data` is absent. Never show a blank area while loading.",
|
|
5357
5374
|
"DO: Pass `empty` (an `<EmptyState>` node) to handle the zero-results case — without it the children render-prop is called with an empty array and you get a silent blank screen. Provide a custom `isEmpty` only when `TFlat` is not an array.",
|
|
5358
5375
|
"DO: Let errors remain cause-aware. Retry is automatic only for classified transient/network/5xx failures. Unknown errors do not get a blind retry unless `showRetry` or `onRetry` is explicitly supplied; a 401 is handled by the app-root `AuthExpiryProvider` (auto, once, skeleton + live region) or, without one, by the `onAuthError` sign-in button; raw backend/token text is never rendered.",
|
|
5359
|
-
"DON'T: Hand-roll a load-more button. The component renders a default centered outline Button when `hasNextPage` is true.
|
|
5376
|
+
"DON'T: Hand-roll a load-more button. The component renders a default centered outline Button when `hasNextPage` is true. Rename it with `loadMoreLabel` (keeps the pending state); replace it only via `loadMore` (custom node) or `showLoadMore={false}` (hide entirely). Never call `query.fetchNextPage()` outside the component for pagination.",
|
|
5360
5377
|
"DON'T: Use `InfiniteQueryState` for a `useQuery` result — it expects `UseInfiniteQueryResult` shape (`pages`, `hasNextPage`, `fetchNextPage`, `isFetchingNextPage`). For regular `useQuery` use `DataState` instead.",
|
|
5361
5378
|
"DON'T: Confuse the two generics: `TPage` is the raw page shape from the API, `TFlat` is what `flatten` returns (usually `TItem[]`). The `children` render-prop receives `TFlat`, not `TPage`. Pass `isEmpty` if `TFlat` is not a plain array so empty detection works correctly."
|
|
5362
5379
|
],
|
|
@@ -6111,6 +6128,16 @@
|
|
|
6111
6128
|
"name": "dialogTitle",
|
|
6112
6129
|
"type": "string"
|
|
6113
6130
|
},
|
|
6131
|
+
{
|
|
6132
|
+
"description": "antd `notFoundContent` — shown when the search finds nothing, in the dropdown shape and the dialog alike (default: localized `dataEntry.recordPicker.empty`). Say WHAT has no match, e.g. 「該当するファイルはありません」.",
|
|
6133
|
+
"name": "notFoundContent",
|
|
6134
|
+
"type": "ReactNode"
|
|
6135
|
+
},
|
|
6136
|
+
{
|
|
6137
|
+
"description": "Text of the dialog's load-more button (default: localized `dataEntry.recordPicker.more`). Only the label — the button still appears only while the server returns a `nextCursor`.",
|
|
6138
|
+
"name": "loadMoreLabel",
|
|
6139
|
+
"type": "ReactNode"
|
|
6140
|
+
},
|
|
6114
6141
|
{
|
|
6115
6142
|
"description": "Control height of the trigger, on the shared control ladder.",
|
|
6116
6143
|
"name": "size",
|
|
@@ -9072,7 +9099,7 @@
|
|
|
9072
9099
|
"type": "\"SHOW_CHILD\" | \"SHOW_PARENT\""
|
|
9073
9100
|
},
|
|
9074
9101
|
{
|
|
9075
|
-
"description": "antd `loadData` — lazy children. Called
|
|
9102
|
+
"description": "antd `loadData` — lazy children. Called when a branch that has no children and isLeaf !== true is expanded, and never again once its promise resolves; push the fetched children into options. A rejected promise is forgotten, so the next activation of the branch asks again (gh#1041).",
|
|
9076
9103
|
"name": "loadData",
|
|
9077
9104
|
"type": "(selectedOptions: TreeOptionProp[]) => void | Promise<void>"
|
|
9078
9105
|
},
|
|
@@ -9313,7 +9340,7 @@
|
|
|
9313
9340
|
"type": "boolean"
|
|
9314
9341
|
},
|
|
9315
9342
|
{
|
|
9316
|
-
"description": "antd `loadData` — lazy children. Called
|
|
9343
|
+
"description": "antd `loadData` — lazy children. Called when a node that has no children and isLeaf !== true is expanded, and never again once its promise resolves; push the fetched children into treeData. A rejected promise folds the branch shut and the next expand asks again, up to 10 attempts (rc-tree, gh#1041). Such a node still reads as expandable (aria-expanded + a working expander).",
|
|
9317
9344
|
"name": "loadData",
|
|
9318
9345
|
"type": "(node: TreeOptionProp) => void | Promise<void>"
|
|
9319
9346
|
},
|
|
@@ -9475,6 +9502,11 @@
|
|
|
9475
9502
|
"name": "onSelectChange",
|
|
9476
9503
|
"type": "(sourceSelectedKeys: string[], targetSelectedKeys: string[]) => void"
|
|
9477
9504
|
},
|
|
9505
|
+
{
|
|
9506
|
+
"description": "antd `locale`, ported for `notFoundContent` only: what an empty or search-emptied pane shows (default: localized `dataEntry.transfer.empty`). A `[source, target]` pair sets each pane separately, as in antd.",
|
|
9507
|
+
"name": "locale",
|
|
9508
|
+
"type": "{ notFoundContent?: ReactNode | [ReactNode, ReactNode] }"
|
|
9509
|
+
},
|
|
9478
9510
|
{
|
|
9479
9511
|
"description": "Fires when items move between panels; you own `targetKeys` state.",
|
|
9480
9512
|
"name": "onValueChange",
|
|
@@ -11040,7 +11072,7 @@
|
|
|
11040
11072
|
"type": "boolean"
|
|
11041
11073
|
},
|
|
11042
11074
|
{
|
|
11043
|
-
"description": "Lazy children (antd `loadData`). Called
|
|
11075
|
+
"description": "Lazy children (antd `loadData`). Called when a branch with no `children` and `isLeaf !== true` is expanded, and never again once its promise RESOLVES; a Skeleton row and `aria-busy` cover the wait. Push the fetched children into `treeData`. A REJECTED promise is not a load (rc-tree, gh#1041): the branch folds back shut (uncontrolled expansion) and the next expand asks again, up to 10 attempts.",
|
|
11044
11076
|
"name": "loadData",
|
|
11045
11077
|
"type": "(node: TreeNodeProp) => void | Promise<void>"
|
|
11046
11078
|
},
|
|
@@ -11049,6 +11081,22 @@
|
|
|
11049
11081
|
"name": "titleRender",
|
|
11050
11082
|
"type": "(node: TreeNodeProp) => ReactNode"
|
|
11051
11083
|
},
|
|
11084
|
+
{
|
|
11085
|
+
"description": "Highlight the nodes this returns true for (antd `filterTreeNode`, gh#1043) — the match of a search box above the tree. Matching rows are MARKED, not hidden: `data-filter-node=\"true\"`, the label in `--tree-node-filter-foreground` (default `hsl(var(--primary))`) at the medium weight, plus sr-only \"matches the filter\" text. Outline, keyboard and ARIA are unchanged. To also open the branches that hold a match, drive `expandedValues`.",
|
|
11086
|
+
"name": "filterTreeNode",
|
|
11087
|
+
"type": "(node: TreeNodeProp) => boolean"
|
|
11088
|
+
},
|
|
11089
|
+
{
|
|
11090
|
+
"description": "Viewport height in px (antd `height`, gh#1042). The tree scrolls inside it and, unless `virtual={false}`, renders only the rows in view plus a small overscan — the windowed rows stay a flat run of treeitems whose `aria-level`/`aria-setsize`/`aria-posinset` still describe the whole outline. Rows must share one height (the `size` tier).",
|
|
11091
|
+
"name": "height",
|
|
11092
|
+
"type": "number"
|
|
11093
|
+
},
|
|
11094
|
+
{
|
|
11095
|
+
"defaultValue": "true",
|
|
11096
|
+
"description": "Set `false` to keep the `height` viewport but render every row (antd `virtual`).",
|
|
11097
|
+
"name": "virtual",
|
|
11098
|
+
"type": "boolean"
|
|
11099
|
+
},
|
|
11052
11100
|
{
|
|
11053
11101
|
"defaultValue": "false",
|
|
11054
11102
|
"description": "Draw the connector rails between a parent and its children (antd `showLine`). Off by default — a rail is chrome, and chrome defaults quiet.",
|
|
@@ -11106,7 +11154,7 @@
|
|
|
11106
11154
|
"TreeSelect — the same hierarchy INSIDE a Popover, as a form field. Use TreeSelect when the answer is a value in a form; use Tree when the hierarchy itself is the page.",
|
|
11107
11155
|
"Cascader — a path picker across columns. Use it when the user walks one path to a leaf; use Tree when several branches are open at once.",
|
|
11108
11156
|
"Accordion — single-level disclosure with rich panel content. It is not a hierarchy and has no tree keyboard model.",
|
|
11109
|
-
"ScrollArea —
|
|
11157
|
+
"ScrollArea — not needed around Tree: pass `height`, and the tree is its own (windowed) scroll viewport."
|
|
11110
11158
|
],
|
|
11111
11159
|
"rules": [
|
|
11112
11160
|
2,
|
|
@@ -11126,8 +11174,9 @@
|
|
|
11126
11174
|
"DON'T nest a Button, Checkbox, Link or any focusable control inside a node label. A tree item owns exactly ONE tab stop; the disclosure triangle and the tick box are decorative glyphs for that reason. Put row actions in a sibling column outside the tree, or open a detail pane on selection.",
|
|
11127
11175
|
"DON'T hand-roll an indented `<ul>` (or a NavList / ListRow stack with a per-depth margin) for a hierarchy. A flat indented list only LOOKS like a tree: no expand/collapse, no `role=\"tree\"`, no keyboard model, no selection contract. `TreeList` was exactly that list and was REMOVED in 21.0.0 — Tree is what replaced it, and it is the one to reach for whenever nodes expand, collapse or are keyboard-navigated.",
|
|
11128
11176
|
"DO pass `divided` when the tree IS the navigation of a page — a wiki/document outline or a section index sitting in a `Card` (`Card` > `CardContent flush` > `Tree divided`). Without a rule the rows run together and the outline reads as one block; with it, it reads as the ruled list ListRow and Table already give a flat list. Retint it per theme with `--tree-divider-color`, never with a per-page utility class.",
|
|
11129
|
-
"DO
|
|
11130
|
-
"DO push fetched children into `treeData` from `loadData`; the tree calls it once per node and shows a Skeleton row until the data lands."
|
|
11177
|
+
"DO pass `height` for a long tree (antd `height` + `virtual`): the tree scrolls inside that height and keeps only the rows in view in the DOM, so a 421-child level renders a few dozen rows. Do not wrap it in `ScrollArea` as well — the tree is its own viewport.",
|
|
11178
|
+
"DO push fetched children into `treeData` from `loadData`; the tree calls it once per node that loads and shows a Skeleton row until the data lands. Reject the promise on failure — the branch folds shut and the next expand retries.",
|
|
11179
|
+
"DON'T wait for a paged \"load more\" node — antd's Tree has none, and `height` covers a long list. If the API itself is paged, append a leaf node such as `{ value: `${parent}::more`, label: t(\"…load more\"), isLeaf: true }` to the loaded children and fetch the next page from `onValueChange` when it is selected: it is a real treeitem, so it is keyboard-reachable and announced."
|
|
11131
11180
|
],
|
|
11132
11181
|
"useCases": [
|
|
11133
11182
|
"A permission tree: modules → resources → actions with tri-state checkboxes, where ticking a module ticks everything under it and a partly-granted module shows the dash.",
|
|
@@ -14649,6 +14698,11 @@
|
|
|
14649
14698
|
"name": "searchable",
|
|
14650
14699
|
"type": "boolean"
|
|
14651
14700
|
},
|
|
14701
|
+
{
|
|
14702
|
+
"description": "antd `notFoundContent` — shown when the branch SEARCH matches nothing (default: localized `dataEntry.branchScope.noMatches`). An empty `branches` list is `empty`'s job, not this.",
|
|
14703
|
+
"name": "notFoundContent",
|
|
14704
|
+
"type": "ReactNode"
|
|
14705
|
+
},
|
|
14652
14706
|
{
|
|
14653
14707
|
"description": "Override the localized radio labels (e.g. domain wording like 全店舗).",
|
|
14654
14708
|
"name": "allLabel / selectedLabel",
|
|
@@ -15608,6 +15662,65 @@
|
|
|
15608
15662
|
"ThoughtChainItem alone: the chip an assistant drops inline to name the tool it just reached for."
|
|
15609
15663
|
]
|
|
15610
15664
|
},
|
|
15665
|
+
{
|
|
15666
|
+
"docPath": "data-display/org-chart.tsx",
|
|
15667
|
+
"example": "import { Avatar, AvatarFallback, Badge, OrgChart } from \"@godxjp/ui/data-display\";\n\n<OrgChart\n label=\"Company org chart\"\n data={[\n {\n key: \"ceo\", name: \"Haruka Tanaka\", title: \"CEO\",\n avatar: <Avatar size=\"sm\"><AvatarFallback>HT</AvatarFallback></Avatar>,\n children: [\n { key: \"cto\", name: \"Kenji Watanabe\", title: \"CTO\" },\n { key: \"bot\", name: \"Review Agent\", title: \"Code review\", variant: \"agent\",\n extra: <Badge tone=\"success\">Running</Badge> },\n ],\n },\n ]}\n/>",
|
|
15668
|
+
"group": "data-display",
|
|
15669
|
+
"importPath": "@godxjp/ui/data-display",
|
|
15670
|
+
"name": "OrgChart",
|
|
15671
|
+
"props": [
|
|
15672
|
+
{
|
|
15673
|
+
"description": "The hierarchy: { key, name, title?, avatar?, extra?, variant?: \"person\" | \"agent\", children? }. `key` is unique across the chart. `avatar` is usually an <Avatar>; `extra` a Badge or status.",
|
|
15674
|
+
"name": "data",
|
|
15675
|
+
"type": "OrgChartNodeProp[]"
|
|
15676
|
+
},
|
|
15677
|
+
{
|
|
15678
|
+
"description": "Replace a box's content. The box, its border, the connectors and the keyboard stay the library's; the narrow Tree form uses it too.",
|
|
15679
|
+
"name": "renderNode",
|
|
15680
|
+
"type": "(node: OrgChartNodeProp) => ReactNode"
|
|
15681
|
+
},
|
|
15682
|
+
{
|
|
15683
|
+
"description": "Accessible name of the role=\"tree\" (a plain string). Localized default \"Organization chart\".",
|
|
15684
|
+
"name": "label",
|
|
15685
|
+
"type": "string"
|
|
15686
|
+
},
|
|
15687
|
+
{
|
|
15688
|
+
"description": "DOM id of the root.",
|
|
15689
|
+
"name": "id",
|
|
15690
|
+
"type": "string"
|
|
15691
|
+
},
|
|
15692
|
+
{
|
|
15693
|
+
"description": "Root class.",
|
|
15694
|
+
"name": "className",
|
|
15695
|
+
"type": "string"
|
|
15696
|
+
}
|
|
15697
|
+
],
|
|
15698
|
+
"related": [
|
|
15699
|
+
"Tree — the indented, collapsible outline. OrgChart renders it as its narrow form.",
|
|
15700
|
+
"Avatar — the mark in each box.",
|
|
15701
|
+
"Badge — a status in a box's `extra` slot."
|
|
15702
|
+
],
|
|
15703
|
+
"rules": [
|
|
15704
|
+
2,
|
|
15705
|
+
6,
|
|
15706
|
+
23,
|
|
15707
|
+
44,
|
|
15708
|
+
45
|
|
15709
|
+
],
|
|
15710
|
+
"storyPath": "data-display/OrgChart.stories.tsx",
|
|
15711
|
+
"tagline": "An organization chart: boxes (avatar, name, title, extra) joined by CSS connector lines, top-down; `agent` nodes are dashed. Scrolls horizontally in its own named region when wider than its container, and turns into an indented Tree when the CONTAINER is under 40rem. APG tree view (tree/treeitem/group, roving tabindex, arrow keys).",
|
|
15712
|
+
"usage": [
|
|
15713
|
+
"DO mark AI agents with `variant: \"agent\"` — the box is dashed AND its accessible name ends in a localized \"AI agent\", so the kind is never carried by the stroke alone.",
|
|
15714
|
+
"DO give it the width it has; the breakpoint is a container query, so a chart in a narrow side panel switches to the Tree form on a wide screen too.",
|
|
15715
|
+
"DO retune boxes and lines through the --org-chart-* tokens (node size, gaps, line width/colour, agent border style).",
|
|
15716
|
+
"DON'T wrap it in your own overflow-x scroller — it owns its scroll region, which only becomes a named tab stop when the chart actually overflows.",
|
|
15717
|
+
"DON'T use it for an outline users expand and collapse — that is Tree. OrgChart always shows every node."
|
|
15718
|
+
],
|
|
15719
|
+
"useCases": [
|
|
15720
|
+
"A company or team org chart with people and AI agents side by side.",
|
|
15721
|
+
"Reporting lines on an admin screen, falling back to an indented list in a narrow panel or on a phone."
|
|
15722
|
+
]
|
|
15723
|
+
},
|
|
15611
15724
|
{
|
|
15612
15725
|
"docPath": "data-entry/attachments.tsx",
|
|
15613
15726
|
"example": "import { Attachments } from \"@godxjp/ui/data-entry\";\n\n<Attachments\n items={files}\n onChange={({ fileList }) => setFiles(fileList)}\n overflow=\"scrollX\"\n maxCount={5}\n/>",
|