@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.
Files changed (41) hide show
  1. package/agent/START-HERE.md +4 -4
  2. package/agent/components/ColorPicker.json +16 -8
  3. package/agent/components/Select.json +22 -0
  4. package/agent/components.json +38 -8
  5. package/agent/index.json +4 -4
  6. package/agent/llms.txt +5 -5
  7. package/agent/tokens.json +24 -0
  8. package/dist/components/data-entry/chat-composer.js +11 -4
  9. package/dist/components/data-entry/chat-suggestion.js +2 -0
  10. package/dist/components/data-entry/color-picker.d.ts +2 -2
  11. package/dist/components/data-entry/color-picker.js +150 -37
  12. package/dist/components/data-entry/command-palette.js +2 -1
  13. package/dist/components/data-entry/date-picker.js +2 -0
  14. package/dist/components/data-entry/index.d.ts +1 -1
  15. package/dist/components/data-entry/number-input.js +2 -1
  16. package/dist/components/data-entry/search-select.js +55 -17
  17. package/dist/components/data-entry/select.js +1 -1
  18. package/dist/components/data-entry/time-picker.js +3 -0
  19. package/dist/components/feedback/non-modal-layer.js +2 -1
  20. package/dist/components/general/typography.js +5 -1
  21. package/dist/components/navigation/pagination.js +2 -1
  22. package/dist/components/ui/tag-input.js +2 -1
  23. package/dist/contracts/measurement.json +1 -1
  24. package/dist/i18n/messages/en.json +4 -2
  25. package/dist/i18n/messages/ja.json +4 -2
  26. package/dist/i18n/messages/vi.json +4 -2
  27. package/dist/lib/ime.d.ts +12 -0
  28. package/dist/lib/ime.js +7 -0
  29. package/dist/props/components/data-entry.prop.d.ts +66 -1
  30. package/dist/props/components/index.d.ts +1 -1
  31. package/dist/props/registry.d.ts +15 -0
  32. package/dist/props/registry.js +17 -0
  33. package/dist/styles/control.css +79 -0
  34. package/dist/styles/layers.json +1 -1
  35. package/dist/tokens/components/control.css +8 -0
  36. package/docs/data-entry/color-picker.tsx +72 -0
  37. package/docs/data-entry/select.tsx +38 -0
  38. package/docs/i18n/messages/en.json +18 -0
  39. package/docs/i18n/messages/ja.json +18 -0
  40. package/docs/i18n/messages/vi.json +18 -0
  41. package/package.json +2 -2
@@ -23,6 +23,7 @@ import { Input } from "./input.js";
23
23
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
24
24
  import { Calendar } from "./calendar.js";
25
25
  import { dateTimeFormat, numberFormat } from "../../lib/intl-cache.js";
26
+ import { isImeComposing } from "../../lib/ime.js";
26
27
  const ISO_HINT = "yyyy-mm-dd";
27
28
  const PERIOD_PICKERS = /* @__PURE__ */ new Set(["month", "quarter", "year"]);
28
29
  const PERIOD_COLUMNS = 3;
@@ -236,6 +237,7 @@ function DatePicker(props) {
236
237
  };
