@godxjp/ui 31.27.0 → 31.28.1
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 +7 -7
- package/agent/components/BlockEditor.json +8 -0
- package/agent/components/CommandPalette.json +5 -0
- package/agent/components/EmojiPicker.json +78 -0
- package/agent/components/Markdown.json +11 -0
- package/agent/components/PageContainer.json +11 -1
- package/agent/components/PageCover.json +75 -0
- package/agent/components/Tree.json +6 -0
- package/agent/components-index.json +10 -0
- package/agent/components.json +194 -1
- package/agent/index.json +8 -8
- package/agent/llms.txt +7 -7
- package/agent/tokens.json +79 -1
- package/dist/components/data-display/tree.js +5 -0
- package/dist/components/data-entry/command-palette.d.ts +5 -0
- package/dist/components/data-entry/command-palette.js +1 -0
- package/dist/components/data-entry/emoji-data.d.ts +43 -0
- package/dist/components/data-entry/emoji-data.js +54 -0
- package/dist/components/data-entry/emoji-picker.d.ts +13 -0
- package/dist/components/data-entry/emoji-picker.js +272 -0
- package/dist/components/data-entry/index.d.ts +2 -0
- package/dist/components/data-entry/index.js +2 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +2 -0
- package/dist/components/layout/page-container.d.ts +1 -1
- package/dist/components/layout/page-container.js +8 -1
- package/dist/components/layout/page-cover.d.ts +14 -0
- package/dist/components/layout/page-cover.js +127 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +25 -0
- package/dist/i18n/messages/ja.json +25 -0
- package/dist/i18n/messages/vi.json +25 -0
- package/dist/props/components/data-display.prop.d.ts +6 -0
- package/dist/props/components/data-entry.prop.d.ts +26 -0
- package/dist/props/components/layout.prop.d.ts +49 -2
- package/dist/props/registry.d.ts +85 -1
- package/dist/props/registry.js +95 -1
- package/dist/styles/control.css +81 -0
- package/dist/styles/data-display-layout.css +94 -0
- package/dist/styles/focus-ring.css +2 -0
- package/dist/styles/layers.json +17 -1
- package/dist/styles/layout.css +113 -0
- package/dist/tokens/components/control.css +10 -0
- package/dist/tokens/components/data-display.css +1 -0
- package/dist/tokens/semantic/layout.css +14 -0
- package/docs/FORMS.md +5 -0
- package/docs/FRAME-COVERAGE-REPORT.md +4 -2
- package/docs/data-entry/emoji-picker.tsx +35 -0
- package/docs/i18n/messages/en.json +16 -0
- package/docs/i18n/messages/ja.json +16 -0
- package/docs/i18n/messages/vi.json +16 -0
- package/docs/layout/page-cover.tsx +56 -0
- package/package.json +5 -6
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.28.1.** 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,7 +47,7 @@ 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` —
|
|
50
|
+
1. `components-index.json` — 51 KB, all 184 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
|
|
@@ -56,15 +56,15 @@ Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `li
|
|
|
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` — 2155 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
|
+
1832 `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.
|
|
66
66
|
|
|
67
|
-
**Do not fetch `components.json`.** It is 1.
|
|
67
|
+
**Do not fetch `components.json`.** It is 1.3 MB, and most URL fetchers truncate a
|
|
68
68
|
response that size and return the head without telling you. You get the first few entries, believe
|
|
69
69
|
you read the catalog, and answer the rest from memory — which is the failure this file exists to
|
|
70
70
|
prevent. The per-component files say the same thing without the cliff.
|
|
@@ -144,8 +144,8 @@ has stopped following the brand.
|
|
|
144
144
|
| `tier` | count | what it is | set it? |
|
|
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
|
-
| `semantic` |
|
|
148
|
-
| `component` |
|
|
147
|
+
| `semantic` | 112 | 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` | 1832 | 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.
|
|
@@ -50,6 +50,12 @@
|
|
|
50
50
|
"name": "resolveUrl",
|
|
51
51
|
"type": "(url: string) => string | undefined"
|
|
52
52
|
},
|
|
53
|
+
{
|
|
54
|
+
"defaultValue": "\"framed\"",
|
|
55
|
+
"description": "framed: a field's border, padding and focus colour, so the editor reads as an editor inside a form; plain: the borderless Notion-style canvas for a full-page editor.",
|
|
56
|
+
"name": "appearance",
|
|
57
|
+
"type": "\"framed\" | \"plain\""
|
|
58
|
+
},
|
|
53
59
|
{
|
|
54
60
|
"description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec.",
|
|
55
61
|
"name": "actions",
|
|
@@ -74,6 +80,8 @@
|
|
|
74
80
|
"storyPath": "data-entry/block-editor.tsx",
|
|
75
81
|
"tagline": "Notion / note.com style block editor (sibling package `@godxjp/block-editor`, versioned with the kit) that reads and writes MARKDOWN through `@godxjp/markdown/codec`: what onValueChange returns is byte-for-byte normalize(body). `/` block menu at the caret, ⋮⋮ handle (drag, turn into, duplicate, move, delete), floating format toolbar, `[[` wikilink suggestions, paste / drop uploads through the host, IME-safe, ja / en / vi (gh#1156).",
|
|
76
82
|
"usage": [
|
|
83
|
+
"Clicking a link (or Mod+K) opens a settings drawer: text, URL, title, open / remove. Clicking an image opens one for src, alt, title, replace (pickMedia / upload) and remove. Markdown stores no link target, so there is no target field. A link in the editor never navigates mid-edit.",
|
|
84
|
+
"YAML front matter shows as a Properties block at the top and round-trips verbatim; read it with frontmatterOf() from @godxjp/markdown/codec.",
|
|
77
85
|
"DO store the Markdown it emits — it is already canonical; compute `normalize()` server-side from the same codec to verify.",
|
|
78
86
|
"DO give it a name: wrap in `FormField` or pass `aria-label` / `aria-labelledby` (the editable is a named `textbox`).",
|
|
79
87
|
"DO pass `upload` (and `pickMedia` for a library) instead of handling paste yourself.",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"required": true,
|
|
11
11
|
"type": "CommandPaletteGroup[]"
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Decorative glyph before an item's label — a folder, a file, an emoji (gh#1159). Menu-row icon size (--menu-icon-size), aria-hidden: the label stays the option's name.",
|
|
15
|
+
"name": "groups[].items[].icon",
|
|
16
|
+
"type": "ReactNode"
|
|
17
|
+
},
|
|
13
18
|
{
|
|
14
19
|
"description": "Localized dialog and search copy.",
|
|
15
20
|
"name": "labels",
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"docPath": "docs/data-entry/emoji-picker.tsx",
|
|
3
|
+
"example": "import { EmojiPicker } from \"@godxjp/ui/data-entry\";\n\n<EmojiPicker value={icon} onValueChange={setIcon} />",
|
|
4
|
+
"group": "data-entry",
|
|
5
|
+
"importPath": "@godxjp/ui/data-entry",
|
|
6
|
+
"name": "EmojiPicker",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"description": "The chosen emoji (controlled with onValueChange).",
|
|
10
|
+
"name": "value",
|
|
11
|
+
"type": "string | null"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Uncontrolled initial emoji.",
|
|
15
|
+
"name": "defaultValue",
|
|
16
|
+
"type": "string | null"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Picked emoji, or null from \"remove icon\".",
|
|
20
|
+
"name": "onValueChange",
|
|
21
|
+
"type": "(emoji: string | null) => void"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "The popover.",
|
|
25
|
+
"name": "open / defaultOpen / onOpenChange",
|
|
26
|
+
"type": "boolean / boolean / (open) => void"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"defaultValue": "true",
|
|
30
|
+
"description": "Offer \"remove icon\" while a value is set.",
|
|
31
|
+
"name": "removable",
|
|
32
|
+
"type": "boolean"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"defaultValue": "\"godxjp-ui:emoji-recents\"",
|
|
36
|
+
"description": "localStorage key for the per-user recents.",
|
|
37
|
+
"name": "recentsKey",
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"defaultValue": "\"md\"",
|
|
42
|
+
"description": "Trigger size.",
|
|
43
|
+
"name": "size",
|
|
44
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"description": "Replace the default trigger (e.g. the page icon drawn large).",
|
|
48
|
+
"name": "trigger",
|
|
49
|
+
"type": "ReactNode"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"description": "Disables the trigger.",
|
|
53
|
+
"name": "disabled",
|
|
54
|
+
"type": "boolean"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"description": "Accessible name for the trigger; defaults to the localized \"Choose an icon\".",
|
|
58
|
+
"name": "aria-label",
|
|
59
|
+
"type": "string"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"description": "Id on the trigger button.",
|
|
63
|
+
"name": "id",
|
|
64
|
+
"type": "string"
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"related": [
|
|
68
|
+
"PageContainer — `icon` slot.",
|
|
69
|
+
"CommandPalette — items can carry an emoji `icon`."
|
|
70
|
+
],
|
|
71
|
+
"rules": [],
|
|
72
|
+
"storyPath": "data-entry/emoji-picker.tsx",
|
|
73
|
+
"tagline": "Page icon / reaction picker in a Popover (gh#1164): search by the active language's CLDR keywords (ja / en / vi — emojibase-data, loaded lazily for that locale only), categories, per-user recents, a WAI-ARIA grid (one tab stop, arrows, Home / End, Enter), and \"remove icon\". No skin tones.",
|
|
74
|
+
"usage": [
|
|
75
|
+
"DO use it for a page icon next to PageContainer `icon` — pass the icon itself as `trigger`.",
|
|
76
|
+
"The data loads on first open (one locale, ~100 KB gzip); nothing ships in your main bundle."
|
|
77
|
+
]
|
|
78
|
+
}
|
|
@@ -52,6 +52,16 @@
|
|
|
52
52
|
"name": "shortCellLength",
|
|
53
53
|
"type": "number | false"
|
|
54
54
|
},
|
|
55
|
+
{
|
|
56
|
+
"description": "Default 'same-tab'. Renderer policy for links to another origin (an absolute http(s) URL whose origin differs from `origin`). 'new-tab' adds target=\"_blank\" rel=\"noopener noreferrer\"; relative links, #anchors, resolved wikilinks and mailto: stay in the tab. Markdown cannot store target, so this replaces it.",
|
|
57
|
+
"name": "externalLinks",
|
|
58
|
+
"type": "'same-tab' | 'new-tab'"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"description": "The page origin externalLinks compares against; defaults to location.origin. Pass it for server rendering, or every absolute link counts as external there.",
|
|
62
|
+
"name": "origin",
|
|
63
|
+
"type": "string"
|
|
64
|
+
},
|
|
55
65
|
{
|
|
56
66
|
"description": "Visible titles for GitHub-alert callouts (`> [!WARNING]`) that carry none of their own. English by default (the package has no i18n); pass localized strings. Grammar v1 (gh#1156): callouts, `:::toggle[summary]`, `::::columns`/`:::column{width=N}`, CJK-friendly emphasis — the same syntax the pure codec at `@godxjp/markdown/codec` (CODEC_ID kit-md@1, parse/serialize/normalize, DOM-free) and @godxjp/block-editor use.",
|
|
57
67
|
"name": "calloutTitles",
|
|
@@ -73,6 +83,7 @@
|
|
|
73
83
|
"storyPath": "data-display/markdown.tsx",
|
|
74
84
|
"tagline": "The one Markdown renderer for GoDX apps (sibling package `@godxjp/markdown`, versioned with the kit): GFM + GitHub heading anchors, one sanitiser schema (no raw HTML; http/https/mailto/relative URLs only), and ```mermaid drawn only after its SVG passes a fail-closed gate (gh#1108). Wrap it in `Prose`.",
|
|
75
85
|
"usage": [
|
|
86
|
+
"Table of contents: outline(markdown) from @godxjp/markdown/codec returns { depth, text, id }[] with exactly the ids <Markdown> writes — feed it to the kit Anchor. YAML front matter is kept verbatim and never rendered; frontmatterOf(markdown) returns it (gh#1163).",
|
|
76
87
|
"DO `<Prose><Markdown>{body}</Markdown></Prose>` for every rendered body (wiki page, issue, mail).",
|
|
77
88
|
"DO record `MARKDOWN_FORMAT` and `RENDERER_VERSION` on stored versions.",
|
|
78
89
|
"DON'T assemble react-markdown + rehype-sanitize per app, add rehype-raw, or render Mermaid yourself — `checkMermaidSvg` is the gate."
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"defaultValue": "\"document\"",
|
|
94
94
|
"description": "What the page's top row IS, which decides the `<h1>`'s type step. \"document\" (default) = the row is the page's TITLE (a record, a form, a collection, a report): --page-title-font-size (h1, 20px) with the existing responsive step down at 720px; no attribute is emitted, so an existing page is byte-identical. \"chrome\" = the row is the surface's own furniture — a chat channel name, a mail subject line, an IDE tab — naming the thing the user is already INSIDE instead of announcing a document; the h1 takes --page-title-font-size-chrome (--heading-h3 = the 14px body step) at EVERY width, including below 720px where the document-scale step would otherwise pull it back UP. The heading stays an `<h1>` either way — this moves the type step only, never the element, so the screen-reader outline is untouched.",
|
|
95
95
|
"name": "headerScale",
|
|
96
|
-
"type": "\"document\" | \"chrome\""
|
|
96
|
+
"type": "\"document\" | \"chrome\" | \"display\""
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"defaultValue": "\"default\"",
|
|
@@ -125,6 +125,16 @@
|
|
|
125
125
|
"name": "headerLoading",
|
|
126
126
|
"type": "boolean"
|
|
127
127
|
},
|
|
128
|
+
{
|
|
129
|
+
"description": "The page's icon (an emoji or glyph) drawn large above the title, riding over a banner `cover`'s bottom edge — Notion's page icon (gh#1160). Add aria-hidden unless it is itself a control.",
|
|
130
|
+
"name": "icon",
|
|
131
|
+
"type": "ReactNode"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"description": "A PageCover: the banner variant spans the page edge to edge above the header; the eyecatch variant sits in the reading column above the title (gh#1160).",
|
|
135
|
+
"name": "cover",
|
|
136
|
+
"type": "ReactNode (a PageCover)"
|
|
137
|
+
},
|
|
128
138
|
{
|
|
129
139
|
"description": "Ref to the page's <h1>; passing it also makes the heading programmatically focusable (tabIndex -1, outside the tab order, no focus ring) so a router can focus the new page title after client-side navigation (gh#1135).",
|
|
130
140
|
"name": "titleRef",
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"docPath": "docs/layout/page-cover.tsx",
|
|
3
|
+
"example": "import { PageContainer, PageCover } from \"@godxjp/ui/layout\";\nimport { Button } from \"@godxjp/ui/general\";\n\n<PageContainer\n title={page.title}\n headerScale=\"display\"\n icon={<span aria-hidden=\"true\">{page.icon}</span>}\n cover={\n <PageCover\n src={page.cover}\n alt=\"\"\n positionY={y}\n onPositionChange={setY}\n repositioning={moving}\n onRepositioningChange={setMoving}\n actions={<Button size=\"sm\" variant=\"secondary\" onClick={() => setMoving(true)}>Reposition</Button>}\n />\n }\n>\n {body}\n</PageContainer>",
|
|
4
|
+
"group": "layout",
|
|
5
|
+
"importPath": "@godxjp/ui/layout",
|
|
6
|
+
"name": "PageCover",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"description": "Image URL.",
|
|
10
|
+
"name": "src",
|
|
11
|
+
"required": true,
|
|
12
|
+
"type": "string"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"description": "Alternative text; \"\" for a decorative cover.",
|
|
16
|
+
"name": "alt",
|
|
17
|
+
"required": true,
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"defaultValue": "50",
|
|
22
|
+
"description": "Vertical focal point, 0 top – 100 bottom.",
|
|
23
|
+
"name": "positionY",
|
|
24
|
+
"type": "number"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"description": "New focal point while repositioning.",
|
|
28
|
+
"name": "onPositionChange",
|
|
29
|
+
"type": "(positionY: number) => void"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"description": "Reposition mode (controlled): the image becomes a slider.",
|
|
33
|
+
"name": "repositioning",
|
|
34
|
+
"type": "boolean"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"description": "Enter / Escape ended the mode.",
|
|
38
|
+
"name": "onRepositioningChange",
|
|
39
|
+
"type": "(repositioning: boolean) => void"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"defaultValue": "\"banner\"",
|
|
43
|
+
"description": "Banner above the header, or eyecatch in the reading column.",
|
|
44
|
+
"name": "variant",
|
|
45
|
+
"type": "\"banner\" | \"eyecatch\""
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"defaultValue": "\"md\"",
|
|
49
|
+
"description": "Banner height step; token-owned, scales phone → desktop.",
|
|
50
|
+
"name": "height",
|
|
51
|
+
"type": "\"md\" | \"lg\""
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"description": "Change / reposition / remove controls: over the bottom edge on a wide screen, BELOW the image on a phone (never on the focal area).",
|
|
55
|
+
"name": "actions",
|
|
56
|
+
"type": "ReactNode"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"description": "Id on the cover frame.",
|
|
60
|
+
"name": "id",
|
|
61
|
+
"type": "string"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"related": [
|
|
65
|
+
"PageContainer — `cover`, `icon`, headerScale=\"display\" for an article title.",
|
|
66
|
+
"Image — an image that opens a preview."
|
|
67
|
+
],
|
|
68
|
+
"rules": [],
|
|
69
|
+
"storyPath": "layout/page-cover.tsx",
|
|
70
|
+
"tagline": "A page's cover image (gh#1160): Notion's banner across the top, or note.com's eyecatch (~1.91:1, rounded) in the reading column. Put it in PageContainer `cover`. The focal point is positionY (object-position); while `repositioning` the image IS a vertical WAI-ARIA slider — drag or arrows / PageUp / PageDown / Home / End, Enter / Escape to finish.",
|
|
71
|
+
"usage": [
|
|
72
|
+
"DO pass it as PageContainer `cover` with the page `icon` — the container places it and overlaps the icon.",
|
|
73
|
+
"DO wire a Reposition button in `actions` that sets `repositioning`, and persist positionY from onPositionChange."
|
|
74
|
+
]
|
|
75
|
+
}
|
|
@@ -85,6 +85,12 @@
|
|
|
85
85
|
"name": "defaultExpandAll",
|
|
86
86
|
"type": "boolean"
|
|
87
87
|
},
|
|
88
|
+
{
|
|
89
|
+
"defaultValue": "false",
|
|
90
|
+
"description": "Expand a parent by clicking its ROW, not only its switcher (antd DirectoryTree): \"click\" selects AND toggles — a page tree where choosing a folder opens it; \"doubleClick\" toggles on a double click (gh#1162). Keyboard keeps the APG map.",
|
|
91
|
+
"name": "expandAction",
|
|
92
|
+
"type": "false | \"click\" | \"doubleClick\""
|
|
93
|
+
},
|
|
88
94
|
{
|
|
89
95
|
"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
96
|
"name": "loadData",
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"name": "PageContainer",
|
|
50
50
|
"tagline": "Mandatory page shell — EVERY page wraps its content in PageContainer (title/subtitle/extra/footer/breadcrumb)."
|
|
51
51
|
},
|
|
52
|
+
{
|
|
53
|
+
"group": "layout",
|
|
54
|
+
"name": "PageCover",
|
|
55
|
+
"tagline": "A page's cover image (gh#1160): Notion's banner across the top, or note.com's eyecatch (~1.91:1, rounded) in the reading column. Put it in PageContainer `cover`. The focal point is positionY (object-position); while `repositioning` the image IS a vertical WAI-ARIA slider — drag or arrows / PageUp / PageDown / Home / End, Enter / Escape to finish."
|
|
56
|
+
},
|
|
52
57
|
{
|
|
53
58
|
"group": "layout",
|
|
54
59
|
"name": "Flex",
|
|
@@ -796,6 +801,11 @@
|
|
|
796
801
|
"name": "CommandPalette",
|
|
797
802
|
"tagline": "Searchable command dialog with controlled or uncontrolled open state and consumer-owned selection."
|
|
798
803
|
},
|
|
804
|
+
{
|
|
805
|
+
"group": "data-entry",
|
|
806
|
+
"name": "EmojiPicker",
|
|
807
|
+
"tagline": "Page icon / reaction picker in a Popover (gh#1164): search by the active language's CLDR keywords (ja / en / vi — emojibase-data, loaded lazily for that locale only), categories, per-user recents, a WAI-ARIA grid (one tab stop, arrows, Home / End, Enter), and \"remove icon\". No skin tones."
|
|
808
|
+
},
|
|
799
809
|
{
|
|
800
810
|
"group": "feedback",
|
|
801
811
|
"name": "TwoFactorSetup",
|
package/agent/components.json
CHANGED
|
@@ -705,7 +705,7 @@
|
|
|
705
705
|
"defaultValue": "\"document\"",
|
|
706
706
|
"description": "What the page's top row IS, which decides the `<h1>`'s type step. \"document\" (default) = the row is the page's TITLE (a record, a form, a collection, a report): --page-title-font-size (h1, 20px) with the existing responsive step down at 720px; no attribute is emitted, so an existing page is byte-identical. \"chrome\" = the row is the surface's own furniture — a chat channel name, a mail subject line, an IDE tab — naming the thing the user is already INSIDE instead of announcing a document; the h1 takes --page-title-font-size-chrome (--heading-h3 = the 14px body step) at EVERY width, including below 720px where the document-scale step would otherwise pull it back UP. The heading stays an `<h1>` either way — this moves the type step only, never the element, so the screen-reader outline is untouched.",
|
|
707
707
|
"name": "headerScale",
|
|
708
|
-
"type": "\"document\" | \"chrome\""
|
|
708
|
+
"type": "\"document\" | \"chrome\" | \"display\""
|
|
709
709
|
},
|
|
710
710
|
{
|
|
711
711
|
"defaultValue": "\"default\"",
|
|
@@ -737,6 +737,16 @@
|
|
|
737
737
|
"name": "headerLoading",
|
|
738
738
|
"type": "boolean"
|
|
739
739
|
},
|
|
740
|
+
{
|
|
741
|
+
"description": "The page's icon (an emoji or glyph) drawn large above the title, riding over a banner `cover`'s bottom edge — Notion's page icon (gh#1160). Add aria-hidden unless it is itself a control.",
|
|
742
|
+
"name": "icon",
|
|
743
|
+
"type": "ReactNode"
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"description": "A PageCover: the banner variant spans the page edge to edge above the header; the eyecatch variant sits in the reading column above the title (gh#1160).",
|
|
747
|
+
"name": "cover",
|
|
748
|
+
"type": "ReactNode (a PageCover)"
|
|
749
|
+
},
|
|
740
750
|
{
|
|
741
751
|
"description": "Ref to the page's <h1>; passing it also makes the heading programmatically focusable (tabIndex -1, outside the tab order, no focus ring) so a router can focus the new page title after client-side navigation (gh#1135).",
|
|
742
752
|
"name": "titleRef",
|
|
@@ -796,6 +806,81 @@
|
|
|
796
806
|
"A chat channel page where a fixed band (channel workflow / pinned-message / connection status) must sit between the page header and the scrolling transcript — `toolbar={<Toolbar>…</Toolbar>}` with `fill` + `footer={<Composer/>}` + `stickyFooter`. The band is outside the scroller, so the transcript never travels under it and the composer stays pinned; a collection page uses the same slot for its filter strip above a full-bleed DataTable (`variant='flush'`)."
|
|
797
807
|
]
|
|
798
808
|
},
|
|
809
|
+
{
|
|
810
|
+
"docPath": "docs/layout/page-cover.tsx",
|
|
811
|
+
"example": "import { PageContainer, PageCover } from \"@godxjp/ui/layout\";\nimport { Button } from \"@godxjp/ui/general\";\n\n<PageContainer\n title={page.title}\n headerScale=\"display\"\n icon={<span aria-hidden=\"true\">{page.icon}</span>}\n cover={\n <PageCover\n src={page.cover}\n alt=\"\"\n positionY={y}\n onPositionChange={setY}\n repositioning={moving}\n onRepositioningChange={setMoving}\n actions={<Button size=\"sm\" variant=\"secondary\" onClick={() => setMoving(true)}>Reposition</Button>}\n />\n }\n>\n {body}\n</PageContainer>",
|
|
812
|
+
"group": "layout",
|
|
813
|
+
"importPath": "@godxjp/ui/layout",
|
|
814
|
+
"name": "PageCover",
|
|
815
|
+
"props": [
|
|
816
|
+
{
|
|
817
|
+
"description": "Image URL.",
|
|
818
|
+
"name": "src",
|
|
819
|
+
"required": true,
|
|
820
|
+
"type": "string"
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
"description": "Alternative text; \"\" for a decorative cover.",
|
|
824
|
+
"name": "alt",
|
|
825
|
+
"required": true,
|
|
826
|
+
"type": "string"
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
"defaultValue": "50",
|
|
830
|
+
"description": "Vertical focal point, 0 top – 100 bottom.",
|
|
831
|
+
"name": "positionY",
|
|
832
|
+
"type": "number"
|
|
833
|
+
},
|
|
834
|
+
{
|
|
835
|
+
"description": "New focal point while repositioning.",
|
|
836
|
+
"name": "onPositionChange",
|
|
837
|
+
"type": "(positionY: number) => void"
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"description": "Reposition mode (controlled): the image becomes a slider.",
|
|
841
|
+
"name": "repositioning",
|
|
842
|
+
"type": "boolean"
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
"description": "Enter / Escape ended the mode.",
|
|
846
|
+
"name": "onRepositioningChange",
|
|
847
|
+
"type": "(repositioning: boolean) => void"
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
"defaultValue": "\"banner\"",
|
|
851
|
+
"description": "Banner above the header, or eyecatch in the reading column.",
|
|
852
|
+
"name": "variant",
|
|
853
|
+
"type": "\"banner\" | \"eyecatch\""
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
"defaultValue": "\"md\"",
|
|
857
|
+
"description": "Banner height step; token-owned, scales phone → desktop.",
|
|
858
|
+
"name": "height",
|
|
859
|
+
"type": "\"md\" | \"lg\""
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
"description": "Change / reposition / remove controls: over the bottom edge on a wide screen, BELOW the image on a phone (never on the focal area).",
|
|
863
|
+
"name": "actions",
|
|
864
|
+
"type": "ReactNode"
|
|
865
|
+
},
|
|
866
|
+
{
|
|
867
|
+
"description": "Id on the cover frame.",
|
|
868
|
+
"name": "id",
|
|
869
|
+
"type": "string"
|
|
870
|
+
}
|
|
871
|
+
],
|
|
872
|
+
"related": [
|
|
873
|
+
"PageContainer — `cover`, `icon`, headerScale=\"display\" for an article title.",
|
|
874
|
+
"Image — an image that opens a preview."
|
|
875
|
+
],
|
|
876
|
+
"rules": [],
|
|
877
|
+
"storyPath": "layout/page-cover.tsx",
|
|
878
|
+
"tagline": "A page's cover image (gh#1160): Notion's banner across the top, or note.com's eyecatch (~1.91:1, rounded) in the reading column. Put it in PageContainer `cover`. The focal point is positionY (object-position); while `repositioning` the image IS a vertical WAI-ARIA slider — drag or arrows / PageUp / PageDown / Home / End, Enter / Escape to finish.",
|
|
879
|
+
"usage": [
|
|
880
|
+
"DO pass it as PageContainer `cover` with the page `icon` — the container places it and overlaps the icon.",
|
|
881
|
+
"DO wire a Reposition button in `actions` that sets `repositioning`, and persist positionY from onPositionChange."
|
|
882
|
+
]
|
|
883
|
+
},
|
|
799
884
|
{
|
|
800
885
|
"example": "import { Flex } from \"@godxjp/ui/layout\";\nimport { Button } from \"@godxjp/ui/general\";\n\n<Flex direction=\"row\" gap=\"sm\" align=\"center\" justify=\"between\" wrap>\n <SearchSummary />\n <Flex direction=\"row\" gap=\"xs\" align=\"center\" wrap>\n <Button variant=\"outline\">リセット</Button>\n <Button>適用</Button>\n </Flex>\n</Flex>",
|
|
801
886
|
"group": "layout",
|
|
@@ -5061,6 +5146,16 @@
|
|
|
5061
5146
|
"name": "shortCellLength",
|
|
5062
5147
|
"type": "number | false"
|
|
5063
5148
|
},
|
|
5149
|
+
{
|
|
5150
|
+
"description": "Default 'same-tab'. Renderer policy for links to another origin (an absolute http(s) URL whose origin differs from `origin`). 'new-tab' adds target=\"_blank\" rel=\"noopener noreferrer\"; relative links, #anchors, resolved wikilinks and mailto: stay in the tab. Markdown cannot store target, so this replaces it.",
|
|
5151
|
+
"name": "externalLinks",
|
|
5152
|
+
"type": "'same-tab' | 'new-tab'"
|
|
5153
|
+
},
|
|
5154
|
+
{
|
|
5155
|
+
"description": "The page origin externalLinks compares against; defaults to location.origin. Pass it for server rendering, or every absolute link counts as external there.",
|
|
5156
|
+
"name": "origin",
|
|
5157
|
+
"type": "string"
|
|
5158
|
+
},
|
|
5064
5159
|
{
|
|
5065
5160
|
"description": "Visible titles for GitHub-alert callouts (`> [!WARNING]`) that carry none of their own. English by default (the package has no i18n); pass localized strings. Grammar v1 (gh#1156): callouts, `:::toggle[summary]`, `::::columns`/`:::column{width=N}`, CJK-friendly emphasis — the same syntax the pure codec at `@godxjp/markdown/codec` (CODEC_ID kit-md@1, parse/serialize/normalize, DOM-free) and @godxjp/block-editor use.",
|
|
5066
5161
|
"name": "calloutTitles",
|
|
@@ -5082,6 +5177,7 @@
|
|
|
5082
5177
|
"storyPath": "data-display/markdown.tsx",
|
|
5083
5178
|
"tagline": "The one Markdown renderer for GoDX apps (sibling package `@godxjp/markdown`, versioned with the kit): GFM + GitHub heading anchors, one sanitiser schema (no raw HTML; http/https/mailto/relative URLs only), and ```mermaid drawn only after its SVG passes a fail-closed gate (gh#1108). Wrap it in `Prose`.",
|
|
5084
5179
|
"usage": [
|
|
5180
|
+
"Table of contents: outline(markdown) from @godxjp/markdown/codec returns { depth, text, id }[] with exactly the ids <Markdown> writes — feed it to the kit Anchor. YAML front matter is kept verbatim and never rendered; frontmatterOf(markdown) returns it (gh#1163).",
|
|
5085
5181
|
"DO `<Prose><Markdown>{body}</Markdown></Prose>` for every rendered body (wiki page, issue, mail).",
|
|
5086
5182
|
"DO record `MARKDOWN_FORMAT` and `RENDERER_VERSION` on stored versions.",
|
|
5087
5183
|
"DON'T assemble react-markdown + rehype-sanitize per app, add rehype-raw, or render Mermaid yourself — `checkMermaidSvg` is the gate."
|
|
@@ -5205,6 +5301,12 @@
|
|
|
5205
5301
|
"name": "resolveUrl",
|
|
5206
5302
|
"type": "(url: string) => string | undefined"
|
|
5207
5303
|
},
|
|
5304
|
+
{
|
|
5305
|
+
"defaultValue": "\"framed\"",
|
|
5306
|
+
"description": "framed: a field's border, padding and focus colour, so the editor reads as an editor inside a form; plain: the borderless Notion-style canvas for a full-page editor.",
|
|
5307
|
+
"name": "appearance",
|
|
5308
|
+
"type": "\"framed\" | \"plain\""
|
|
5309
|
+
},
|
|
5208
5310
|
{
|
|
5209
5311
|
"description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec.",
|
|
5210
5312
|
"name": "actions",
|
|
@@ -5229,6 +5331,8 @@
|
|
|
5229
5331
|
"storyPath": "data-entry/block-editor.tsx",
|
|
5230
5332
|
"tagline": "Notion / note.com style block editor (sibling package `@godxjp/block-editor`, versioned with the kit) that reads and writes MARKDOWN through `@godxjp/markdown/codec`: what onValueChange returns is byte-for-byte normalize(body). `/` block menu at the caret, ⋮⋮ handle (drag, turn into, duplicate, move, delete), floating format toolbar, `[[` wikilink suggestions, paste / drop uploads through the host, IME-safe, ja / en / vi (gh#1156).",
|
|
5231
5333
|
"usage": [
|
|
5334
|
+
"Clicking a link (or Mod+K) opens a settings drawer: text, URL, title, open / remove. Clicking an image opens one for src, alt, title, replace (pickMedia / upload) and remove. Markdown stores no link target, so there is no target field. A link in the editor never navigates mid-edit.",
|
|
5335
|
+
"YAML front matter shows as a Properties block at the top and round-trips verbatim; read it with frontmatterOf() from @godxjp/markdown/codec.",
|
|
5232
5336
|
"DO store the Markdown it emits — it is already canonical; compute `normalize()` server-side from the same codec to verify.",
|
|
5233
5337
|
"DO give it a name: wrap in `FormField` or pass `aria-label` / `aria-labelledby` (the editable is a named `textbox`).",
|
|
5234
5338
|
"DO pass `upload` (and `pickMedia` for a library) instead of handling paste yourself.",
|
|
@@ -11477,6 +11581,12 @@
|
|
|
11477
11581
|
"name": "defaultExpandAll",
|
|
11478
11582
|
"type": "boolean"
|
|
11479
11583
|
},
|
|
11584
|
+
{
|
|
11585
|
+
"defaultValue": "false",
|
|
11586
|
+
"description": "Expand a parent by clicking its ROW, not only its switcher (antd DirectoryTree): \"click\" selects AND toggles — a page tree where choosing a folder opens it; \"doubleClick\" toggles on a double click (gh#1162). Keyboard keeps the APG map.",
|
|
11587
|
+
"name": "expandAction",
|
|
11588
|
+
"type": "false | \"click\" | \"doubleClick\""
|
|
11589
|
+
},
|
|
11480
11590
|
{
|
|
11481
11591
|
"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.",
|
|
11482
11592
|
"name": "loadData",
|
|
@@ -14265,6 +14375,11 @@
|
|
|
14265
14375
|
"required": true,
|
|
14266
14376
|
"type": "CommandPaletteGroup[]"
|
|
14267
14377
|
},
|
|
14378
|
+
{
|
|
14379
|
+
"description": "Decorative glyph before an item's label — a folder, a file, an emoji (gh#1159). Menu-row icon size (--menu-icon-size), aria-hidden: the label stays the option's name.",
|
|
14380
|
+
"name": "groups[].items[].icon",
|
|
14381
|
+
"type": "ReactNode"
|
|
14382
|
+
},
|
|
14268
14383
|
{
|
|
14269
14384
|
"description": "Localized dialog and search copy.",
|
|
14270
14385
|
"name": "labels",
|
|
@@ -14343,6 +14458,84 @@
|
|
|
14343
14458
|
"The empty-state contract: with `shouldFilter` (default) cmdk decides — items exist, the query matches none. With `shouldFilter={false}` the PALETTE decides from props — `labels.empty` renders when `groups` carries no items, and never while `loading` or `error` is set. Hold `loading` for the whole in-flight window: a request that has not answered yet is not an empty result, and asserting over cmdk's own empty node races an async group that populates a frame late."
|
|
14344
14459
|
]
|
|
14345
14460
|
},
|
|
14461
|
+
{
|
|
14462
|
+
"docPath": "docs/data-entry/emoji-picker.tsx",
|
|
14463
|
+
"example": "import { EmojiPicker } from \"@godxjp/ui/data-entry\";\n\n<EmojiPicker value={icon} onValueChange={setIcon} />",
|
|
14464
|
+
"group": "data-entry",
|
|
14465
|
+
"importPath": "@godxjp/ui/data-entry",
|
|
14466
|
+
"name": "EmojiPicker",
|
|
14467
|
+
"props": [
|
|
14468
|
+
{
|
|
14469
|
+
"description": "The chosen emoji (controlled with onValueChange).",
|
|
14470
|
+
"name": "value",
|
|
14471
|
+
"type": "string | null"
|
|
14472
|
+
},
|
|
14473
|
+
{
|
|
14474
|
+
"description": "Uncontrolled initial emoji.",
|
|
14475
|
+
"name": "defaultValue",
|
|
14476
|
+
"type": "string | null"
|
|
14477
|
+
},
|
|
14478
|
+
{
|
|
14479
|
+
"description": "Picked emoji, or null from \"remove icon\".",
|
|
14480
|
+
"name": "onValueChange",
|
|
14481
|
+
"type": "(emoji: string | null) => void"
|
|
14482
|
+
},
|
|
14483
|
+
{
|
|
14484
|
+
"description": "The popover.",
|
|
14485
|
+
"name": "open / defaultOpen / onOpenChange",
|
|
14486
|
+
"type": "boolean / boolean / (open) => void"
|
|
14487
|
+
},
|
|
14488
|
+
{
|
|
14489
|
+
"defaultValue": "true",
|
|
14490
|
+
"description": "Offer \"remove icon\" while a value is set.",
|
|
14491
|
+
"name": "removable",
|
|
14492
|
+
"type": "boolean"
|
|
14493
|
+
},
|
|
14494
|
+
{
|
|
14495
|
+
"defaultValue": "\"godxjp-ui:emoji-recents\"",
|
|
14496
|
+
"description": "localStorage key for the per-user recents.",
|
|
14497
|
+
"name": "recentsKey",
|
|
14498
|
+
"type": "string"
|
|
14499
|
+
},
|
|
14500
|
+
{
|
|
14501
|
+
"defaultValue": "\"md\"",
|
|
14502
|
+
"description": "Trigger size.",
|
|
14503
|
+
"name": "size",
|
|
14504
|
+
"type": "\"xs\" | \"sm\" | \"md\" | \"lg\""
|
|
14505
|
+
},
|
|
14506
|
+
{
|
|
14507
|
+
"description": "Replace the default trigger (e.g. the page icon drawn large).",
|
|
14508
|
+
"name": "trigger",
|
|
14509
|
+
"type": "ReactNode"
|
|
14510
|
+
},
|
|
14511
|
+
{
|
|
14512
|
+
"description": "Disables the trigger.",
|
|
14513
|
+
"name": "disabled",
|
|
14514
|
+
"type": "boolean"
|
|
14515
|
+
},
|
|
14516
|
+
{
|
|
14517
|
+
"description": "Accessible name for the trigger; defaults to the localized \"Choose an icon\".",
|
|
14518
|
+
"name": "aria-label",
|
|
14519
|
+
"type": "string"
|
|
14520
|
+
},
|
|
14521
|
+
{
|
|
14522
|
+
"description": "Id on the trigger button.",
|
|
14523
|
+
"name": "id",
|
|
14524
|
+
"type": "string"
|
|
14525
|
+
}
|
|
14526
|
+
],
|
|
14527
|
+
"related": [
|
|
14528
|
+
"PageContainer — `icon` slot.",
|
|
14529
|
+
"CommandPalette — items can carry an emoji `icon`."
|
|
14530
|
+
],
|
|
14531
|
+
"rules": [],
|
|
14532
|
+
"storyPath": "data-entry/emoji-picker.tsx",
|
|
14533
|
+
"tagline": "Page icon / reaction picker in a Popover (gh#1164): search by the active language's CLDR keywords (ja / en / vi — emojibase-data, loaded lazily for that locale only), categories, per-user recents, a WAI-ARIA grid (one tab stop, arrows, Home / End, Enter), and \"remove icon\". No skin tones.",
|
|
14534
|
+
"usage": [
|
|
14535
|
+
"DO use it for a page icon next to PageContainer `icon` — pass the icon itself as `trigger`.",
|
|
14536
|
+
"The data loads on first open (one locale, ~100 KB gzip); nothing ships in your main bundle."
|
|
14537
|
+
]
|
|
14538
|
+
},
|
|
14346
14539
|
{
|
|
14347
14540
|
"example": "import { TwoFactorSetup } from \"@godxjp/ui/feedback\";\n\n<TwoFactorSetup\n open={open}\n onOpenChange={setOpen}\n qrValue={enrollment.qr}\n manualKey={enrollment.secret}\n code={code}\n onCodeChange={setCode}\n onConfirm={verify}\n recoveryCodes={recoveryCodes}\n onAcknowledge={finish}\n labels={labels}\n/>",
|
|
14348
14541
|
"group": "feedback",
|