@godxjp/ui 31.7.0 → 31.8.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 +4 -4
- package/agent/components/ColorPicker.json +16 -8
- package/agent/components/Select.json +22 -0
- package/agent/components.json +38 -8
- package/agent/index.json +4 -4
- package/agent/llms.txt +5 -5
- package/agent/tokens.json +24 -0
- package/dist/components/data-entry/chat-composer.js +11 -4
- package/dist/components/data-entry/chat-suggestion.js +2 -0
- package/dist/components/data-entry/color-picker.d.ts +2 -2
- package/dist/components/data-entry/color-picker.js +150 -37
- package/dist/components/data-entry/command-palette.js +2 -1
- package/dist/components/data-entry/date-picker.js +2 -0
- package/dist/components/data-entry/index.d.ts +1 -1
- package/dist/components/data-entry/number-input.js +2 -1
- package/dist/components/data-entry/search-select.js +55 -17
- package/dist/components/data-entry/select.js +1 -1
- package/dist/components/data-entry/time-picker.js +3 -0
- package/dist/components/feedback/non-modal-layer.js +2 -1
- package/dist/components/general/typography.js +5 -1
- package/dist/components/navigation/pagination.js +2 -1
- package/dist/components/ui/tag-input.js +2 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +4 -2
- package/dist/i18n/messages/ja.json +4 -2
- package/dist/i18n/messages/vi.json +4 -2
- package/dist/lib/ime.d.ts +12 -0
- package/dist/lib/ime.js +7 -0
- package/dist/props/components/data-entry.prop.d.ts +66 -1
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/registry.d.ts +15 -0
- package/dist/props/registry.js +17 -0
- package/dist/styles/control.css +79 -0
- package/dist/styles/layers.json +1 -1
- package/dist/tokens/components/control.css +8 -0
- package/docs/data-entry/color-picker.tsx +72 -0
- package/docs/data-entry/select.tsx +38 -0
- package/docs/i18n/messages/en.json +18 -0
- package/docs/i18n/messages/ja.json +18 -0
- package/docs/i18n/messages/vi.json +18 -0
- package/package.json +2 -2
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.8.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.
|
|
@@ -56,10 +56,10 @@ 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` — 2104 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
|
+
1789 `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` | 1789 | 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.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"example": "import { useState } from \"react\";\nimport { ColorPicker, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <FormField id=\"brand-color\" label=\"Brand color\"
|
|
2
|
+
"example": "import { useState } from \"react\";\nimport { ColorPicker, Form, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <Form>\n <FormField id=\"brand-color\" label=\"Brand color\">\n <ColorPicker id=\"brand-color\" value={color} onValueChange={setColor} />\n </FormField>\n </Form>\n );\n}\n\n// Compact swatch-only variant (no hex input)\nexport function SwatchOnly() {\n const [color, setColor] = useState(\"#16a34a\");\n return <ColorPicker value={color} onValueChange={setColor} showHexInput={false} />;\n}\n\n// Fixed palette only (gh#1055): tags pick from presets, never free hex\nexport function TagColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n return (\n <Form>\n <FormField id=\"tag-color\" label=\"Tag colour\">\n <ColorPicker\n id=\"tag-color\"\n value={color}\n onValueChange={setColor}\n presets={[{ label: \"Palette\", colors: [\"#dc2626\", \"#16a34a\", \"#2563eb\", \"#9333ea\"] }]}\n panelRender={(_, { components: { Presets } }) => <Presets />}\n />\n </FormField>\n </Form>\n );\n}\n\n// Disabled state\nexport function DisabledColor() {\n return <ColorPicker value=\"#6b7280\" disabled />;\n}",
|
|
3
3
|
"group": "data-entry",
|
|
4
4
|
"importPath": "@godxjp/ui/data-entry",
|
|
5
5
|
"name": "ColorPicker",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
{
|
|
24
24
|
"defaultValue": "undefined",
|
|
25
25
|
"description": "Called with the normalized, validated hex string whenever the user commits a new color — via the native swatch picker or by pressing Enter / blurring the hex input. Not called for invalid hex drafts.",
|
|
26
|
-
"name": "
|
|
26
|
+
"name": "onValueChange",
|
|
27
27
|
"type": "(hex: string) => void"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
@@ -51,14 +51,21 @@
|
|
|
51
51
|
"type": "string"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
54
|
+
"defaultValue": "undefined",
|
|
55
|
+
"description": "antd `presets` (gh#1055) — named groups of fixed hex swatches under the picker. Each group is collapsible (`defaultOpen`, default true) and is an APG radio group: one tab stop, arrow keys move and select, each swatch is named by its hex and the one equal to `value` is checked. An empty `colors` shows the localized 'Empty' line. Hex only (#rgb/#rrggbb) — antd also accepts colour objects and gradients, which this picker has no model for.",
|
|
56
|
+
"name": "presets",
|
|
57
|
+
"type": "{ label: ReactNode; colors: string[]; defaultOpen?: boolean; key?: Key }[]"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"defaultValue": "undefined",
|
|
61
|
+
"description": "antd `panelRender` — replaces the picker body. `panel` is the default (swatch + hex row, then presets). PRESETS-ONLY mode (a fixed palette, no free hex): `panelRender={(_, { components: { Presets } }) => <Presets />}`. The hidden `name` input always renders outside the panel.",
|
|
62
|
+
"name": "panelRender",
|
|
63
|
+
"type": "(panel: ReactNode, extra: { components: { Picker: FC; Presets: FC } }) => ReactNode"
|
|
57
64
|
}
|
|
58
65
|
],
|
|
59
66
|
"related": [
|
|
60
67
|
"Input — use for plain text/number entry; use ColorPicker when the value is specifically a color hex code and you want a visual swatch.",
|
|
61
|
-
"Select / SearchSelect — use for choosing from a
|
|
68
|
+
"Select / SearchSelect — use for choosing from a list of colour NAMES (e.g. 'Red', 'Blue'); for a fixed palette of visible swatches use ColorPicker `presets` (presets-only via `panelRender`)."
|
|
62
69
|
],
|
|
63
70
|
"rules": [
|
|
64
71
|
2,
|
|
@@ -70,10 +77,11 @@
|
|
|
70
77
|
"tagline": "Native color-swatch picker with an optional editable hex input — always pass a valid 3- or 6-digit hex `value`; invalid hex is silently ignored and the previous value is restored.",
|
|
71
78
|
"usage": [
|
|
72
79
|
"DO wrap in FormField when a label or validation message is needed — pass the same id to both FormField and ColorPicker so htmlFor wires up correctly: `<FormField id='brand' label='Brand color'><ColorPicker id='brand' value={v} onValueChange={setV} /></FormField>`.",
|
|
73
|
-
"
|
|
80
|
+
"Use it controlled (value + onValueChange) or uncontrolled (defaultValue + onValueChange); both paths commit only validated hex.",
|
|
74
81
|
"DON'T pass an invalid or empty string to value — the component will flash the invalid color on the preview swatch. Always initialize state to a valid 3- or 6-digit hex (e.g. '#2563eb').",
|
|
75
|
-
"The hex Input is a live draft field —
|
|
82
|
+
"The hex Input is a live draft field — onValueChange is NOT called until the user presses Enter or blurs; only then is the value validated and the parent notified. Do not rely on onValueChange firing on every keystroke.",
|
|
76
83
|
"Set showHexInput={false} only for compact/inline contexts (icon pickers, table cells) where space is tight and keyboard hex entry is not needed.",
|
|
84
|
+
"DO use `presets` when the value must come from a fixed palette (tag / label colours) — add `panelRender={(_, { components: { Presets } }) => <Presets />}` to remove free hex entry entirely. NEVER rebuild a palette from a ToggleGroup of swatches.",
|
|
77
85
|
"NEVER hand-roll a color picker with raw <input type='color'> — always use this component; it normalizes hex, debounces draft state, and respects the design-token control styles."
|
|
78
86
|
],
|
|
79
87
|
"useCases": [
|
|
@@ -321,6 +321,28 @@
|
|
|
321
321
|
"name": "tokenSeparators",
|
|
322
322
|
"type": "string[]"
|
|
323
323
|
},
|
|
324
|
+
{
|
|
325
|
+
"defaultValue": "true",
|
|
326
|
+
"description": "mode=\"tags\" — whether typed text may become a NEW value (gh#1052). false, or a predicate returning false for the text, hides the create row and drops unknown tokenSeparators tokens; values already held stay listed so they can be removed. Not an antd prop.",
|
|
327
|
+
"name": "allowCreate",
|
|
328
|
+
"type": "boolean | ((text: string) => boolean)"
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"description": "mode=\"tags\" — the create row's content (gh#1052). Default is the localised Create “text” / 「text」を作成 / Tạo “text”. The committed value is the typed text either way. antd shows the bare text instead — a documented deviation.",
|
|
332
|
+
"name": "createLabel",
|
|
333
|
+
"type": "(text: string) => React.ReactNode"
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"description": "mode=\"tags\" — fires when a value that NO option carries joins the selection (create row, Enter on it, or a tokenSeparators run), beside onSelect/onValueChange. The way to tell invented text from an option id. Not an antd prop.",
|
|
337
|
+
"name": "onCreate",
|
|
338
|
+
"type": "(text: string) => void"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"defaultValue": "false",
|
|
342
|
+
"description": "Compare typed text case-sensitively (gh#1053). Default false: the built-in filter, the tags create row and a tokenSeparators run all case-fold, so typing \"bug\" when \"Bug\" exists finds Bug instead of offering a duplicate. antd folds its filter but compares the create row exactly; true restores that. A custom filterOption is unaffected.",
|
|
343
|
+
"name": "caseSensitive",
|
|
344
|
+
"type": "boolean"
|
|
345
|
+
},
|
|
324
346
|
{
|
|
325
347
|
"description": "antd `maxTagTextLength` (multiple/tags) — cut each chip's TEXT to this many characters (an ellipsis marks the cut). The value keeps its whole label.",
|
|
326
348
|
"name": "maxTagTextLength",
|
package/agent/components.json
CHANGED
|
@@ -6502,6 +6502,28 @@
|
|
|
6502
6502
|
"name": "tokenSeparators",
|
|
6503
6503
|
"type": "string[]"
|
|
6504
6504
|
},
|
|
6505
|
+
{
|
|
6506
|
+
"defaultValue": "true",
|
|
6507
|
+
"description": "mode=\"tags\" — whether typed text may become a NEW value (gh#1052). false, or a predicate returning false for the text, hides the create row and drops unknown tokenSeparators tokens; values already held stay listed so they can be removed. Not an antd prop.",
|
|
6508
|
+
"name": "allowCreate",
|
|
6509
|
+
"type": "boolean | ((text: string) => boolean)"
|
|
6510
|
+
},
|
|
6511
|
+
{
|
|
6512
|
+
"description": "mode=\"tags\" — the create row's content (gh#1052). Default is the localised Create “text” / 「text」を作成 / Tạo “text”. The committed value is the typed text either way. antd shows the bare text instead — a documented deviation.",
|
|
6513
|
+
"name": "createLabel",
|
|
6514
|
+
"type": "(text: string) => React.ReactNode"
|
|
6515
|
+
},
|
|
6516
|
+
{
|
|
6517
|
+
"description": "mode=\"tags\" — fires when a value that NO option carries joins the selection (create row, Enter on it, or a tokenSeparators run), beside onSelect/onValueChange. The way to tell invented text from an option id. Not an antd prop.",
|
|
6518
|
+
"name": "onCreate",
|
|
6519
|
+
"type": "(text: string) => void"
|
|
6520
|
+
},
|
|
6521
|
+
{
|
|
6522
|
+
"defaultValue": "false",
|
|
6523
|
+
"description": "Compare typed text case-sensitively (gh#1053). Default false: the built-in filter, the tags create row and a tokenSeparators run all case-fold, so typing \"bug\" when \"Bug\" exists finds Bug instead of offering a duplicate. antd folds its filter but compares the create row exactly; true restores that. A custom filterOption is unaffected.",
|
|
6524
|
+
"name": "caseSensitive",
|
|
6525
|
+
"type": "boolean"
|
|
6526
|
+
},
|
|
6505
6527
|
{
|
|
6506
6528
|
"description": "antd `maxTagTextLength` (multiple/tags) — cut each chip's TEXT to this many characters (an ellipsis marks the cut). The value keeps its whole label.",
|
|
6507
6529
|
"name": "maxTagTextLength",
|
|
@@ -9840,7 +9862,7 @@
|
|
|
9840
9862
|
]
|
|
9841
9863
|
},
|
|
9842
9864
|
{
|
|
9843
|
-
"example": "import { useState } from \"react\";\nimport { ColorPicker, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <FormField id=\"brand-color\" label=\"Brand color\"
|
|
9865
|
+
"example": "import { useState } from \"react\";\nimport { ColorPicker, Form, FormField } from \"@godxjp/ui/data-entry\";\n\nexport function BrandColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n\n return (\n <Form>\n <FormField id=\"brand-color\" label=\"Brand color\">\n <ColorPicker id=\"brand-color\" value={color} onValueChange={setColor} />\n </FormField>\n </Form>\n );\n}\n\n// Compact swatch-only variant (no hex input)\nexport function SwatchOnly() {\n const [color, setColor] = useState(\"#16a34a\");\n return <ColorPicker value={color} onValueChange={setColor} showHexInput={false} />;\n}\n\n// Fixed palette only (gh#1055): tags pick from presets, never free hex\nexport function TagColorField() {\n const [color, setColor] = useState(\"#2563eb\");\n return (\n <Form>\n <FormField id=\"tag-color\" label=\"Tag colour\">\n <ColorPicker\n id=\"tag-color\"\n value={color}\n onValueChange={setColor}\n presets={[{ label: \"Palette\", colors: [\"#dc2626\", \"#16a34a\", \"#2563eb\", \"#9333ea\"] }]}\n panelRender={(_, { components: { Presets } }) => <Presets />}\n />\n </FormField>\n </Form>\n );\n}\n\n// Disabled state\nexport function DisabledColor() {\n return <ColorPicker value=\"#6b7280\" disabled />;\n}",
|
|
9844
9866
|
"group": "data-entry",
|
|
9845
9867
|
"importPath": "@godxjp/ui/data-entry",
|
|
9846
9868
|
"name": "ColorPicker",
|
|
@@ -9864,7 +9886,7 @@
|
|
|
9864
9886
|
{
|
|
9865
9887
|
"defaultValue": "undefined",
|
|
9866
9888
|
"description": "Called with the normalized, validated hex string whenever the user commits a new color — via the native swatch picker or by pressing Enter / blurring the hex input. Not called for invalid hex drafts.",
|
|
9867
|
-
"name": "
|
|
9889
|
+
"name": "onValueChange",
|
|
9868
9890
|
"type": "(hex: string) => void"
|
|
9869
9891
|
},
|
|
9870
9892
|
{
|
|
@@ -9892,14 +9914,21 @@
|
|
|
9892
9914
|
"type": "string"
|
|
9893
9915
|
},
|
|
9894
9916
|
{
|
|
9895
|
-
"
|
|
9896
|
-
"
|
|
9897
|
-
"
|
|
9917
|
+
"defaultValue": "undefined",
|
|
9918
|
+
"description": "antd `presets` (gh#1055) — named groups of fixed hex swatches under the picker. Each group is collapsible (`defaultOpen`, default true) and is an APG radio group: one tab stop, arrow keys move and select, each swatch is named by its hex and the one equal to `value` is checked. An empty `colors` shows the localized 'Empty' line. Hex only (#rgb/#rrggbb) — antd also accepts colour objects and gradients, which this picker has no model for.",
|
|
9919
|
+
"name": "presets",
|
|
9920
|
+
"type": "{ label: ReactNode; colors: string[]; defaultOpen?: boolean; key?: Key }[]"
|
|
9921
|
+
},
|
|
9922
|
+
{
|
|
9923
|
+
"defaultValue": "undefined",
|
|
9924
|
+
"description": "antd `panelRender` — replaces the picker body. `panel` is the default (swatch + hex row, then presets). PRESETS-ONLY mode (a fixed palette, no free hex): `panelRender={(_, { components: { Presets } }) => <Presets />}`. The hidden `name` input always renders outside the panel.",
|
|
9925
|
+
"name": "panelRender",
|
|
9926
|
+
"type": "(panel: ReactNode, extra: { components: { Picker: FC; Presets: FC } }) => ReactNode"
|
|
9898
9927
|
}
|
|
9899
9928
|
],
|
|
9900
9929
|
"related": [
|
|
9901
9930
|
"Input — use for plain text/number entry; use ColorPicker when the value is specifically a color hex code and you want a visual swatch.",
|
|
9902
|
-
"Select / SearchSelect — use for choosing from a
|
|
9931
|
+
"Select / SearchSelect — use for choosing from a list of colour NAMES (e.g. 'Red', 'Blue'); for a fixed palette of visible swatches use ColorPicker `presets` (presets-only via `panelRender`)."
|
|
9903
9932
|
],
|
|
9904
9933
|
"rules": [
|
|
9905
9934
|
2,
|
|
@@ -9911,10 +9940,11 @@
|
|
|
9911
9940
|
"tagline": "Native color-swatch picker with an optional editable hex input — always pass a valid 3- or 6-digit hex `value`; invalid hex is silently ignored and the previous value is restored.",
|
|
9912
9941
|
"usage": [
|
|
9913
9942
|
"DO wrap in FormField when a label or validation message is needed — pass the same id to both FormField and ColorPicker so htmlFor wires up correctly: `<FormField id='brand' label='Brand color'><ColorPicker id='brand' value={v} onValueChange={setV} /></FormField>`.",
|
|
9914
|
-
"
|
|
9943
|
+
"Use it controlled (value + onValueChange) or uncontrolled (defaultValue + onValueChange); both paths commit only validated hex.",
|
|
9915
9944
|
"DON'T pass an invalid or empty string to value — the component will flash the invalid color on the preview swatch. Always initialize state to a valid 3- or 6-digit hex (e.g. '#2563eb').",
|
|
9916
|
-
"The hex Input is a live draft field —
|
|
9945
|
+
"The hex Input is a live draft field — onValueChange is NOT called until the user presses Enter or blurs; only then is the value validated and the parent notified. Do not rely on onValueChange firing on every keystroke.",
|
|
9917
9946
|
"Set showHexInput={false} only for compact/inline contexts (icon pickers, table cells) where space is tight and keyboard hex entry is not needed.",
|
|
9947
|
+
"DO use `presets` when the value must come from a fixed palette (tag / label colours) — add `panelRender={(_, { components: { Presets } }) => <Presets />}` to remove free hex entry entirely. NEVER rebuild a palette from a ToggleGroup of swatches.",
|
|
9918
9948
|
"NEVER hand-roll a color picker with raw <input type='color'> — always use this component; it normalizes hex, debounces draft state, and respects the design-token control styles."
|
|
9919
9949
|
],
|
|
9920
9950
|
"useCases": [
|
package/agent/index.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"components": 177,
|
|
5
5
|
"patterns": 21,
|
|
6
6
|
"rules": 50,
|
|
7
|
-
"tokens":
|
|
7
|
+
"tokens": 2104,
|
|
8
8
|
"vocabulary": 14
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
@@ -48,19 +48,19 @@
|
|
|
48
48
|
"note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
|
|
49
49
|
"read": {
|
|
50
50
|
"live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
|
|
51
|
-
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.
|
|
51
|
+
"pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v31.8.0/agent/index.json"
|
|
52
52
|
},
|
|
53
53
|
"source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
|
|
54
54
|
"start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
|
|
55
55
|
"tokenTiers": {
|
|
56
56
|
"component": "per-part knobs, --{component}-{part}-{property}; usually leave these alone",
|
|
57
57
|
"counts": {
|
|
58
|
-
"component":
|
|
58
|
+
"component": 1789,
|
|
59
59
|
"foundation": 211,
|
|
60
60
|
"semantic": 104
|
|
61
61
|
},
|
|
62
62
|
"foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
|
|
63
63
|
"semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
|
|
64
64
|
},
|
|
65
|
-
"version": "31.
|
|
65
|
+
"version": "31.8.0"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
|
-
> A Japanese-enterprise React design system: 177 components,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.
|
|
3
|
+
> A Japanese-enterprise React design system: 177 components, 2104 design tokens,
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.8.0.
|
|
5
5
|
|
|
6
6
|
If your client can run a process, do not read these files — run the MCP server instead
|
|
7
|
-
(`npx @godxjp/ui-mcp@31.
|
|
7
|
+
(`npx @godxjp/ui-mcp@31.8.0`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -18,7 +18,7 @@ that can only fetch URLs.
|
|
|
18
18
|
- [components-index.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json): 47 KB — all 177 components as name, group, tagline, plus `absorbed`: the names that do NOT exist and map to it (`Combobox` → `Select`).
|
|
19
19
|
- [components/<Name>.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json): one file per component (1 KB–36 KB, median 6 KB). Read the index, then fetch only the ones you chose — this is the selective route, and the reason you do not need the blob.
|
|
20
20
|
- [components.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components.json): 1.2 MB — every entry in one file. Most URL fetchers truncate a response this size without saying so; prefer the per-component files.
|
|
21
|
-
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 104 `semantic` roles,
|
|
21
|
+
- [tokens.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/tokens.json): every design token with its value, the reason it exists, and its `tier` — 211 `foundation` seeds (`--primary`, `--background`, `--radius`: set these when you are handed a brand), 104 `semantic` roles, 1789 `component` knobs.
|
|
22
22
|
- [vocabulary.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/vocabulary.json): the controlled prop vocabulary — which prop name means what, across every component.
|
|
23
23
|
- [rules.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/rules.json): 50 cardinal rules.
|
|
24
24
|
- [anti-ai-tells.json](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/anti-ai-tells.json): 26 shapes that make generated UI look generated, each with its fix.
|
|
@@ -26,7 +26,7 @@ that can only fetch URLs.
|
|
|
26
26
|
## Pinning
|
|
27
27
|
|
|
28
28
|
Every URL above tracks `main`. To pin to the release a project actually installed, swap `main` for
|
|
29
|
-
the tag: `.../godx-jp/godxjp-ui/v31.
|
|
29
|
+
the tag: `.../godx-jp/godxjp-ui/v31.8.0/agent/...`. A catalog that does not match the installed
|
|
30
30
|
package describes props that are absent, or hides props that are present, and says nothing either way.
|
|
31
31
|
|
|
32
32
|
Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.
|
package/agent/tokens.json
CHANGED
|
@@ -3647,6 +3647,24 @@
|
|
|
3647
3647
|
"tier": "component",
|
|
3648
3648
|
"value": "6.5rem"
|
|
3649
3649
|
},
|
|
3650
|
+
{
|
|
3651
|
+
"description": "ColorPicker `presets` (gh#1055). The swatch box IS the radio's pointer target, so it sits on the WCAG 2.2 SC 2.5.8 floor (antd's own preset block is 24px too) and never rides --scaling below it. The gap leaves room for the checked ring, which is drawn outside the box.",
|
|
3652
|
+
"name": "--color-picker-preset-size",
|
|
3653
|
+
"tier": "component",
|
|
3654
|
+
"value": "var(--touch-target-min)"
|
|
3655
|
+
},
|
|
3656
|
+
{
|
|
3657
|
+
"description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
|
|
3658
|
+
"name": "--color-picker-preset-gap",
|
|
3659
|
+
"tier": "component",
|
|
3660
|
+
"value": "var(--space-2)"
|
|
3661
|
+
},
|
|
3662
|
+
{
|
|
3663
|
+
"description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
|
|
3664
|
+
"name": "--color-picker-presets-gap",
|
|
3665
|
+
"tier": "component",
|
|
3666
|
+
"value": "var(--space-1)"
|
|
3667
|
+
},
|
|
3650
3668
|
{
|
|
3651
3669
|
"description": "Command / CommandPalette — list height, inner paddings and the palette's own box.",
|
|
3652
3670
|
"name": "--command-list-max-height",
|
|
@@ -3773,6 +3791,12 @@
|
|
|
3773
3791
|
"tier": "component",
|
|
3774
3792
|
"value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
|
|
3775
3793
|
},
|
|
3794
|
+
{
|
|
3795
|
+
"description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
|
|
3796
|
+
"name": "--color-picker-presets-font-size",
|
|
3797
|
+
"tier": "component",
|
|
3798
|
+
"value": "var( --font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)) )"
|
|
3799
|
+
},
|
|
3776
3800
|
{
|
|
3777
3801
|
"description": "Control primitive tokens: heights, horizontal padding, adjacent control sizes.",
|
|
3778
3802
|
"name": "--command-group-heading-font-size",
|
|
@@ -9,6 +9,7 @@ import { omitFieldA11y, pickFieldA11y, useFieldIdentity } from "../../lib/field-
|
|
|
9
9
|
import { Button } from "../general/button.js";
|
|
10
10
|
import { Textarea } from "./textarea.js";
|
|
11
11
|
import { controlSurfaceAttrs, resolveAriaInvalid } from "./control-surface.js";
|
|
12
|
+
import { isImeComposing } from "../../lib/ime.js";
|
|
12
13
|
function isSendable(text) {
|
|
13
14
|
return text.trim().length > 0;
|
|
14
15
|
}
|
|
@@ -70,9 +71,7 @@ const ChatComposer = React.forwardRef(
|
|
|
70
71
|
onKeyDown?.(event);
|
|
71
72
|
if (event.defaultPrevented) return;
|
|
72
73
|
if (event.key !== "Enter") return;
|
|
73
|
-
if (composing.current || event
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
74
|
+
if (composing.current || isImeComposing(event)) return;
|
|
76
75
|
const wantsSend = submitType === "modEnter" ? (
|
|
77
76
|
// ⌘ on Apple platforms, Ctrl everywhere else — the other one is left alone, because
|
|
78
77
|
// Ctrl+Enter on a Mac is not the convention a Mac user reaches for.
|
|
@@ -85,7 +84,15 @@ const ChatComposer = React.forwardRef(
|
|
|
85
84
|
const sendName = submitLabel ?? t("dataEntry.chatComposer.send");
|
|
86
85
|
const cancelName = cancelLabel ?? t("dataEntry.chatComposer.cancel");
|
|
87
86
|
const actionSize = size === "xs" ? "icon-xs" : size === "sm" ? "icon-sm" : size === "lg" ? "icon-lg" : "icon";
|
|
88
|
-
const liveRef = React.useRef({
|
|
87
|
+
const liveRef = React.useRef({
|
|
88
|
+
actionSize,
|
|
89
|
+
sendName,
|
|
90
|
+
cancelName,
|
|
91
|
+
submit,
|
|
92
|
+
onCancel,
|
|
93
|
+
canSubmit,
|
|
94
|
+
disabled
|
|
95
|
+
});
|
|
89
96
|
liveRef.current = { actionSize, sendName, cancelName, submit, onCancel, canSubmit, disabled };
|
|
90
97
|
const SubmitButton = React.useMemo(
|
|
91
98
|
() => function SubmitButton2(buttonProps) {
|
|
@@ -6,6 +6,7 @@ import { cn } from "../../lib/utils.js";
|
|
|
6
6
|
import { VisuallyHidden } from "../general/visually-hidden.js";
|
|
7
7
|
import { Popover, PopoverAnchor, PopoverContent } from "../data-display/popover.js";
|
|
8
8
|
import { Command, CommandEmpty, CommandItem, CommandList } from "./command.js";
|
|
9
|
+
import { isImeComposing } from "../../lib/ime.js";
|
|
9
10
|
function matchTrigger(text, caret, trigger) {
|
|
10
11
|
if (!trigger) return null;
|
|
11
12
|
const before = text.slice(0, caret);
|
|
@@ -154,6 +155,7 @@ function ChatSuggestion({
|
|
|
154
155
|
);
|
|
155
156
|
const onKeyDown = React.useCallback(
|
|
156
157
|
(event) => {
|
|
158
|
+
if (isImeComposing(event)) return;
|
|
157
159
|
if (!openRef.current) {
|
|
158
160
|
if (event.key.startsWith("Arrow") || event.key === "Home" || event.key === "End") {
|
|
159
161
|
window.setTimeout(evaluate, 0);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import type { ColorPickerProp } from "../../props/components/data-entry.prop.js";
|
|
3
|
-
export type { ColorPickerProp, ColorPickerProp as ColorPickerProps, } from "../../props/components/data-entry.prop.js";
|
|
4
|
-
export declare function ColorPicker({ value: valueProp, defaultValue, onValueChange, disabled, name, className, id, showHexInput, ...ariaProps }: ColorPickerProp): React.JSX.Element;
|
|
3
|
+
export type { ColorPickerProp, ColorPickerProp as ColorPickerProps, ColorPickerPresetProp, ColorPickerPresetProp as ColorPickerPresetProps, } from "../../props/components/data-entry.prop.js";
|
|
4
|
+
export declare function ColorPicker({ value: valueProp, defaultValue, onValueChange, disabled, name, className, id, showHexInput, presets, panelRender, ...ariaProps }: ColorPickerProp): React.JSX.Element;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import { ChevronDown } from "lucide-react";
|
|
5
|
+
import { Radio as AriaRadio, RadioGroup as AriaRadioGroup } from "react-aria-components";
|
|
4
6
|
import { useTranslation } from "../../i18n/use-translation.js";
|
|
5
7
|
import { cn } from "../../lib/utils.js";
|
|
8
|
+
import { isImeComposing } from "../../lib/ime.js";
|
|
6
9
|
import { resolveFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
|
|
7
10
|
import { controlIconClass } from "../../lib/control-styles.js";
|
|
11
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../data-display/collapsible.js";
|
|
8
12
|
import { Input } from "./input.js";
|
|
9
13
|
const HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
10
14
|
const NATIVE_COLOR_FALLBACK = "#000000";
|
|
@@ -12,6 +16,68 @@ function normalizeHex(value) {
|
|
|
12
16
|
if (!value.startsWith("#")) return `#${value}`;
|
|
13
17
|
return value;
|
|
14
18
|
}
|
|
19
|
+
function colorKey(value) {
|
|
20
|
+
const hex = normalizeHex(value.trim()).toLowerCase();
|
|
21
|
+
if (!HEX_PATTERN.test(hex)) return hex;
|
|
22
|
+
if (hex.length === 4) return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
|
|
23
|
+
return hex;
|
|
24
|
+
}
|
|
25
|
+
const ColorPickerPartsContext = React.createContext(null);
|
|
26
|
+
function ColorPickerPickerPart() {
|
|
27
|
+
return /* @__PURE__ */ jsx(Fragment, { children: React.useContext(ColorPickerPartsContext)?.picker });
|
|
28
|
+
}
|
|
29
|
+
function ColorPickerPresetsPart() {
|
|
30
|
+
return /* @__PURE__ */ jsx(Fragment, { children: React.useContext(ColorPickerPartsContext)?.presets });
|
|
31
|
+
}
|
|
32
|
+
const PANEL_COMPONENTS = { Picker: ColorPickerPickerPart, Presets: ColorPickerPresetsPart };
|
|
33
|
+
function ColorPickerPresetGroup({
|
|
34
|
+
preset,
|
|
35
|
+
value,
|
|
36
|
+
disabled,
|
|
37
|
+
onSelect
|
|
38
|
+
}) {
|
|
39
|
+
const { t } = useTranslation();
|
|
40
|
+
const labelId = React.useId();
|
|
41
|
+
const currentKey = colorKey(value);
|
|
42
|
+
const checked = preset.colors.find((color) => colorKey(color) === currentKey) ?? null;
|
|
43
|
+
return /* @__PURE__ */ jsxs(
|
|
44
|
+
Collapsible,
|
|
45
|
+
{
|
|
46
|
+
defaultOpen: preset.defaultOpen ?? true,
|
|
47
|
+
className: "ui-color-picker-presets-group",
|
|
48
|
+
"data-slot": "color-picker-presets-group",
|
|
49
|
+
children: [
|
|
50
|
+
/* @__PURE__ */ jsxs(CollapsibleTrigger, { className: "ui-color-picker-presets-trigger ui-focus-ring", children: [
|
|
51
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "ui-color-picker-presets-chevron", "aria-hidden": "true" }),
|
|
52
|
+
/* @__PURE__ */ jsx("span", { id: labelId, className: "ui-color-picker-presets-label", children: preset.label })
|
|
53
|
+
] }),
|
|
54
|
+
/* @__PURE__ */ jsx(CollapsibleContent, { className: "ui-color-picker-presets-content", children: preset.colors.length > 0 ? /* @__PURE__ */ jsx(
|
|
55
|
+
AriaRadioGroup,
|
|
56
|
+
{
|
|
57
|
+
"aria-labelledby": labelId,
|
|
58
|
+
orientation: "horizontal",
|
|
59
|
+
value: checked,
|
|
60
|
+
onChange: onSelect,
|
|
61
|
+
isDisabled: disabled,
|
|
62
|
+
className: "ui-color-picker-presets-items",
|
|
63
|
+
"data-slot": "color-picker-presets-items",
|
|
64
|
+
children: preset.colors.map((color, index) => /* @__PURE__ */ jsx(
|
|
65
|
+
AriaRadio,
|
|
66
|
+
{
|
|
67
|
+
value: color,
|
|
68
|
+
"aria-label": color,
|
|
69
|
+
className: "ui-color-picker-presets-color ui-focus-ring",
|
|
70
|
+
"data-slot": "color-picker-preset",
|
|
71
|
+
style: { ["--color-picker-preset-color"]: color }
|
|
72
|
+
},
|
|
73
|
+
`${index}-${color}`
|
|
74
|
+
))
|
|
75
|
+
}
|
|
76
|
+
) : /* @__PURE__ */ jsx("span", { className: "ui-color-picker-presets-empty", children: t("dataEntry.colorPicker.presetEmpty") }) })
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
15
81
|
function ColorPicker({
|
|
16
82
|
value: valueProp,
|
|
17
83
|
defaultValue,
|
|
@@ -21,6 +87,8 @@ function ColorPicker({
|
|
|
21
87
|
className,
|
|
22
88
|
id,
|
|
23
89
|
showHexInput = true,
|
|
90
|
+
presets,
|
|
91
|
+
panelRender,
|
|
24
92
|
...ariaProps
|
|
25
93
|
}) {
|
|
26
94
|
const { t } = useTranslation();
|
|
@@ -43,48 +111,93 @@ function ColorPicker({
|
|
|
43
111
|
if (!isControlled) setInternalValue(normalized);
|
|
44
112
|
onValueChange?.(normalized);
|
|
45
113
|
};
|
|
46
|
-
|
|
47
|
-
/* @__PURE__ */
|
|
114
|
+
const swatch = /* @__PURE__ */ jsxs("div", { className: cn("ui-color-picker-swatch", controlIconClass), children: [
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
116
|
+
"div",
|
|
117
|
+
{
|
|
118
|
+
className: "ui-color-picker-preview",
|
|
119
|
+
style: { backgroundColor: swatchValue },
|
|
120
|
+
"aria-hidden": "true"
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
"input",
|
|
125
|
+
{
|
|
126
|
+
id,
|
|
127
|
+
type: "color",
|
|
128
|
+
value: swatchValue,
|
|
129
|
+
disabled,
|
|
130
|
+
onChange: (event) => commit(event.target.value),
|
|
131
|
+
className: "ui-color-picker-input",
|
|
132
|
+
"data-field": ariaProps["data-field"] ?? identity["data-field"],
|
|
133
|
+
...swatchA11y
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
] });
|
|
137
|
+
const hexInput = showHexInput ? /* @__PURE__ */ jsx(
|
|
138
|
+
Input,
|
|
139
|
+
{
|
|
140
|
+
id: id ? `${id}-hex` : void 0,
|
|
141
|
+
value: display,
|
|
142
|
+
disabled,
|
|
143
|
+
"aria-label": t("dataEntry.colorPicker.hexLabel"),
|
|
144
|
+
onChange: (event) => setDraft(event.target.value),
|
|
145
|
+
onBlur: () => commit(display),
|
|
146
|
+
onKeyDown: (event) => {
|
|
147
|
+
if (event.key === "Enter" && !isImeComposing(event)) commit(display);
|
|
148
|
+
},
|
|
149
|
+
className: "ui-color-picker-hex",
|
|
150
|
+
spellCheck: false
|
|
151
|
+
}
|
|
152
|
+
) : null;
|
|
153
|
+
const hiddenInput = resolvedName ? /* @__PURE__ */ jsx("input", { type: "hidden", name: resolvedName, value, readOnly: true }) : null;
|
|
154
|
+
if (!presets && !panelRender) {
|
|
155
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("ui-color-picker", className), children: [
|
|
156
|
+
swatch,
|
|
157
|
+
hexInput,
|
|
158
|
+
hiddenInput
|
|
159
|
+
] });
|
|
160
|
+
}
|
|
161
|
+
const presetsNamed = Boolean(ariaProps["aria-labelledby"] ?? ariaProps["aria-label"]);
|
|
162
|
+
const parts = {
|
|
163
|
+
picker: /* @__PURE__ */ jsxs("div", { className: "ui-color-picker-picker", "data-slot": "color-picker-picker", children: [
|
|
164
|
+
swatch,
|
|
165
|
+
hexInput
|
|
166
|
+
] }),
|
|
167
|
+
presets: presets?.length ? (
|
|
168
|
+
// The FormField name/description also reach the palette as a GROUP, so presets-only mode
|
|
169
|
+
// (no native swatch to carry them) still announces which field these swatches fill.
|
|
48
170
|
/* @__PURE__ */ jsx(
|
|
49
171
|
"div",
|
|
50
172
|
{
|
|
51
|
-
className: "ui-color-picker-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
173
|
+
className: "ui-color-picker-presets",
|
|
174
|
+
"data-slot": "color-picker-presets",
|
|
175
|
+
role: presetsNamed ? "group" : void 0,
|
|
176
|
+
"aria-labelledby": ariaProps["aria-labelledby"],
|
|
177
|
+
"aria-label": ariaProps["aria-labelledby"] ? void 0 : ariaProps["aria-label"],
|
|
178
|
+
"aria-describedby": ariaProps["aria-describedby"],
|
|
179
|
+
children: presets.map((preset, index) => /* @__PURE__ */ jsx(
|
|
180
|
+
ColorPickerPresetGroup,
|
|
181
|
+
{
|
|
182
|
+
preset,
|
|
183
|
+
value,
|
|
184
|
+
disabled,
|
|
185
|
+
onSelect: commit
|
|
186
|
+
},
|
|
187
|
+
preset.key ?? index
|
|
188
|
+
))
|
|
67
189
|
}
|
|
68
190
|
)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
value: display,
|
|
75
|
-
disabled,
|
|
76
|
-
"aria-label": t("dataEntry.colorPicker.hexLabel"),
|
|
77
|
-
onChange: (event) => setDraft(event.target.value),
|
|
78
|
-
onBlur: () => commit(display),
|
|
79
|
-
onKeyDown: (event) => {
|
|
80
|
-
if (event.key === "Enter") commit(display);
|
|
81
|
-
},
|
|
82
|
-
className: "ui-color-picker-hex",
|
|
83
|
-
spellCheck: false
|
|
84
|
-
}
|
|
85
|
-
),
|
|
86
|
-
resolvedName ? /* @__PURE__ */ jsx("input", { type: "hidden", name: resolvedName, value, readOnly: true }) : null
|
|
191
|
+
) : null
|
|
192
|
+
};
|
|
193
|
+
const panel = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
194
|
+
parts.picker,
|
|
195
|
+
parts.presets
|
|
87
196
|
] });
|
|
197
|
+
return /* @__PURE__ */ jsx(ColorPickerPartsContext.Provider, { value: parts, children: /* @__PURE__ */ jsxs("div", { className: cn("ui-color-picker", className), "data-panel": "", children: [
|
|
198
|
+
panelRender ? panelRender(panel, { components: PANEL_COMPONENTS }) : panel,
|
|
199
|
+
hiddenInput
|
|
200
|
+
] }) });
|
|
88
201
|
}
|
|
89
202
|
export {
|
|
90
203
|
ColorPicker
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
CommandItem,
|
|
13
13
|
CommandList
|
|
14
14
|
} from "./command.js";
|
|
15
|
+
import { isImeComposing } from "../../lib/ime.js";
|
|
15
16
|
function CommandPalette({
|
|
16
17
|
groups,
|
|
17
18
|
labels,
|
|
@@ -61,7 +62,7 @@ function CommandPalette({
|
|
|
61
62
|
React.useEffect(() => {
|
|
62
63
|
if (!shortcut) return;
|
|
63
64
|
const handleKeyDown = (event) => {
|
|
64
|
-
if (!event
|
|
65
|
+
if (!isImeComposing(event) && event.key.toLowerCase() === "k" && (event.metaKey || event.ctrlKey)) {
|
|
65
66
|
event.preventDefault();
|
|
66
67
|
if (!open && document.activeElement instanceof HTMLElement) {
|
|
67
68
|
shortcutRestoreFocusRef.current = document.activeElement;
|