237
238
  const keyHandlers = (onEnter) => ({
238
239
  onKeyDown: (event) => {
240
+ if (isImeComposing(event)) return;
239
241
  if (event.key === "ArrowDown") {
240
242
  event.preventDefault();
241
243
  setOpen(true);
@@ -39,7 +39,7 @@ export type { DatePickerProps } from "./date-picker.js";
39
39
  export { TimePicker } from "./time-picker.js";
40
40
  export type { TimePickerProps } from "./time-picker.js";
41
41
  export { ColorPicker } from "./color-picker.js";
42
- export type { ColorPickerProps } from "./color-picker.js";
42
+ export type { ColorPickerProps, ColorPickerPresetProps } from "./color-picker.js";
43
43
  export type { SelectProp, SelectProp as SelectProps } from "./select.js";
44
44
  export type { SearchSelectOptionProp as SelectOption, SearchSelectLoadParamsProp as SelectLoadParams, SearchSelectLoadResultProp as SelectLoadResult, } from "./search-select.js";
45
45
  export { UPLOAD_LIST_IGNORE, Upload, collectUploadCommitActions, createUploadItem, useUploadDraft, } from "./upload.js";
@@ -8,6 +8,7 @@ import { pickFieldA11y } from "../../lib/field-a11y.js";
8
8
  import { Button } from "../general/button.js";
9
9
  import { Input } from "./input.js";
10
10
  import { numberFormat } from "../../lib/intl-cache.js";
11
+ import { isImeComposing } from "../../lib/ime.js";
11
12
  function decimalsOf(n) {
12
13
  if (!Number.isFinite(n)) return 0;
13
14
  const s = String(n);
@@ -165,7 +166,7 @@ const NumberInput = React.forwardRef(
165
166
  };
166
167
  const handleKeyDown = (event) => {
167
168
  if (!interactive) return;
168
- if (composing.current || event.nativeEvent.isComposing) return;
169
+ if (composing.current || isImeComposing(event)) return;
169
170
  if (keyboard && event.key === "ArrowUp") {
170
171
  event.preventDefault();
171
172
  stepBy(1, event.shiftKey ? 10 : 1);
@@ -4,6 +4,7 @@ import * as React from "react";
4
4
  import { ChevronsUpDown, Loader2, X } from "lucide-react";
5
5
  import { useTranslation } from "../../i18n/use-translation.js";
6
6
  import { useFieldIdentity, useFieldNameFallback } from "../../lib/field-a11y.js";
7
+ import { isImeComposing } from "../../lib/ime.js";
7
8
  import { cn } from "../../lib/utils.js";
8
9
  import { controlSurfaceTriggerClass } from "../../lib/control-styles.js";
9
10
  import {
@@ -54,6 +55,7 @@ function SearchSelect(props) {
54
55
  onSearchChange,
55
56
  filterOption,
56
57
  optionFilterProp,
58
+ caseSensitive = false,
57
59
  filterSort,
58
60
  autoClearSearchValue = true,
59
61
  optionRender,
@@ -91,6 +93,18 @@ function SearchSelect(props) {
91
93
  const maxTagTextLength = props.mode !== void 0 ? props.maxTagTextLength : void 0;
92
94
  const tokenSeparators = props.mode !== void 0 ? props.tokenSeparators : void 0;
93
95
  const tagRender = props.mode !== void 0 ? props.tagRender : void 0;
96
+ const allowCreate = props.mode !== void 0 ? props.allowCreate : void 0;
97
+ const createLabel = props.mode !== void 0 ? props.createLabel : void 0;
98
+ const onCreate = props.mode !== void 0 ? props.onCreate : void 0;
99
+ const fold = React.useCallback(
100
+ (text) => caseSensitive ? text : text.toLowerCase(),
101
+ [caseSensitive]
102
+ );
103
+ const canCreate = React.useCallback(
104
+ (text) => tagsMode && (typeof allowCreate === "function" ? allowCreate(text) : allowCreate !== false),
105
+ [tagsMode, allowCreate]
106
+ );
107
+ const composingRef = React.useRef(false);
94
108
  const { t } = useTranslation();
95
109
  const nameFallback = useFieldNameFallback({
96
110
  "aria-label": ariaLabel,
@@ -154,9 +168,7 @@ function SearchSelect(props) {
154
168
  const matches = (option) => {
155
169
  if (filterOption) return filterOption(option, needle);
156
170
  const haystack = optionFilterProp ? [String(option[optionFilterProp] ?? "")] : [option.label, option.value];
157
- return haystack.some(
158
- (field) => String(field).toLowerCase().includes(needle.toLowerCase())
159
- );
171
+ return haystack.some((field) => fold(String(field)).includes(fold(needle)));
160
172
  };
161
173
  const kept = needle ? list.filter(matches) : list;
162
174
  return {
@@ -164,7 +176,7 @@ function SearchSelect(props) {
164
176
  hasMore: false
165
177
  };
166
178
  }),
167
- [loadOptions, staticOptions, filterOption, optionFilterProp, filterSort]
179
+ [loadOptions, staticOptions, filterOption, optionFilterProp, filterSort, fold]
168
180
  );
169
181
  React.useEffect(() => {
170
182
  const handle = window.setTimeout(() => setDebouncedQuery(query.trim()), DEBOUNCE_MS);
@@ -201,8 +213,9 @@ function SearchSelect(props) {
201
213
  setActiveIndex(0);
202
214
  void fetchPage(1, debouncedQuery, false);
203
215
  }, [open, debouncedQuery, fetchPage]);
204
- const displayOptions = React.useMemo(() => {
205
- if (!tagsMode) return loaded;
216
+ const typedText = query.trim();
217
+ const { displayOptions, createOption } = React.useMemo(() => {
218
+ if (!tagsMode) return { displayOptions: loaded, createOption: void 0 };
206
219
  const known = new Set(loaded.map((option) => option.value));
207
220
  const extras = [];
208
221
  for (const entry of values) {
@@ -210,11 +223,16 @@ function SearchSelect(props) {
210
223
  known.add(entry);
211
224
  extras.push(pickedOptions[entry] ?? { value: entry, label: entry });
212
225
  }
213
- const needle = query.trim();
214
- const exists = known.has(needle) || loaded.some((option) => option.label === needle);
215
- const create = needle && !exists ? [{ value: needle, label: needle }] : [];
216
- return create.length || extras.length ? [...create, ...extras, ...loaded] : loaded;
217
- }, [tagsMode, loaded, values, query, pickedOptions]);
226
+ const typed = fold(typedText);
227
+ const exists = [...known].some((entry) => fold(entry) === typed) || [...staticOptions ?? [], ...loaded].some(
228
+ (option) => fold(option.value) === typed || fold(option.label) === typed
229
+ );
230
+ const create = typedText && !exists && canCreate(typedText) ? { value: typedText, label: typedText } : void 0;
231
+ return {
232
+ displayOptions: create || extras.length ? [...create ? [create] : [], ...extras, ...loaded] : loaded,
233
+ createOption: create
234
+ };
235
+ }, [tagsMode, loaded, values, typedText, pickedOptions, staticOptions, fold, canCreate]);
218
236
  const grouped = React.useMemo(() => {
219
237
  const order = [];
220
238
  const buckets = /* @__PURE__ */ new Map();
@@ -258,6 +276,7 @@ function SearchSelect(props) {
258
276
  const maxCount = props.mode !== void 0 ? props.maxCount : void 0;
259
277
  const atMaxCount = maxCount !== void 0 && values.length >= maxCount;
260
278
  const remember = (option) => setPickedOptions((prev) => ({ ...prev, [option.value]: option }));
279
+ const isInvented = (entry) => tagsMode && !(staticOptions ?? []).some((option) => option.value === entry) && !loaded.some((option) => option.value === entry);
261
280
  const select = (option) => {
262
281
  if (option.disabled) return;
263
282
  if (props.mode !== void 0) {
@@ -271,7 +290,10 @@ function SearchSelect(props) {
271
290
  next.map((entry) => entry === option.value ? option : optionFor(entry)).filter((entry) => entry !== null)
272
291
  );
273
292
  if (already) props.onDeselect?.(option.value, option);
274
- else props.onSelect?.(option.value, option);
293
+ else {
294
+ props.onSelect?.(option.value, option);
295
+ if (isInvented(option.value)) onCreate?.(option.value);
296
+ }
275
297
  if (autoClearSearchValue) setQuery("");
276
298
  return;
277
299
  }
@@ -289,8 +311,10 @@ function SearchSelect(props) {
289
311
  for (const raw of splitByTokenSeparators(text, tokenSeparators ?? [])) {
290
312
  const token = raw.trim();
291
313
  if (!token) continue;
292
- const match = flatOrdered.find((option2) => option2.value === token || option2.label === token);
293
- const option = match ?? (tagsMode ? { value: token, label: token } : void 0);
314
+ const match = flatOrdered.find((option2) => option2.value === token || option2.label === token) ?? flatOrdered.find(
315
+ (option2) => option2 !== createOption && (fold(option2.value) === fold(token) || fold(option2.label) === fold(token))
316
+ );
317
+ const option = match ?? (canCreate(token) ? { value: token, label: token } : void 0);
294
318
  if (!option || option.disabled) continue;
295
319
  if (next.includes(option.value)) continue;
296
320
  if (maxCount !== void 0 && next.length >= maxCount) break;
@@ -304,7 +328,10 @@ function SearchSelect(props) {
304
328
  next,
305
329
  next.map((entry) => picked.find((option) => option.value === entry) ?? optionFor(entry)).filter((entry) => entry != null)
306
330
  );
307
- for (const option of picked) props.onSelect?.(option.value, option);
331
+ for (const option of picked) {
332
+ props.onSelect?.(option.value, option);
333
+ if (isInvented(option.value)) onCreate?.(option.value);
334
+ }
308
335
  };
309
336
  const deselect = (chipValue) => {
310
337
  select(optionFor(chipValue) ?? { value: chipValue, label: chipValue });
@@ -344,6 +371,7 @@ function SearchSelect(props) {
344
371
  if (next !== void 0) setActiveIndex(next);
345
372
  };
346
373
  const onKeyDown = (event) => {
374
+ if (isImeComposing(event)) return;
347
375
  if (event.key === "ArrowDown") {
348
376
  event.preventDefault();
349
377
  moveActive(1);
@@ -530,7 +558,7 @@ function SearchSelect(props) {
530
558
  value: query,
531
559
  onChange: (event) => {
532
560
  const next = event.target.value;
533
- if (multiple && tokenSeparators?.length && tokenSeparators.some((separator) => next.includes(separator))) {
561
+ if (multiple && !composingRef.current && tokenSeparators?.length && tokenSeparators.some((separator) => next.includes(separator))) {
534
562
  selectTokens(next);
535
563
  setQuery("");
536
564
  return;
@@ -546,6 +574,12 @@ function SearchSelect(props) {
546
574
  setQuery("");
547
575
  },
548
576
  onKeyDown,
577
+ onCompositionStart: () => {
578
+ composingRef.current = true;
579
+ },
580
+ onCompositionEnd: () => {
581
+ composingRef.current = false;
582
+ },
549
583
  placeholder: searchPlaceholder ?? t("dataEntry.searchSelect.search"),
550
584
  className: "ui-search-select-search-input"
551
585
  }
@@ -588,7 +622,11 @@ function SearchSelect(props) {
588
622
  onMouseDown: (event) => event.preventDefault(),
589
623
  onClick: () => select(option),
590
624
  children: [
591
- optionRender ? /* @__PURE__ */ jsx("div", { className: "ui-search-select-option-slot", children: optionRender(option, { index }) }) : renderOption ? /* @__PURE__ */ jsx("div", { className: "ui-search-select-option-slot", children: renderOption(option) }) : /* @__PURE__ */ jsxs("div", { className: "ui-search-select-option-body", children: [
625
+ option === createOption ? (
626
+ // gh#1052: the create row SAYS it creates — antd shows the bare text, which
627
+ // reads like an existing option.
628
+ /* @__PURE__ */ jsx("div", { className: "ui-search-select-option-body", "data-slot": "select-create", children: /* @__PURE__ */ jsx("span", { className: "ui-search-select-option-label", children: createLabel ? createLabel(option.value) : t("dataEntry.searchSelect.create", { value: option.value }) }) })
629
+ ) : optionRender ? /* @__PURE__ */ jsx("div", { className: "ui-search-select-option-slot", children: optionRender(option, { index }) }) : renderOption ? /* @__PURE__ */ jsx("div", { className: "ui-search-select-option-slot", children: renderOption(option) }) : /* @__PURE__ */ jsxs("div", { className: "ui-search-select-option-body", children: [
592
630
  option.icon ? /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center", "aria-hidden": "true", children: option.icon }) : null,
593
631
  /* @__PURE__ */ jsxs("div", { className: "ui-search-select-option-text", children: [
594
632
  /* @__PURE__ */ jsx("span", { className: "ui-search-select-option-label", children: option.label }),
@@ -646,7 +646,7 @@ function DataSelect(props) {
646
646
  props.onSearchChange?.(query);
647
647
  } : void 0,
648
648
  autoClearSearchValue: showSearchConfig?.autoClearSearchValue ?? props.autoClearSearchValue,
649
- disabled: props.disabled || !props.loadOptions && !hasOptions,
649
+ disabled: props.disabled || !props.loadOptions && !hasOptions && props.mode !== "tags",
650
650
  name: resolvedName,
651
651
  "data-field": resolvedField
652
652
  }
@@ -11,6 +11,7 @@ import { resolveAllowClear } from "./control-surface.js";
11
11
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
12
12
  import { Button } from "../general/button.js";
13
13
  import { Input } from "./input.js";
14
+ import { isImeComposing } from "../../lib/ime.js";
14
15
  function pad2(n) {
15
16
  return String(n).padStart(2, "0");
16
17
  }
@@ -326,6 +327,7 @@ function TimePickerPanel({
326
327
  "aria-label": t("dataEntry.timePicker.typeLabel"),
327
328
  className: "text-center tabular-nums",
328
329
  onKeyDown: (e) => {
330
+ if (isImeComposing(e)) return;
329
331
  if (e.key === "Enter") {
330
332
  e.preventDefault();
331
333
  commitDraft();
@@ -482,6 +484,7 @@ function TimePicker({
482
484
  if (!disabled) setOpen(true);
483
485
  },
484
486
  onKeyDown: (event) => {
487
+ if (isImeComposing(event)) return;
485
488
  if (event.key === "ArrowDown") {
486
489
  event.preventDefault();
487
490
  setOpen(true);
@@ -4,6 +4,7 @@ import * as React from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import { useExitAnimation } from "@react-aria/utils";
6
6
  import { FocusScope } from "react-aria";
7
+ import { isImeComposing } from "../../lib/ime.js";
7
8
  function useNonModalPortal(isOpen, enabled) {
8
9
  const contentRef = React.useRef(null);
9
10
  const isExiting = useExitAnimation(contentRef, enabled && isOpen);
@@ -11,7 +12,7 @@ function useNonModalPortal(isOpen, enabled) {
11
12
  }
12
13
  function closeOnEscape(close) {
13
14
  return (event) => {
14
- if (event.key === "Escape" && !event.defaultPrevented && !event.nativeEvent.isComposing) {
15
+ if (event.key === "Escape" && !event.defaultPrevented && !isImeComposing(event)) {
15
16
  event.preventDefault();
16
17
  event.stopPropagation();
17
18
  close();
@@ -7,6 +7,7 @@ import { useTranslation } from "../../i18n/use-translation.js";
7
7
  import { EllipsisTooltip, Tooltip, TooltipContent, TooltipTrigger } from "../feedback/tooltip.js";
8
8
  import { Textarea } from "../data-entry/textarea.js";
9
9
  import { isDevelopment } from "../../lib/dev.js";
10
+ import { isImeComposing } from "../../lib/ime.js";
10
11
  const COPIED_RESET_MS = 3e3;
11
12
  const DECORATION_ELEMENTS = [
12
13
  ["strong", "strong"],
@@ -133,7 +134,10 @@ function TypographyEditor({
133
134
  inComposition.current = false;
134
135
  },
135
136
  onKeyDown: (event) => {
136
- if (inComposition.current) return;
137
+ if (inComposition.current || isImeComposing(event)) {
138
+ lastKey.current = null;
139
+ return;
140
+ }
137
141
  lastKey.current = event.key;
138
142
  },
139
143
  onKeyUp: (event) => {
@@ -17,6 +17,7 @@ import {
17
17
  SelectValue
18
18
  } from "../data-entry/select.js";
19
19
  import { buildPageRange } from "./pagination-utils.js";
20
+ import { isImeComposing } from "../../lib/ime.js";
20
21
  const PaginationContent = React.forwardRef(({ className, ...props }, ref) => {
21
22
  const [scrollRegion, setScrollRegion] = React.useState(null);
22
23
  const setListElement = React.useCallback(
@@ -171,7 +172,7 @@ function Pagination({
171
172
  value: jumperDraft,
172
173
  onChange: (event) => setJumperDraft(event.target.value),
173
174
  onKeyDown: (event) => {
174
- if (event.key !== "Enter") return;
175
+ if (event.key !== "Enter" || isImeComposing(event)) return;
175
176
  event.preventDefault();
176
177
  commitJump();
177
178
  }
@@ -3,6 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { X } from "lucide-react";
5
5
  import { useTranslation } from "../../i18n/use-translation.js";
6
+ import { isImeComposing } from "../../lib/ime.js";
6
7
  import { cn } from "../../lib/utils.js";
7
8
  import {
8
9
  applyMaxTagCount,
@@ -62,7 +63,7 @@ const TagInput = React.forwardRef(
62
63
  const removeAt = (i) => commit(tags.filter((_, idx) => idx !== i));
63
64
  const onKeyDown = (e) => {
64
65
  if (readOnly) return;
65
- if (e.nativeEvent.isComposing) return;
66
+ if (isImeComposing(e)) return;
66
67
  if (e.key === "Enter" || tokenSeparators.includes(e.key)) {
67
68
  e.preventDefault();
68
69
  add(draft);
@@ -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.7.0",
3
+ "version": "31.8.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,
@@ -56,7 +56,8 @@
56
56
  },
57
57
  "colorPicker": {
58
58
  "ariaLabel": "Pick color",
59
- "hexLabel": "Hex color value"
59
+ "hexLabel": "Hex color value",
60
+ "presetEmpty": "Empty"
60
61
  },
61
62
  "upload": {
62
63
  "dropzoneLabel": "Upload files",
@@ -123,7 +124,8 @@
123
124
  "clear": "Clear selection",
124
125
  "loading": "Loading…",
125
126
  "empty": "No results",
126
- "error": "Couldn’t load options"
127
+ "error": "Couldn’t load options",
128
+ "create": "Create “{value}”"
127
129
  },
128
130
  "selection": {
129
131
  "overflow": "+{count}"
@@ -56,7 +56,8 @@
56
56
  },
57
57
  "colorPicker": {
58
58
  "ariaLabel": "色を選択",
59
- "hexLabel": "カラーコード(HEX)"
59
+ "hexLabel": "カラーコード(HEX)",
60
+ "presetEmpty": "空"
60
61
  },
61
62
  "upload": {
62
63
  "dropzoneLabel": "ファイルをアップロード",
@@ -123,7 +124,8 @@
123
124
  "clear": "選択をクリア",
124
125
  "loading": "読み込み中…",
125
126
  "empty": "該当なし",
126
- "error": "選択肢を読み込めませんでした"
127
+ "error": "選択肢を読み込めませんでした",
128
+ "create": "「{value}」を作成"
127
129
  },
128
130
  "selection": {
129
131
  "overflow": "他{count}件"
@@ -56,7 +56,8 @@
56
56
  },
57
57
  "colorPicker": {
58
58
  "ariaLabel": "Chọn màu",
59
- "hexLabel": "Mã màu hex"
59
+ "hexLabel": "Mã màu hex",
60
+ "presetEmpty": "Trống"
60
61
  },
61
62
  "upload": {
62
63
  "dropzoneLabel": "Tải file lên",
@@ -123,7 +124,8 @@
123
124
  "clear": "Xóa lựa chọn",
124
125
  "loading": "Đang tải…",
125
126
  "empty": "Không có kết quả",
126
- "error": "Không tải được lựa chọn"
127
+ "error": "Không tải được lựa chọn",
128
+ "create": "Tạo “{value}”"
127
129
  },
128
130
  "selection": {
129
131
  "overflow": "+{count}"
@@ -0,0 +1,12 @@
1
+ import type * as React from "react";
2
+ /**
3
+ * TRUE WHILE AN IME IS COMPOSING (gh#1054). Between `compositionstart` and `compositionend` a
4
+ * Japanese / Chinese / Korean IME holds a CANDIDATE, and the Enter that confirms the conversion is
5
+ * delivered as an ordinary `keydown` — acting on it creates a tag, submits a form or picks an option
6
+ * from a half-typed reading. Every Enter (and Escape/Tab) handler in the kit asks this first.
7
+ *
8
+ * `isComposing` is the standards answer; `keyCode === 229` is the legacy one some browsers
9
+ * (Safari after `compositionend`, older Chromium on Windows) still report instead. Accepts a React
10
+ * synthetic event or a native `KeyboardEvent`.
11
+ */
12
+ export declare function isImeComposing(event: React.KeyboardEvent | KeyboardEvent): boolean;
@@ -0,0 +1,7 @@
1
+ function isImeComposing(event) {
2
+ const native = "nativeEvent" in event ? event.nativeEvent : event;
3
+ return native.isComposing || native.keyCode === 229;
4
+ }
5
+ export {
6
+ isImeComposing
7
+ };
@@ -1114,6 +1114,39 @@ export type ColorPickerProp = FieldA11yProps & {
1114
1114
  className?: ClassNameProp;
1115
1115
  id?: IdProp;
1116
1116
  showHexInput?: boolean;
1117
+ /**
1118
+ * antd `presets` (gh#1055) — named groups of fixed swatches under the picker. Each group is a
1119
+ * collapsible section (antd renders a ghost `Collapse`); `defaultOpen` (default `true`) is its
1120
+ * initial state and `key` its stable identity (falls back to the index). Each swatch is a radio
1121
+ * named by its hex; the one equal to `value` (case- and shorthand-insensitive) is checked.
1122
+ * Colours are hex strings (`#rgb`/`#rrggbb`) because the value is — antd also takes a colour
1123
+ * object or a gradient, which this picker has no model for.
1124
+ */
1125
+ presets?: ColorPickerPresetProp[];
1126
+ /**
1127
+ * antd `panelRender` — replace the picker's body. `panel` is the default body (the swatch + hex
1128
+ * row, then the presets); `extra.components` hands back each part on its own, so
1129
+ * `panelRender={(_, { components: { Presets } }) => <Presets />}` is the PRESETS-ONLY mode —
1130
+ * the palette with no free-colour entry (antd's own recipe for it). The hidden `name` input
1131
+ * is outside the panel and always submits.
1132
+ */
1133
+ panelRender?: (panel: React.ReactNode, extra: {
1134
+ components: {
1135
+ Picker: React.FC;
1136
+ Presets: React.FC;
1137
+ };
1138
+ }) => React.ReactNode;
1139
+ };
1140
+ /** One `ColorPicker presets` group — antd `PresetsItem` (gh#1055). */
1141
+ export type ColorPickerPresetProp = {
1142
+ /** Group heading; also names the group's radiogroup. */
1143
+ label: LabelProp;
1144
+ /** Hex colours (`#rgb` / `#rrggbb`), in display order. Empty → antd's "Empty" line. */
1145
+ colors: string[];
1146
+ /** Initial expanded state of the group (antd default `true`). */
1147
+ defaultOpen?: DefaultOpenProp;
1148
+ /** Stable identity of the group (antd `key`); defaults to its index. */
1149
+ key?: React.Key;
1117
1150
  };
1118
1151
  /** A SearchSelect option row. `group` buckets it under an optgroup-style heading. */
1119
1152
  export type SearchSelectOptionProp = {
@@ -1503,6 +1536,14 @@ export type SearchSelectBaseProp = {
1503
1536
  * every call site that has ever relied on the default expects a label search.
1504
1537
  */
1505
1538
  optionFilterProp?: "label" | "value" | "sublabel";
1539
+ /**
1540
+ * Match typed text case-SENSITIVELY (gh#1053). Default `false`: the built-in filter, the
1541
+ * `mode="tags"` create row and a `tokenSeparators` run all compare case-folded, so typing "bug"
1542
+ * when "Bug" exists finds "Bug" and never offers a duplicate. antd's filter folds case too; its
1543
+ * create row compares exactly, which is the deviation `true` restores. A custom `filterOption`
1544
+ * owns its own comparison and is not affected.
1545
+ */
1546
+ caseSensitive?: boolean;
1506
1547
  };
1507
1548
  /**
1508
1549
  * Single-select (the default): one `string` in, one `string` out — `""` means nothing selected.
@@ -1578,7 +1619,7 @@ export type SearchSelectMultipleProp = {
1578
1619
  * a token only counts when it matches a row; in `mode="tags"` it is accepted as it stands.
1579
1620
  */
1580
1621
  tokenSeparators?: string[];
1581
- };
1622
+ } & SelectTagsCreateProp;
1582
1623
  /**
1583
1624
  * antd `labelInValue`, single. The value carries its own label, so a screen that never sees the
1584
1625
  * option list can still render what was picked.
@@ -1612,6 +1653,30 @@ export type SelectLabelInValueMultipleProp = {
1612
1653
  index: number;
1613
1654
  disabled: boolean;
1614
1655
  }) => React.ReactNode;
1656
+ } & SelectTagsCreateProp;
1657
+ /**
1658
+ * `mode="tags"` — how typed text becomes a NEW value (gh#1052). antd has no equivalent of these
1659
+ * three: its create row is the bare text and nothing reports that a value was invented. Ignored in
1660
+ * `mode="multiple"`, which never creates.
1661
+ */
1662
+ export type SelectTagsCreateProp = {
1663
+ /**
1664
+ * Whether typed text may become a new value. `false` (or a predicate returning `false` for the
1665
+ * text) hides the create row and drops unknown `tokenSeparators` tokens — values already held
1666
+ * stay listed so they can still be removed. Default `true`.
1667
+ */
1668
+ allowCreate?: boolean | ((text: string) => boolean);
1669
+ /**
1670
+ * The create row's content. Default: the localised `Create "{text}"` (「{text}」を作成). The
1671
+ * value committed is the text itself either way; this only changes what the row says.
1672
+ */
1673
+ createLabel?: (text: string) => React.ReactNode;
1674
+ /**
1675
+ * Fired when a value that is NOT one of the options joins the selection — from the create row,
1676
+ * Enter on it, or a `tokenSeparators` run. Fires beside `onSelect`/`onValueChange`, so a consumer
1677
+ * can tell invented text apart from an option id.
1678
+ */
1679
+ onCreate?: (text: string) => void;
1615
1680
  };
1616
1681
  /** @see Select — the searchable engine. Single by default; `mode="multiple"` switches the shape. */
1617
1682
  export type SearchSelectProp = SearchSelectBaseProp & (SearchSelectSingleProp | SearchSelectMultipleProp);
@@ -1,6 +1,6 @@
1
1
  export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, DragAxisProp, DragBoundsProp, DraggablePanelLabels, DraggablePanelPlacementProp, DraggablePanelPositionProp, DraggablePanelProp, PageContainerExtraProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
2
2
  export type { ButtonProp } from "./general.prop.js";
3
- export type { CommandProp, InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
3
+ export type { CommandProp, InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, TimePickerProp, ColorPickerProp, ColorPickerPresetProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
4
4
  export type { AvatarProp, EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, QrCodeProp, } from "./data-display.prop.js";
5
5
  export type { ChartDatum, ChartSeriesProp, LineChartProp, BarChartProp, AreaChartProp, PieChartProp, } from "./charts.prop.js";
6
6
  export type { AlertQueryErrorProp, AuthExpiryProviderProp, AlertProp, DialogProp, DialogContentProp, AlertTitleProp, AlertContentProp, AlertDescriptionProp, AlertActionsProp, SheetResponsiveProp, SkeletonRowsProp, } from "./feedback.prop.js";
@@ -1744,6 +1744,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
1744
1744
  readonly file: "components/data-entry.prop.ts";
1745
1745
  readonly vocabulary: readonly ["ValueProp", "OnValueChangeProp", "DisabledProp", "IdProp"];
1746
1746
  };
1747
+ readonly ColorPickerPresetProp: {
1748
+ readonly group: "data-entry";
1749
+ readonly file: "components/data-entry.prop.ts";
1750
+ readonly vocabulary: readonly ["LabelProp", "DefaultOpenProp"];
1751
+ };
1747
1752
  readonly SearchSelectBaseProp: {
1748
1753
  readonly group: "data-entry";
1749
1754
  readonly file: "components/data-entry.prop.ts";
@@ -1762,6 +1767,16 @@ export declare const COMPONENT_PROP_REGISTRY: {
1762
1767
  readonly vocabulary: readonly ["ValueProp", "DefaultValueProp", "OnValueChangeProp", "MaxTagCountProp", "MaxTagPlaceholderProp"];
1763
1768
  readonly note: 'Internal — the `mode="multiple"` value shape of `<Select options>`; use Select.';
1764
1769
  };
1770
+ readonly SelectTagsCreateProp: {
1771
+ readonly group: "data-entry";
1772
+ readonly file: "components/data-entry.prop.ts";
1773
+ readonly vocabulary: readonly [{
1774
+ readonly field: "onCreate";
1775
+ readonly local: true;
1776
+ readonly reason: "An EVENT, not a value channel: fires once per invented text as it joins the selection, beside onSelect/onValueChange, so a consumer can tell typed-new text from an option id (antd has no equivalent, gh#1052).";
1777
+ }];
1778
+ readonly note: 'Internal — `mode="tags"` create-row knobs (allowCreate / createLabel / onCreate, gh#1052) shared by both multi-value shapes of `<Select options>`.';
1779
+ };
1765
1780
  readonly SearchSelectProp: {
1766
1781
  readonly group: "data-entry";
1767
1782
  readonly file: "components/data-entry.prop.ts";
@@ -2013,6 +2013,11 @@ const COMPONENT_PROP_REGISTRY = {
2013
2013
  file: "components/data-entry.prop.ts",
2014
2014
  vocabulary: ["ValueProp", "OnValueChangeProp", "DisabledProp", "IdProp"]
2015
2015
  },
2016
+ ColorPickerPresetProp: {
2017
+ group: "data-entry",
2018
+ file: "components/data-entry.prop.ts",
2019
+ vocabulary: ["LabelProp", "DefaultOpenProp"]
2020
+ },
2016
2021
  SearchSelectBaseProp: {
2017
2022
  group: "data-entry",
2018
2023
  file: "components/data-entry.prop.ts",
@@ -2054,6 +2059,18 @@ const COMPONENT_PROP_REGISTRY = {
2054
2059
  ],
2055
2060
  note: 'Internal \u2014 the `mode="multiple"` value shape of `<Select options>`; use Select.'
2056
2061
  },
2062
+ SelectTagsCreateProp: {
2063
+ group: "data-entry",
2064
+ file: "components/data-entry.prop.ts",
2065
+ vocabulary: [
2066
+ {
2067
+ field: "onCreate",
2068
+ local: true,
2069
+ reason: "An EVENT, not a value channel: fires once per invented text as it joins the selection, beside onSelect/onValueChange, so a consumer can tell typed-new text from an option id (antd has no equivalent, gh#1052)."
2070
+ }
2071
+ ],
2072
+ note: 'Internal \u2014 `mode="tags"` create-row knobs (allowCreate / createLabel / onCreate, gh#1052) shared by both multi-value shapes of `<Select options>`.'
2073
+ },
2057
2074
  SearchSelectProp: {
2058
2075
  group: "data-entry",
2059
2076
  file: "components/data-entry.prop.ts",