@godxjp/ui 31.26.2 → 31.28.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 +7 -7
- package/agent/components/BlockEditor.json +91 -0
- package/agent/components/CommandPalette.json +5 -0
- package/agent/components/EmojiPicker.json +78 -0
- package/agent/components/Markdown.json +16 -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 +15 -0
- package/agent/components.json +282 -1
- package/agent/index.json +8 -8
- package/agent/llms.txt +7 -7
- package/agent/tokens.json +108 -0
- 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 +315 -2
- package/dist/styles/focus-ring.css +4 -0
- package/dist/styles/layers.json +26 -1
- package/dist/styles/layout.css +113 -0
- package/dist/tokens/components/control.css +10 -0
- package/dist/tokens/components/data-display.css +9 -0
- package/dist/tokens/semantic/layout.css +14 -0
- package/docs/FRAME-COVERAGE-REPORT.md +5 -2
- package/docs/data-entry/block-editor.tsx +105 -0
- package/docs/data-entry/emoji-picker.tsx +35 -0
- package/docs/i18n/messages/en.json +40 -0
- package/docs/i18n/messages/ja.json +40 -0
- package/docs/i18n/messages/vi.json +40 -0
- package/docs/layout/page-cover.tsx +56 -0
- package/package.json +28 -4
- package/scripts/prune-css.mjs +1 -1
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.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,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.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"docPath": "docs/data-entry/block-editor.tsx",
|
|
3
|
+
"example": "import { BlockEditor } from \"@godxjp/block-editor\";\nimport { FormField } from \"@godxjp/ui/data-entry\";\n\n<FormField id=\"body\" label=\"本文\">\n <BlockEditor\n value={body}\n onValueChange={setBody}\n upload={async (file, { signal }) => ({ url: await media.put(file, { signal }), name: file.name })}\n suggestWikilinks={(q) => pages.search(q)}\n />\n</FormField>",
|
|
4
|
+
"group": "data-entry",
|
|
5
|
+
"importPath": "@godxjp/block-editor",
|
|
6
|
+
"name": "BlockEditor",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"description": "Controlled Markdown body (with `onValueChange`).",
|
|
10
|
+
"name": "value",
|
|
11
|
+
"type": "string"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"description": "Uncontrolled initial body.",
|
|
15
|
+
"name": "defaultValue",
|
|
16
|
+
"type": "string"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"description": "Canonical Markdown after each edit — `serialize(editor.getJSON())`, identical to `normalize(body)` from `@godxjp/markdown/codec` (CODEC_ID kit-md@1).",
|
|
20
|
+
"name": "onValueChange",
|
|
21
|
+
"type": "(markdown: string) => void"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"description": "Stores a pasted / dropped / chosen file (return `asset:<id>` if you like). An inline placeholder shows progress; failure offers Retry / Remove; deleting the placeholder aborts `signal`. Images become ``, other files a link.",
|
|
25
|
+
"name": "upload",
|
|
26
|
+
"type": "(file: File, options: { signal: AbortSignal }) => Promise<{ url: string; name?: string }>"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"description": "The host's media library; the `/` Image row opens it instead of a file picker.",
|
|
30
|
+
"name": "pickMedia",
|
|
31
|
+
"type": "() => Promise<{ url: string; name?: string } | null>"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"description": "Refuse files with this message.",
|
|
35
|
+
"name": "uploadBlockedReason",
|
|
36
|
+
"type": "string | null"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"description": "`[[` suggestions from the host's page index; picking inserts `[[target|label]]`.",
|
|
40
|
+
"name": "suggestWikilinks",
|
|
41
|
+
"type": "(query: string) => WikilinkSuggestion[] | Promise<WikilinkSuggestion[]>"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"description": "Renders a block embed `![[target]]`; default is a labelled placeholder.",
|
|
45
|
+
"name": "renderEmbed",
|
|
46
|
+
"type": "(target: string) => ReactNode"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"description": "Resolves a stored image URL (`asset:<id>`) for display; the body keeps the original.",
|
|
50
|
+
"name": "resolveUrl",
|
|
51
|
+
"type": "(url: string) => string | undefined"
|
|
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
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"description": "Extra `/` rows ({ key, label, icon, keywords?, run(api) }) — `api.insertMarkdown` inserts through the codec.",
|
|
61
|
+
"name": "actions",
|
|
62
|
+
"type": "BlockEditorAction[]"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"description": "Override any string (defaults: kit ja / en / vi).",
|
|
66
|
+
"name": "labels",
|
|
67
|
+
"type": "Partial<BlockEditorLabels>"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"description": "Not editable; the body still renders as Prose.",
|
|
71
|
+
"name": "disabled / readOnly",
|
|
72
|
+
"type": "boolean"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"related": [
|
|
76
|
+
"MarkdownEditor — a Textarea with Markdown tooling, for raw-Markdown editing.",
|
|
77
|
+
"Markdown — rendering a stored body (same grammar, renderer v4)."
|
|
78
|
+
],
|
|
79
|
+
"rules": [],
|
|
80
|
+
"storyPath": "data-entry/block-editor.tsx",
|
|
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).",
|
|
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.",
|
|
85
|
+
"DO store the Markdown it emits — it is already canonical; compute `normalize()` server-side from the same codec to verify.",
|
|
86
|
+
"DO give it a name: wrap in `FormField` or pass `aria-label` / `aria-labelledby` (the editable is a named `textbox`).",
|
|
87
|
+
"DO pass `upload` (and `pickMedia` for a library) instead of handling paste yourself.",
|
|
88
|
+
"DON'T render Markdown into it via HTML — pass `value`; HTML paste from other apps is handled by the schema.",
|
|
89
|
+
"Keyboard: `/` menu (↑↓ Enter Esc), Alt+Shift+↑/↓ moves a block, Mod+/ opens the block menu, Markdown shortcuts (`# `, `- `, `> `, ```` ``` ````, `---`)."
|
|
90
|
+
]
|
|
91
|
+
}
|
|
@@ -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,21 @@
|
|
|
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
|
+
},
|
|
65
|
+
{
|
|
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.",
|
|
67
|
+
"name": "calloutTitles",
|
|
68
|
+
"type": "Partial<Record<'note' | 'tip' | 'important' | 'warning' | 'caution', string>>"
|
|
69
|
+
},
|
|
55
70
|
{
|
|
56
71
|
"defaultValue": "true",
|
|
57
72
|
"description": "`false` keeps ```mermaid fences as code. Diagrams need the optional peer `mermaid`.",
|
|
@@ -68,6 +83,7 @@
|
|
|
68
83
|
"storyPath": "data-display/markdown.tsx",
|
|
69
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`.",
|
|
70
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).",
|
|
71
87
|
"DO `<Prose><Markdown>{body}</Markdown></Prose>` for every rendered body (wiki page, issue, mail).",
|
|
72
88
|
"DO record `MARKDOWN_FORMAT` and `RENDERER_VERSION` on stored versions.",
|
|
73
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",
|
|
@@ -311,6 +316,11 @@
|
|
|
311
316
|
"name": "MarkdownEditor",
|
|
312
317
|
"tagline": "Markdown editor (sibling package `@godxjp/editor`, versioned with the kit): the kit's Textarea with a WAI-ARIA formatting toolbar, write / preview / side by side (preview via `@godxjp/markdown`), IME-safe ⌘/Ctrl+B·I·K, one undo step per toolbar edit, and paste / drop / attach through a host `upload` (gh#1109)."
|
|
313
318
|
},
|
|
319
|
+
{
|
|
320
|
+
"group": "data-entry",
|
|
321
|
+
"name": "BlockEditor",
|
|
322
|
+
"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)."
|
|
323
|
+
},
|
|
314
324
|
{
|
|
315
325
|
"group": "data-display",
|
|
316
326
|
"name": "Prose",
|
|
@@ -791,6 +801,11 @@
|
|
|
791
801
|
"name": "CommandPalette",
|
|
792
802
|
"tagline": "Searchable command dialog with controlled or uncontrolled open state and consumer-owned selection."
|
|
793
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
|
+
},
|
|
794
809
|
{
|
|
795
810
|
"group": "feedback",
|
|
796
811
|
"name": "TwoFactorSetup",
|