@godxjp/ui 31.21.0 → 31.22.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 +1 -1
- package/agent/components/ChatSuggestion.json +23 -1
- package/agent/components/CommandPalette.json +8 -2
- package/agent/components.json +31 -3
- package/agent/index.json +2 -2
- package/agent/llms.txt +3 -3
- package/dist/components/data-entry/chat-suggestion.d.ts +1 -1
- package/dist/components/data-entry/chat-suggestion.js +17 -8
- package/dist/components/data-entry/command-palette.d.ts +20 -2
- package/dist/components/data-entry/command-palette.js +99 -39
- package/dist/components/data-entry/index.d.ts +1 -1
- package/dist/contracts/measurement.json +1 -1
- package/dist/props/components/data-entry.prop.d.ts +15 -1
- package/dist/styles/layers.json +1 -1
- package/dist/styles/layout.css +2 -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.22.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.
|
|
@@ -18,10 +18,32 @@
|
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"defaultValue": "\"/\"",
|
|
21
|
-
"description": "The character that
|
|
21
|
+
"description": "The character(s) that open the list when typed at a boundary — the start, whitespace, or any non-ASCII character, so `[[` opens right after Japanese text (gh#1127); an ASCII letter still blocks it, so `https://x` opens nothing. Use \"@\" for mentions, \"[[\" for a link picker.",
|
|
22
22
|
"name": "triggerCharacter",
|
|
23
23
|
"type": "string"
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
"defaultValue": "false",
|
|
27
|
+
"description": "Spaces may appear inside the query (a `[[` link picker searching \"Meeting notes\"); a line break still ends it (gh#1127).",
|
|
28
|
+
"name": "allowSpaces",
|
|
29
|
+
"type": "boolean"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"description": "Typing this inside the query finishes the token and closes the list, e.g. `]]` (gh#1127).",
|
|
33
|
+
"name": "terminator",
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"defaultValue": "true",
|
|
38
|
+
"description": "`false` when the host answers the query itself (async, via `onQueryChange`) and `items` already holds the matches — they are shown as given, not filtered again (gh#1127).",
|
|
39
|
+
"name": "shouldFilter",
|
|
40
|
+
"type": "boolean"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"description": "The query typed after the trigger, on every change while the list is open — the seam for server-side search (gh#1127).",
|
|
44
|
+
"name": "onQueryChange",
|
|
45
|
+
"type": "(query: string) => void"
|
|
46
|
+
},
|
|
25
47
|
{
|
|
26
48
|
"description": "Controlled open state of the list.",
|
|
27
49
|
"name": "open",
|
|
@@ -17,10 +17,16 @@
|
|
|
17
17
|
"type": "CommandPaletteLabels"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
"description": "Consumer-owned selection handler.",
|
|
20
|
+
"description": "Consumer-owned selection handler. The second argument carries the modifier keys held on the Enter or click that chose the item — build \"open in split / new tab\" on ⌘/Ctrl/Shift (gh#1126).",
|
|
21
21
|
"name": "onSelect",
|
|
22
22
|
"required": true,
|
|
23
|
-
"type": "(item: CommandPaletteItem) => void"
|
|
23
|
+
"type": "(item: CommandPaletteItem, modifiers: { metaKey, ctrlKey, shiftKey, altKey }) => void"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"defaultValue": "true",
|
|
27
|
+
"description": "The global toggle shortcut. `true` = ⌘K / Ctrl+K, `false` = none, or a combo string — `\"mod+o\"`, `\"mod+p\"`, `\"mod+shift+p\"` — so a quick switcher and a command palette can live side by side. `mod` is ⌘ or Ctrl; Shift / Alt must match exactly. Never fires during IME composition; the default trigger shows the combo (gh#1126).",
|
|
28
|
+
"name": "shortcut",
|
|
29
|
+
"type": "boolean | string"
|
|
24
30
|
},
|
|
25
31
|
{
|
|
26
32
|
"description": "Controlled open state.",
|
package/agent/components.json
CHANGED
|
@@ -14147,10 +14147,16 @@
|
|
|
14147
14147
|
"type": "CommandPaletteLabels"
|
|
14148
14148
|
},
|
|
14149
14149
|
{
|
|
14150
|
-
"description": "Consumer-owned selection handler.",
|
|
14150
|
+
"description": "Consumer-owned selection handler. The second argument carries the modifier keys held on the Enter or click that chose the item — build \"open in split / new tab\" on ⌘/Ctrl/Shift (gh#1126).",
|
|
14151
14151
|
"name": "onSelect",
|
|
14152
14152
|
"required": true,
|
|
14153
|
-
"type": "(item: CommandPaletteItem) => void"
|
|
14153
|
+
"type": "(item: CommandPaletteItem, modifiers: { metaKey, ctrlKey, shiftKey, altKey }) => void"
|
|
14154
|
+
},
|
|
14155
|
+
{
|
|
14156
|
+
"defaultValue": "true",
|
|
14157
|
+
"description": "The global toggle shortcut. `true` = ⌘K / Ctrl+K, `false` = none, or a combo string — `\"mod+o\"`, `\"mod+p\"`, `\"mod+shift+p\"` — so a quick switcher and a command palette can live side by side. `mod` is ⌘ or Ctrl; Shift / Alt must match exactly. Never fires during IME composition; the default trigger shows the combo (gh#1126).",
|
|
14158
|
+
"name": "shortcut",
|
|
14159
|
+
"type": "boolean | string"
|
|
14154
14160
|
},
|
|
14155
14161
|
{
|
|
14156
14162
|
"description": "Controlled open state.",
|
|
@@ -15477,10 +15483,32 @@
|
|
|
15477
15483
|
},
|
|
15478
15484
|
{
|
|
15479
15485
|
"defaultValue": "\"/\"",
|
|
15480
|
-
"description": "The character that
|
|
15486
|
+
"description": "The character(s) that open the list when typed at a boundary — the start, whitespace, or any non-ASCII character, so `[[` opens right after Japanese text (gh#1127); an ASCII letter still blocks it, so `https://x` opens nothing. Use \"@\" for mentions, \"[[\" for a link picker.",
|
|
15481
15487
|
"name": "triggerCharacter",
|
|
15482
15488
|
"type": "string"
|
|
15483
15489
|
},
|
|
15490
|
+
{
|
|
15491
|
+
"defaultValue": "false",
|
|
15492
|
+
"description": "Spaces may appear inside the query (a `[[` link picker searching \"Meeting notes\"); a line break still ends it (gh#1127).",
|
|
15493
|
+
"name": "allowSpaces",
|
|
15494
|
+
"type": "boolean"
|
|
15495
|
+
},
|
|
15496
|
+
{
|
|
15497
|
+
"description": "Typing this inside the query finishes the token and closes the list, e.g. `]]` (gh#1127).",
|
|
15498
|
+
"name": "terminator",
|
|
15499
|
+
"type": "string"
|
|
15500
|
+
},
|
|
15501
|
+
{
|
|
15502
|
+
"defaultValue": "true",
|
|
15503
|
+
"description": "`false` when the host answers the query itself (async, via `onQueryChange`) and `items` already holds the matches — they are shown as given, not filtered again (gh#1127).",
|
|
15504
|
+
"name": "shouldFilter",
|
|
15505
|
+
"type": "boolean"
|
|
15506
|
+
},
|
|
15507
|
+
{
|
|
15508
|
+
"description": "The query typed after the trigger, on every change while the list is open — the seam for server-side search (gh#1127).",
|
|
15509
|
+
"name": "onQueryChange",
|
|
15510
|
+
"type": "(query: string) => void"
|
|
15511
|
+
},
|
|
15484
15512
|
{
|
|
15485
15513
|
"description": "Controlled open state of the list.",
|
|
15486
15514
|
"name": "open",
|
package/agent/index.json
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
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.22.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",
|
|
@@ -62,5 +62,5 @@
|
|
|
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.22.0"
|
|
66
66
|
}
|
package/agent/llms.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# @godxjp/ui
|
|
2
2
|
|
|
3
3
|
> A Japanese-enterprise React design system: 181 components, 2129 design tokens,
|
|
4
|
-
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.
|
|
4
|
+
> 50 cardinal rules. This file is the entry point for AI agents. Catalog version 31.22.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.22.0`). It is searchable and version-locked. These files exist for agents
|
|
8
8
|
that can only fetch URLs.
|
|
9
9
|
|
|
10
10
|
## Start
|
|
@@ -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.22.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.
|
|
@@ -22,7 +22,7 @@ export type { ChatSuggestionProp, ChatSuggestionProp as ChatSuggestionProps, Cha
|
|
|
22
22
|
* typed text exactly as it was; a suggestion list that eats the draft on dismiss is the defect
|
|
23
23
|
* this guards.
|
|
24
24
|
*/
|
|
25
|
-
export declare function ChatSuggestion({ items, onValueChange, triggerCharacter, open, defaultOpen, onOpenChange, children, emptyMessage, listLabel: listLabelProp, id, className, }: ChatSuggestionProp): React.JSX.Element;
|
|
25
|
+
export declare function ChatSuggestion({ items, onValueChange, triggerCharacter, open, defaultOpen, onOpenChange, children, emptyMessage, listLabel: listLabelProp, id, className, allowSpaces, terminator, shouldFilter, onQueryChange, }: ChatSuggestionProp): React.JSX.Element;
|
|
26
26
|
export declare namespace ChatSuggestion {
|
|
27
27
|
var displayName: string;
|
|
28
28
|
}
|
|
@@ -7,15 +7,16 @@ 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
9
|
import { isImeComposing } from "../../lib/ime.js";
|
|
10
|
-
function matchTrigger(text, caret, trigger) {
|
|
10
|
+
function matchTrigger(text, caret, trigger, { allowSpaces = false, terminator } = {}) {
|
|
11
11
|
if (!trigger) return null;
|
|
12
12
|
const before = text.slice(0, caret);
|
|
13
13
|
const start = before.lastIndexOf(trigger);
|
|
14
14
|
if (start === -1) return null;
|
|
15
15
|
const query = before.slice(start + trigger.length);
|
|
16
|
-
if (/\s/.test(query)) return null;
|
|
16
|
+
if (allowSpaces ? /\n/.test(query) : /\s/.test(query)) return null;
|
|
17
|
+
if (terminator && query.includes(terminator)) return null;
|
|
17
18
|
const preceding = start === 0 ? "" : before[start - 1];
|
|
18
|
-
if (preceding !== "" && !/\s/.test(preceding)) return null;
|
|
19
|
+
if (preceding !== "" && !/\s/.test(preceding) && preceding.charCodeAt(0) < 128) return null;
|
|
19
20
|
return { query };
|
|
20
21
|
}
|
|
21
22
|
function levelItems(items, path) {
|
|
@@ -46,7 +47,11 @@ function ChatSuggestion({
|
|
|
46
47
|
emptyMessage,
|
|
47
48
|
listLabel: listLabelProp,
|
|
48
49
|
id,
|
|
49
|
-
className
|
|
50
|
+
className,
|
|
51
|
+
allowSpaces = false,
|
|
52
|
+
terminator,
|
|
53
|
+
shouldFilter = true,
|
|
54
|
+
onQueryChange
|
|
50
55
|
}) {
|
|
51
56
|
const { t } = useTranslation();
|
|
52
57
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false);
|
|
@@ -75,8 +80,12 @@ function ChatSuggestion({
|
|
|
75
80
|
[open, onOpenChange]
|
|
76
81
|
);
|
|
77
82
|
const visible = React.useMemo(() => {
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
const level = levelItems(items, path);
|
|
84
|
+
return shouldFilter ? level.filter((item) => matches(item, query)) : level;
|
|
85
|
+
}, [items, path, query, shouldFilter]);
|
|
86
|
+
React.useEffect(() => {
|
|
87
|
+
if (isOpen) onQueryChange?.(query);
|
|
88
|
+
}, [isOpen, query, onQueryChange]);
|
|
80
89
|
const enabled = React.useMemo(() => visible.filter((item) => !item.disabled), [visible]);
|
|
81
90
|
React.useEffect(() => {
|
|
82
91
|
if (enabled.length === 0) {
|
|
@@ -105,14 +114,14 @@ function ChatSuggestion({
|
|
|
105
114
|
const node = field();
|
|
106
115
|
if (!node) return;
|
|
107
116
|
const caret = node.selectionStart ?? node.value.length;
|
|
108
|
-
const hit = matchTrigger(node.value, caret, triggerCharacter);
|
|
117
|
+
const hit = matchTrigger(node.value, caret, triggerCharacter, { allowSpaces, terminator });
|
|
109
118
|
if (!hit) {
|
|
110
119
|
setOpen(false);
|
|
111
120
|
return;
|
|
112
121
|
}
|
|
113
122
|
setQuery(hit.query);
|
|
114
123
|
setOpen(true);
|
|
115
|
-
}, [field, setOpen, triggerCharacter]);
|
|
124
|
+
}, [field, setOpen, triggerCharacter, allowSpaces, terminator]);
|
|
116
125
|
const onTrigger = React.useCallback(
|
|
117
126
|
(next) => {
|
|
118
127
|
if (next === false) {
|
|
@@ -22,10 +22,21 @@ export type CommandPaletteLabels = {
|
|
|
22
22
|
select?: React.ReactNode;
|
|
23
23
|
close?: React.ReactNode;
|
|
24
24
|
};
|
|
25
|
+
/** The modifier keys held while an item was chosen (gh#1126). */
|
|
26
|
+
export type CommandPaletteSelectModifiers = {
|
|
27
|
+
metaKey: boolean;
|
|
28
|
+
ctrlKey: boolean;
|
|
29
|
+
shiftKey: boolean;
|
|
30
|
+
altKey: boolean;
|
|
31
|
+
};
|
|
25
32
|
export type CommandPaletteProps = {
|
|
26
33
|
groups: CommandPaletteGroup[];
|
|
27
34
|
labels: CommandPaletteLabels;
|
|
28
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Fires with the chosen item and the modifier keys held while choosing it (gh#1126) — Enter or a
|
|
37
|
+
* click with ⌘/Ctrl/Shift/Alt — so a host can "open in split" or "open in a new tab".
|
|
38
|
+
*/
|
|
39
|
+
onSelect: (item: CommandPaletteItem, modifiers: CommandPaletteSelectModifiers) => void;
|
|
29
40
|
open?: boolean;
|
|
30
41
|
defaultOpen?: boolean;
|
|
31
42
|
onOpenChange?: (open: boolean) => void;
|
|
@@ -65,7 +76,14 @@ export type CommandPaletteProps = {
|
|
|
65
76
|
* better handler than a consumer's own. A topbar with no width to spare should be able to say so.
|
|
66
77
|
*/
|
|
67
78
|
trigger?: React.ReactNode;
|
|
68
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The global shortcut that toggles the palette (gh#1126). `true` (default) is ⌘K / Ctrl+K;
|
|
81
|
+
* `false` binds none; a combo string — `"mod+o"`, `"mod+p"`, `"mod+shift+p"` — binds that, so two
|
|
82
|
+
* palettes (a quick switcher and a command palette) can live side by side. `mod` is ⌘ on Apple
|
|
83
|
+
* and Ctrl elsewhere (either is accepted); `shift` and `alt` must match exactly, so `mod+p` and
|
|
84
|
+
* `mod+shift+p` are different shortcuts. Never fires during IME composition.
|
|
85
|
+
*/
|
|
86
|
+
shortcut?: boolean | string;
|
|
69
87
|
};
|
|
70
88
|
/**
|
|
71
89
|
* Unchanged. - **`shouldFilter={false}` (server-side)** — the PALETTE owns it, derived
|
|
@@ -13,6 +13,49 @@ import {
|
|
|
13
13
|
CommandList
|
|
14
14
|
} from "./command.js";
|
|
15
15
|
import { isImeComposing } from "../../lib/ime.js";
|
|
16
|
+
function parseShortcut(shortcut) {
|
|
17
|
+
if (shortcut === false) return null;
|
|
18
|
+
const parts = (shortcut === true ? "mod+k" : shortcut).toLowerCase().split("+").map((p) => p.trim());
|
|
19
|
+
const key = parts.pop() ?? "";
|
|
20
|
+
if (!key) return null;
|
|
21
|
+
return {
|
|
22
|
+
key,
|
|
23
|
+
mod: parts.includes("mod"),
|
|
24
|
+
meta: parts.includes("meta") || parts.includes("cmd"),
|
|
25
|
+
ctrl: parts.includes("ctrl"),
|
|
26
|
+
shift: parts.includes("shift"),
|
|
27
|
+
alt: parts.includes("alt") || parts.includes("option")
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function shortcutMatches(spec, event) {
|
|
31
|
+
const keyMatches = event.key.toLowerCase() === spec.key || /^[a-z]$/.test(spec.key) && event.code === `Key${spec.key.toUpperCase()}`;
|
|
32
|
+
if (!keyMatches) return false;
|
|
33
|
+
if (spec.mod && !(event.metaKey || event.ctrlKey)) return false;
|
|
34
|
+
if (spec.meta && !event.metaKey) return false;
|
|
35
|
+
if (spec.ctrl && !event.ctrlKey) return false;
|
|
36
|
+
return event.shiftKey === spec.shift && event.altKey === spec.alt;
|
|
37
|
+
}
|
|
38
|
+
function shortcutHint(spec) {
|
|
39
|
+
return [
|
|
40
|
+
spec.mod || spec.meta ? "\u2318" : "",
|
|
41
|
+
spec.ctrl ? "Ctrl+" : "",
|
|
42
|
+
spec.alt ? "\u2325" : "",
|
|
43
|
+
spec.shift ? "\u21E7" : "",
|
|
44
|
+
spec.key.length === 1 ? spec.key.toUpperCase() : spec.key
|
|
45
|
+
].join("");
|
|
46
|
+
}
|
|
47
|
+
const modifiersOf = (event) => ({
|
|
48
|
+
metaKey: event.metaKey,
|
|
49
|
+
ctrlKey: event.ctrlKey,
|
|
50
|
+
shiftKey: event.shiftKey,
|
|
51
|
+
altKey: event.altKey
|
|
52
|
+
});
|
|
53
|
+
const NO_MODIFIERS = {
|
|
54
|
+
metaKey: false,
|
|
55
|
+
ctrlKey: false,
|
|
56
|
+
shiftKey: false,
|
|
57
|
+
altKey: false
|
|
58
|
+
};
|
|
16
59
|
function CommandPalette({
|
|
17
60
|
groups,
|
|
18
61
|
labels,
|
|
@@ -32,6 +75,8 @@ function CommandPalette({
|
|
|
32
75
|
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
|
|
33
76
|
const [uncontrolledSearch, setUncontrolledSearch] = React.useState(defaultSearch);
|
|
34
77
|
const shortcutRestoreFocusRef = React.useRef(null);
|
|
78
|
+
const modifiersRef = React.useRef(NO_MODIFIERS);
|
|
79
|
+
const shortcutSpec = React.useMemo(() => parseShortcut(shortcut), [shortcut]);
|
|
35
80
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
36
81
|
const search = controlledSearch ?? uncontrolledSearch;
|
|
37
82
|
const setOpen = React.useCallback(
|
|
@@ -60,9 +105,9 @@ function CommandPalette({
|
|
|
60
105
|
setSearch(defaultSearch);
|
|
61
106
|
}, [open, search, defaultSearch, setSearch]);
|
|
62
107
|
React.useEffect(() => {
|
|
63
|
-
if (!
|
|
108
|
+
if (!shortcutSpec) return;
|
|
64
109
|
const handleKeyDown = (event) => {
|
|
65
|
-
if (!isImeComposing(event) &&
|
|
110
|
+
if (!isImeComposing(event) && shortcutMatches(shortcutSpec, event)) {
|
|
66
111
|
event.preventDefault();
|
|
67
112
|
if (!open && document.activeElement instanceof HTMLElement) {
|
|
68
113
|
shortcutRestoreFocusRef.current = document.activeElement;
|
|
@@ -72,12 +117,12 @@ function CommandPalette({
|
|
|
72
117
|
};
|
|
73
118
|
document.addEventListener("keydown", handleKeyDown);
|
|
74
119
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
75
|
-
}, [open, setOpen,
|
|
120
|
+
}, [open, setOpen, shortcutSpec]);
|
|
76
121
|
const hasItems = React.useMemo(() => groups.some((group) => group.items.length > 0), [groups]);
|
|
77
122
|
const triggerNode = trigger === void 0 ? /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", className: "ui-command-palette-trigger", children: [
|
|
78
123
|
/* @__PURE__ */ jsx(Search, { "aria-hidden": "true" }),
|
|
79
124
|
/* @__PURE__ */ jsx("span", { children: labels.open }),
|
|
80
|
-
/* @__PURE__ */ jsx("span", { className: "kbd", "aria-hidden": "true", children:
|
|
125
|
+
shortcutSpec ? /* @__PURE__ */ jsx("span", { className: "kbd", "aria-hidden": "true", children: shortcutHint(shortcutSpec) }) : null
|
|
81
126
|
] }) : trigger;
|
|
82
127
|
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: setOpen, children: [
|
|
83
128
|
triggerNode === null ? null : /* @__PURE__ */ jsx(Dialog.Trigger, { asChild: true, children: triggerNode }),
|
|
@@ -103,41 +148,56 @@ function CommandPalette({
|
|
|
103
148
|
children: [
|
|
104
149
|
/* @__PURE__ */ jsx(Dialog.Title, { className: "sr-only", children: labels.title }),
|
|
105
150
|
/* @__PURE__ */ jsx(Dialog.Description, { id: "ui-command-palette-description", className: "sr-only", children: labels.description }),
|
|
106
|
-
/* @__PURE__ */ jsxs(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
151
|
+
/* @__PURE__ */ jsxs(
|
|
152
|
+
Command,
|
|
153
|
+
{
|
|
154
|
+
label: labels.title,
|
|
155
|
+
shouldFilter,
|
|
156
|
+
onKeyDownCapture: (event) => {
|
|
157
|
+
if (event.key === "Enter") modifiersRef.current = modifiersOf(event);
|
|
158
|
+
},
|
|
159
|
+
onClickCapture: (event) => {
|
|
160
|
+
modifiersRef.current = modifiersOf(event);
|
|
161
|
+
},
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ jsx(
|
|
164
|
+
CommandInput,
|
|
165
|
+
{
|
|
166
|
+
autoFocus: true,
|
|
167
|
+
value: search,
|
|
168
|
+
onValueChange: setSearch,
|
|
169
|
+
placeholder: labels.placeholder,
|
|
170
|
+
"aria-label": labels.placeholder
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
/* @__PURE__ */ jsx(CommandList, { "aria-busy": loading, children: loading ? /* @__PURE__ */ jsx("div", { className: "ui-command-palette-state", role: "status", children: labels.loading }) : error ? /* @__PURE__ */ jsx("div", { className: "ui-command-palette-state", role: "alert", children: error }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
174
|
+
shouldFilter ? /* @__PURE__ */ jsx(CommandEmpty, { children: labels.empty }) : hasItems ? null : (
|
|
175
|
+
// Same node cmdk would have rendered (class + role), decided from `groups`
|
|
176
|
+
// instead of from its scheduled DOM-registration count — see the doc block.
|
|
177
|
+
/* @__PURE__ */ jsx("div", { className: "ui-command-empty", role: "presentation", children: labels.empty })
|
|
178
|
+
),
|
|
179
|
+
groups.map((group) => /* @__PURE__ */ jsx(CommandGroup, { heading: group.label, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
180
|
+
CommandItem,
|
|
181
|
+
{
|
|
182
|
+
value: item.searchValue ?? `${item.id} ${String(item.label)}`,
|
|
183
|
+
disabled: item.disabled,
|
|
184
|
+
onSelect: () => {
|
|
185
|
+
const modifiers = modifiersRef.current;
|
|
186
|
+
modifiersRef.current = NO_MODIFIERS;
|
|
187
|
+
setOpen(false);
|
|
188
|
+
onSelect(item, modifiers);
|
|
189
|
+
},
|
|
190
|
+
children: [
|
|
191
|
+
/* @__PURE__ */ jsx("span", { className: "ui-command-palette-label", children: item.label }),
|
|
192
|
+
item.meta != null ? /* @__PURE__ */ jsx("span", { className: "ui-command-palette-meta", children: item.meta }) : null
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
item.id
|
|
196
|
+
)) }, group.id))
|
|
197
|
+
] }) })
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
),
|
|
141
201
|
labels.move != null || labels.select != null || labels.close != null ? /* @__PURE__ */ jsxs("div", { className: "ui-command-palette-hints", "aria-hidden": "true", children: [
|
|
142
202
|
labels.move != null ? /* @__PURE__ */ jsxs("span", { children: [
|
|
143
203
|
"\u2191\u2193 ",
|
|
@@ -54,7 +54,7 @@ export type { TransferProps, TransferItemProp } from "./transfer.js";
|
|
|
54
54
|
export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "./command.js";
|
|
55
55
|
export type { CommandProps } from "./command.js";
|
|
56
56
|
export { CommandPalette } from "./command-palette.js";
|
|
57
|
-
export type { CommandPaletteGroup, CommandPaletteItem, CommandPaletteLabels, CommandPaletteProps, } from "./command-palette.js";
|
|
57
|
+
export type { CommandPaletteGroup, CommandPaletteItem, CommandPaletteLabels, CommandPaletteProps, CommandPaletteSelectModifiers, } from "./command-palette.js";
|
|
58
58
|
export { PasswordInput } from "./password-input.js";
|
|
59
59
|
export type { PasswordInputProps, PasswordVisibilityToggleProp } from "./password-input.js";
|
|
60
60
|
export { PasswordStrength, usePasswordStrength } from "./password-strength.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.22.0",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
|
@@ -2253,8 +2253,22 @@ export type ChatSuggestionProp = {
|
|
|
2253
2253
|
items: readonly ChatSuggestionItemProp[];
|
|
2254
2254
|
/** Fires with the picked row's `value`. The caller owns what that does to the draft text. */
|
|
2255
2255
|
onValueChange?: OnValueChangeProp<string>;
|
|
2256
|
-
/**
|
|
2256
|
+
/**
|
|
2257
|
+
* The character(s) that open the list when typed at a boundary — the start, whitespace, or any
|
|
2258
|
+
* non-ASCII character (so `[[` opens right after Japanese text). Default `/`.
|
|
2259
|
+
*/
|
|
2257
2260
|
triggerCharacter?: string;
|
|
2261
|
+
/** Spaces may appear inside the query (a `[[` link picker); a line break still ends it (gh#1127). */
|
|
2262
|
+
allowSpaces?: boolean;
|
|
2263
|
+
/** Typing this inside the query finishes the token and closes the list, e.g. `]]` (gh#1127). */
|
|
2264
|
+
terminator?: string;
|
|
2265
|
+
/**
|
|
2266
|
+
* Whether the list filters `items` against the query itself. `false` when the host answers the
|
|
2267
|
+
* query (async, via `onQueryChange`) and `items` already holds the matches (gh#1127). Default `true`.
|
|
2268
|
+
*/
|
|
2269
|
+
shouldFilter?: boolean;
|
|
2270
|
+
/** The query typed after the trigger, on every change while the list is open (gh#1127). */
|
|
2271
|
+
onQueryChange?: (query: string) => void;
|
|
2258
2272
|
/** Controlled open state. */
|
|
2259
2273
|
open?: OpenProp;
|
|
2260
2274
|
/** Uncontrolled initial open state. */
|
package/dist/styles/layers.json
CHANGED
package/dist/styles/layout.css
CHANGED