@godxjp/ui 33.1.1 → 33.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +4 -4
  2. package/agent/START-HERE.md +6 -6
  3. package/agent/components/Command.json +9 -1
  4. package/agent/components/TranslatableInput.json +92 -0
  5. package/agent/components/TranslatableTextarea.json +84 -0
  6. package/agent/components-index.json +10 -0
  7. package/agent/components.json +185 -1
  8. package/agent/index.json +7 -7
  9. package/agent/llms.txt +7 -7
  10. package/agent/tokens.json +12 -0
  11. package/dist/components/data-entry/command.d.ts +22 -1
  12. package/dist/components/data-entry/command.js +14 -1
  13. package/dist/components/data-entry/form-field.js +10 -4
  14. package/dist/components/data-entry/index.d.ts +4 -2
  15. package/dist/components/data-entry/index.js +6 -1
  16. package/dist/components/data-entry/translatable-input.d.ts +29 -0
  17. package/dist/components/data-entry/translatable-input.js +184 -0
  18. package/dist/contracts/measurement.json +1 -1
  19. package/dist/i18n/messages/en.json +4 -0
  20. package/dist/i18n/messages/ja.json +4 -0
  21. package/dist/i18n/messages/vi.json +4 -0
  22. package/dist/lib/field-a11y.d.ts +15 -0
  23. package/dist/lib/field-a11y.js +13 -1
  24. package/dist/lib/intl-cache.d.ts +1 -0
  25. package/dist/lib/intl-cache.js +4 -0
  26. package/dist/props/components/data-entry.prop.d.ts +46 -0
  27. package/dist/props/components/index.d.ts +1 -1
  28. package/dist/props/registry.d.ts +51 -0
  29. package/dist/props/registry.js +79 -0
  30. package/dist/styles/control.css +15 -0
  31. package/dist/styles/data-entry-layout.css +25 -0
  32. package/dist/styles/layers.json +19 -1
  33. package/dist/styles.css +1 -1
  34. package/dist/tokens/components/data-entry.css +4 -0
  35. package/package.json +2 -2
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
- import type { CommandProp } from "../../props/components/data-entry.prop.js";
2
+ import type { CommandProp, CommandSeparatorProp } from "../../props/components/data-entry.prop.js";
3
3
  export type { CommandProp, CommandProp as CommandProps };
4
+ export type { CommandSeparatorProp, CommandSeparatorProp as CommandSeparatorProps };
4
5
  export declare const Command: React.ForwardRefExoticComponent<Omit<{
5
6
  children?: React.ReactNode;
6
7
  } & Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
@@ -66,3 +67,23 @@ export declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
66
67
  keywords?: string[];
67
68
  forceMount?: boolean;
68
69
  } & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
70
+ /**
71
+ * A hairline between two groups of one list — e.g. the matches, then `+ Create "<q>"` (gh#1335).
72
+ * It is cmdk's own `Command.Separator`, so it must sit inside the same `Command` as its groups.
73
+ *
74
+ * `alwaysRender` defaults to `true`, the OPPOSITE of cmdk: cmdk drops a separator as soon as the
75
+ * search is non-empty, because in a palette the groups collapse under filtering. A "Create" group
76
+ * exists only BECAUSE the user typed, so with cmdk's default the rule vanished exactly when it
77
+ * was needed. Pass `alwaysRender={false}` for cmdk's palette behaviour.
78
+ *
79
+ * `aria-hidden` by default: the rule is decorative, and a `role="separator"` child is not allowed
80
+ * in the `listbox` CommandList renders (ARIA owns only `option` / `group` there); the groups'
81
+ * headings carry the structure.
82
+ */
83
+ export declare const CommandSeparator: React.ForwardRefExoticComponent<Omit<Pick<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
84
+ ref?: React.Ref<HTMLDivElement>;
85
+ } & {
86
+ asChild?: boolean;
87
+ }, "asChild" | "key" | keyof React.HTMLAttributes<HTMLDivElement>> & {
88
+ alwaysRender?: boolean;
89
+ } & React.RefAttributes<HTMLDivElement>, "ref"> & CommandSeparatorProp & React.RefAttributes<HTMLDivElement>>;
@@ -50,11 +50,24 @@ const CommandGroup = React.forwardRef(({ className, ...props }, ref) => /* @__PU
50
50
  CommandGroup.displayName = CommandPrimitive.Group.displayName;
51
51
  const CommandItem = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(CommandPrimitive.Item, { ref, className: cn("ui-command-item", className), ...props }));
52
52
  CommandItem.displayName = CommandPrimitive.Item.displayName;
53
+ const CommandSeparator = React.forwardRef(({ className, alwaysRender = true, ...props }, ref) => /* @__PURE__ */ jsx(
54
+ CommandPrimitive.Separator,
55
+ {
56
+ ref,
57
+ className: cn("ui-command-separator", className),
58
+ "data-slot": "command-separator",
59
+ "aria-hidden": "true",
60
+ alwaysRender,
61
+ ...props
62
+ }
63
+ ));
64
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
53
65
  export {
54
66
  Command,
55
67
  CommandEmpty,
56
68
  CommandGroup,
57
69
  CommandInput,
58
70
  CommandItem,
59
- CommandList
71
+ CommandList,
72
+ CommandSeparator
60
73
  };
@@ -5,7 +5,12 @@ import { CheckCircle, CircleAlert, LoaderCircle, TriangleAlert } from "lucide-re
5
5
  import { useTranslation } from "../../i18n/use-translation.js";
6
6
  import { Label } from "../data-entry/label.js";
7
7
  import { cn } from "../../lib/utils.js";
8
- import { FieldIdentityContext, FieldNameContext, mergeAriaIds } from "../../lib/field-a11y.js";
8
+ import {
9
+ FieldErrorReportContext,
10
+ FieldIdentityContext,
11
+ FieldNameContext,
12
+ mergeAriaIds
13
+ } from "../../lib/field-a11y.js";
9
14
  import { useOptionalAppContext } from "../../app/app-provider.js";
10
15
  import { useFormLayout } from "./form.js";
11
16
  import { firstBagMessage, useClaimErrorKey, useFormErrorsRegistry } from "./form-errors.js";
@@ -42,7 +47,8 @@ function FormField({
42
47
  const collapseBelow = form?.collapseBelow ?? "md";
43
48
  const errorsRegistry = useFormErrorsRegistry();
44
49
  useClaimErrorKey(name);
45
- const error = errorProp ?? (name && errorsRegistry ? firstBagMessage(errorsRegistry.errors[name]) : void 0);
50
+ const [reportedError, setReportedError] = React.useState(void 0);
51
+ const error = errorProp ?? (name && errorsRegistry ? firstBagMessage(errorsRegistry.errors[name]) : void 0) ?? (reportedError === null || reportedError === false || reportedError === "" ? void 0 : reportedError);
46
52
  const autoId = React.useId();
47
53
  const resolvedId = id ?? autoId;
48
54
  const labelId = `${resolvedId}-label`;
@@ -165,7 +171,7 @@ function FormField({
165
171
  ] }) : null,
166
172
  /* @__PURE__ */ jsxs("div", { "data-slot": "form-field-control", className: "ui-form-field-control", children: [
167
173
  helperPlacement === "before" ? helperNode : null,
168
- isStatic ? childWithA11y : /* @__PURE__ */ jsx(FieldNameContext.Provider, { value: fieldNameContext, children: /* @__PURE__ */ jsx(FieldIdentityContext.Provider, { value: fieldIdentityContext, children: /* @__PURE__ */ jsx(
174
+ isStatic ? childWithA11y : /* @__PURE__ */ jsx(FieldNameContext.Provider, { value: fieldNameContext, children: /* @__PURE__ */ jsx(FieldIdentityContext.Provider, { value: fieldIdentityContext, children: /* @__PURE__ */ jsx(FieldErrorReportContext.Provider, { value: setReportedError, children: /* @__PURE__ */ jsx(
169
175
  "fieldset",
170
176
  {
171
177
  role: "presentation",
@@ -173,7 +179,7 @@ function FormField({
173
179
  disabled: form?.disabled && childProps?.disabled !== false,
174
180
  children: childWithA11y
175
181
  }
176
- ) }) }),
182
+ ) }) }) }),
177
183
  hasFeedback && validationStatus ? /* @__PURE__ */ jsxs(
178
184
  "span",
179
185
  {
@@ -9,6 +9,8 @@ export { CheckboxGroup } from "./checkbox-group.js";
9
9
  export { Radio, RadioGroup, RadioItem, RadioGroupRoot } from "./radio.js";
10
10
  export { Textarea } from "./textarea.js";
11
11
  export type { TextareaProps } from "./textarea.js";
12
+ export { TranslatableInput, TranslatableTextarea } from "./translatable-input.js";
13
+ export type { TranslatableValue, TranslatableInputProp, TranslatableInputProps, TranslatableTextareaProp, TranslatableTextareaProps, } from "./translatable-input.js";
12
14
  export { Form, useFormLayout, type FormLayoutContextValue } from "./form.js";
13
15
  export type { FormProp, FormProps } from "./form.js";
14
16
  export { FormField } from "./form-field.js";
@@ -47,8 +49,8 @@ export { TreeSelect, SHOW_CHILD, SHOW_PARENT, SHOW_ALL } from "./tree-select.js"
47
49
  export type { TreeSelectProps } from "./tree-select.js";
48
50
  export { Transfer } from "./transfer.js";
49
51
  export type { TransferProps, TransferItemProp } from "./transfer.js";
50
- export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "./command.js";
51
- export type { CommandProps } from "./command.js";
52
+ export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from "./command.js";
53
+ export type { CommandProps, CommandSeparatorProps } from "./command.js";
52
54
  export { CommandPalette } from "./command-palette.js";
53
55
  export type { CommandPaletteGroup, CommandPaletteItem, CommandPaletteLabels, CommandPaletteProps, CommandPaletteRecent, CommandPaletteSelectModifiers, } from "./command-palette.js";
54
56
  export { PasswordInput } from "./password-input.js";
@@ -17,6 +17,7 @@ import { Checkbox } from "./checkbox.js";
17
17
  import { CheckboxGroup } from "./checkbox-group.js";
18
18
  import { Radio, RadioGroup, RadioItem, RadioGroupRoot } from "./radio.js";
19
19
  import { Textarea } from "./textarea.js";
20
+ import { TranslatableInput, TranslatableTextarea } from "./translatable-input.js";
20
21
  import { Form, useFormLayout } from "./form.js";
21
22
  import { FormField } from "./form-field.js";
22
23
  import { FormErrors, FormErrorsProvider } from "./form-errors.js";
@@ -48,7 +49,8 @@ import {
48
49
  CommandGroup,
49
50
  CommandInput,
50
51
  CommandItem,
51
- CommandList
52
+ CommandList,
53
+ CommandSeparator
52
54
  } from "./command.js";
53
55
  import { CommandPalette } from "./command-palette.js";
54
56
  import { PasswordInput } from "./password-input.js";
@@ -77,6 +79,7 @@ export {
77
79
  CommandItem,
78
80
  CommandList,
79
81
  CommandPalette,
82
+ CommandSeparator,
80
83
  DatePicker,
81
84
  DayButton,
82
85
  Field,
@@ -123,6 +126,8 @@ export {
123
126
  ToggleGroup,
124
127
  ToggleGroupItem,
125
128
  Transfer,
129
+ TranslatableInput,
130
+ TranslatableTextarea,
126
131
  TreeSelect,
127
132
  UPLOAD_LIST_IGNORE,
128
133
  Upload,
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import type { TranslatableValue } from "../../props/components/data-entry.prop.js";
3
+ export type { TranslatableValue, TranslatableInputProp, TranslatableInputProp as TranslatableInputProps, TranslatableTextareaProp, TranslatableTextareaProp as TranslatableTextareaProps, } from "../../props/components/data-entry.prop.js";
4
+ /**
5
+ * TranslatableInput — ONE text field that holds a value per locale (`{ ja, en, vi }`), switched by
6
+ * locale tabs above it (gh#1336). The locale list, the first tab and the fallback come from
7
+ * `AppProvider` and are overridable per field; an empty locale shows the fallback locale's text as
8
+ * its placeholder; a locale with an error is marked on its tab. Every other `Input` prop applies to
9
+ * the single control, and `ref` is that control's `<input>`.
10
+ */
11
+ export declare const TranslatableInput: React.ForwardRefExoticComponent<Omit<import("./input.js").InputProp, "defaultValue" | "lang" | "onValueChange" | "value"> & {
12
+ value?: import("../../props/index.js").ValueProp<TranslatableValue>;
13
+ defaultValue?: import("../../props/index.js").DefaultValueProp<TranslatableValue>;
14
+ onValueChange?: import("../../props/index.js").OnValueChangeProp<TranslatableValue>;
15
+ locales?: readonly string[];
16
+ defaultLocale?: string;
17
+ fallbackLocale?: string;
18
+ errors?: Partial<Record<string, import("../../props/index.js").ErrorProp>>;
19
+ } & React.RefAttributes<HTMLInputElement>>;
20
+ /** TranslatableTextarea — {@link TranslatableInput} over a `Textarea`; `ref` is the `<textarea>`. */
21
+ export declare const TranslatableTextarea: React.ForwardRefExoticComponent<Omit<import("./textarea.js").TextareaProp, "defaultValue" | "lang" | "onValueChange" | "value"> & {
22
+ value?: import("../../props/index.js").ValueProp<TranslatableValue>;
23
+ defaultValue?: import("../../props/index.js").DefaultValueProp<TranslatableValue>;
24
+ onValueChange?: import("../../props/index.js").OnValueChangeProp<TranslatableValue>;
25
+ locales?: readonly string[];
26
+ defaultLocale?: string;
27
+ fallbackLocale?: string;
28
+ errors?: Partial<Record<string, import("../../props/index.js").ErrorProp>>;
29
+ } & React.RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,184 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { CircleAlert } from "lucide-react";
5
+ import { useTranslation } from "../../i18n/use-translation.js";
6
+ import { getRegisteredLocales } from "../../i18n/locale-tags.js";
7
+ import { mergeAriaIds, useReportFieldError } from "../../lib/field-a11y.js";
8
+ import { displayNames } from "../../lib/intl-cache.js";
9
+ import { cn } from "../../lib/utils.js";
10
+ import { Tabs, TabsList, TabsTrigger } from "../navigation/tabs.js";
11
+ import { Input } from "./input.js";
12
+ import { Textarea } from "./textarea.js";
13
+ const NO_VALUE = {};
14
+ function localeName(code, uiLocale) {
15
+ try {
16
+ return displayNames(uiLocale, { type: "language" }).of(code) ?? code;
17
+ } catch {
18
+ return code;
19
+ }
20
+ }
21
+ const idPart = (code) => code.replace(/[^A-Za-z0-9_-]/g, "_");
22
+ function TranslatableField({
23
+ kind,
24
+ value: valueProp,
25
+ defaultValue,
26
+ onValueChange,
27
+ locales: localesProp,
28
+ defaultLocale,
29
+ fallbackLocale: fallbackLocaleProp,
30
+ errors,
31
+ size,
32
+ placeholder,
33
+ className,
34
+ forwardedRef,
35
+ ...rest
36
+ }) {
37
+ const { t, locale: uiLocale, fallbackLocale: appFallbackLocale } = useTranslation();
38
+ const locales = React.useMemo(() => {
39
+ const list = localesProp ?? getRegisteredLocales();
40
+ return list.length > 0 ? list : [uiLocale];
41
+ }, [localesProp, uiLocale]);
42
+ const pick = (candidates) => candidates.find((code) => code !== void 0 && locales.includes(code)) ?? locales[0];
43
+ const fallbackLocale = pick([fallbackLocaleProp, appFallbackLocale]);
44
+ const [activeState, setActiveState] = React.useState(
45
+ () => pick([defaultLocale, uiLocale, fallbackLocale])
46
+ );
47
+ const active = locales.includes(activeState) ? activeState : pick([defaultLocale, fallbackLocale]);
48
+ const [innerValue, setInnerValue] = React.useState(defaultValue ?? NO_VALUE);
49
+ const current = valueProp ?? innerValue;
50
+ const currentRef = React.useRef(current);
51
+ currentRef.current = current;
52
+ const handleText = (text) => {
53
+ const next = { ...currentRef.current, [active]: text };
54
+ currentRef.current = next;
55
+ if (valueProp === void 0) setInnerValue(next);
56
+ onValueChange?.(next);
57
+ };
58
+ const activeText = current[active] ?? "";
59
+ const fallbackText = active !== fallbackLocale && activeText === "" ? current[fallbackLocale] : void 0;
60
+ const activeError = errors?.[active];
61
+ const hasActiveError = activeError !== void 0 && activeError !== null && activeError !== false && activeError !== "";
62
+ const insideFormField = useReportFieldError(hasActiveError ? activeError : void 0);
63
+ const baseId = React.useId();
64
+ const tabId = (code) => `${baseId}-tab-${idPart(code)}`;
65
+ const panelId = `${baseId}-panel`;
66
+ const switcherNameId = `${baseId}-languages`;
67
+ const localeNameId = `${baseId}-locale`;
68
+ const ownErrorId = `${baseId}-error`;
69
+ const labelledBy = rest["aria-labelledby"];
70
+ const ariaLabel = rest["aria-label"];
71
+ const showOwnError = hasActiveError && !insideFormField;
72
+ const controlProps = {
73
+ ...rest,
74
+ ref: forwardedRef,
75
+ lang: active,
76
+ value: activeText,
77
+ onValueChange: handleText,
78
+ placeholder: fallbackText ? fallbackText : placeholder,
79
+ // The control is named by the field AND the locale it holds: "商品名 English".
80
+ "aria-labelledby": labelledBy ? `${labelledBy} ${localeNameId}` : void 0,
81
+ "aria-invalid": hasActiveError ? true : rest["aria-invalid"],
82
+ "aria-errormessage": mergeAriaIds(
83
+ rest["aria-errormessage"],
84
+ showOwnError ? ownErrorId : void 0
85
+ ),
86
+ status: hasActiveError ? "error" : rest.status
87
+ };
88
+ return /* @__PURE__ */ jsxs(
89
+ "div",
90
+ {
91
+ "data-slot": "translatable-field",
92
+ "data-size": size,
93
+ className: cn("ui-translatable-field", className),
94
+ children: [
95
+ /* @__PURE__ */ jsx(
96
+ Tabs,
97
+ {
98
+ value: active,
99
+ onValueChange: setActiveState,
100
+ size: size === "lg" ? "md" : "sm",
101
+ controls: panelId,
102
+ className: "ui-translatable-field-tabs",
103
+ ...labelledBy ? { "aria-labelledby": `${labelledBy} ${switcherNameId}` } : {
104
+ "aria-label": [ariaLabel, t("dataEntry.translatable.languages")].filter(Boolean).join(" ")
105
+ },
106
+ children: /* @__PURE__ */ jsx(TabsList, { children: locales.map((code) => {
107
+ const error = errors?.[code];
108
+ const invalid = error !== void 0 && error !== null && error !== false && error !== "";
109
+ return /* @__PURE__ */ jsxs(
110
+ TabsTrigger,
111
+ {
112
+ id: tabId(code),
113
+ value: code,
114
+ "data-locale": code,
115
+ "data-invalid": invalid ? "true" : void 0,
116
+ "data-filled": current[code] ? "true" : void 0,
117
+ children: [
118
+ /* @__PURE__ */ jsx("span", { children: localeName(code, uiLocale) }),
119
+ invalid ? /* @__PURE__ */ jsxs(Fragment, { children: [
120
+ /* @__PURE__ */ jsx(CircleAlert, { className: "ui-translatable-field-error-mark", "aria-hidden": "true" }),
121
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: `, ${t("dataEntry.translatable.hasError")}` })
122
+ ] }) : null
123
+ ]
124
+ },
125
+ code
126
+ );
127
+ }) })
128
+ }
129
+ ),
130
+ /* @__PURE__ */ jsx("span", { id: switcherNameId, hidden: true, children: t("dataEntry.translatable.languages") }),
131
+ /* @__PURE__ */ jsx("span", { id: localeNameId, hidden: true, children: localeName(active, uiLocale) }),
132
+ /* @__PURE__ */ jsx(
133
+ "div",
134
+ {
135
+ role: "tabpanel",
136
+ id: panelId,
137
+ "aria-labelledby": tabId(active),
138
+ className: "ui-translatable-field-panel",
139
+ children: kind === "input" ? /* @__PURE__ */ jsx(
140
+ Input,
141
+ {
142
+ ...controlProps,
143
+ size
144
+ }
145
+ ) : /* @__PURE__ */ jsx(
146
+ Textarea,
147
+ {
148
+ ...controlProps,
149
+ size
150
+ }
151
+ )
152
+ }
153
+ ),
154
+ showOwnError ? /* @__PURE__ */ jsx("p", { id: ownErrorId, role: "alert", className: "ui-form-field-note text-error-strong text-xs", children: activeError }) : null
155
+ ]
156
+ }
157
+ );
158
+ }
159
+ const TranslatableInput = React.forwardRef(
160
+ (props, ref) => /* @__PURE__ */ jsx(
161
+ TranslatableField,
162
+ {
163
+ ...props,
164
+ kind: "input",
165
+ forwardedRef: ref
166
+ }
167
+ )
168
+ );
169
+ TranslatableInput.displayName = "TranslatableInput";
170
+ const TranslatableTextarea = React.forwardRef(
171
+ (props, ref) => /* @__PURE__ */ jsx(
172
+ TranslatableField,
173
+ {
174
+ ...props,
175
+ kind: "textarea",
176
+ forwardedRef: ref
177
+ }
178
+ )
179
+ );
180
+ TranslatableTextarea.displayName = "TranslatableTextarea";
181
+ export {
182
+ TranslatableInput,
183
+ TranslatableTextarea
184
+ };
@@ -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": "33.1.1",
3
+ "version": "33.2.1",
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,
@@ -278,6 +278,10 @@
278
278
  "number": "Contains number",
279
279
  "symbol": "Contains symbol"
280
280
  }
281
+ },
282
+ "translatable": {
283
+ "languages": "Language",
284
+ "hasError": "has an error"
281
285
  }
282
286
  },
283
287
  "feedback": {
@@ -273,6 +273,10 @@
273
273
  "number": "数字を含む",
274
274
  "symbol": "記号を含む"
275
275
  }
276
+ },
277
+ "translatable": {
278
+ "languages": "言語",
279
+ "hasError": "エラーあり"
276
280
  }
277
281
  },
278
282
  "feedback": {
@@ -274,6 +274,10 @@
274
274
  "number": "Có chữ số",
275
275
  "symbol": "Có ký hiệu"
276
276
  }
277
+ },
278
+ "translatable": {
279
+ "languages": "Ngôn ngữ",
280
+ "hasError": "có lỗi"
277
281
  }
278
282
  },
279
283
  "feedback": {
@@ -106,3 +106,18 @@ export declare function pickGroupFieldA11y(props: FieldA11yProps): {
106
106
  "aria-describedby"?: string;
107
107
  "data-field"?: string;
108
108
  };
109
+ /**
110
+ * A control that owns SEVERAL values reports which of its messages is current (gh#1336). A
111
+ * `TranslatableInput` holds one value per locale and gets one message per locale; only the active
112
+ * locale's message describes the text the user is looking at, and only the control knows which
113
+ * locale that is. FormField reads the report as the lowest-precedence source of its `error` — its
114
+ * own `error` prop and the form's error bag both win — so the message renders in FormField's own
115
+ * error line and reaches the control through the same `aria-invalid` / `aria-errormessage` wiring
116
+ * every other field uses. `null` outside a FormField.
117
+ */
118
+ export declare const FieldErrorReportContext: React.Context<((message: React.ReactNode) => void) | null>;
119
+ /**
120
+ * Report `message` (or its absence) to the enclosing FormField. Returns `true` when a FormField is
121
+ * listening — a caller with no FormField above it has to render its own message.
122
+ */
123
+ export declare function useReportFieldError(message: React.ReactNode): boolean;
@@ -78,7 +78,18 @@ function pickGroupFieldA11y(props) {
78
78
  ...props["data-field"] !== void 0 ? { "data-field": props["data-field"] } : {}
79
79
  };
80
80
  }
81
+ const FieldErrorReportContext = React.createContext(null);
82
+ function useReportFieldError(message) {
83
+ const report = React.useContext(FieldErrorReportContext);
84
+ React.useEffect(() => {
85
+ if (!report) return;
86
+ report(message);
87
+ return () => report(void 0);
88
+ }, [report, message]);
89
+ return report !== null;
90
+ }
81
91
  export {
92
+ FieldErrorReportContext,
82
93
  FieldIdentityContext,
83
94
  FieldNameContext,
84
95
  mergeAriaIds,
@@ -88,5 +99,6 @@ export {
88
99
  resolveFieldA11y,
89
100
  useFieldIdentity,
90
101
  useFieldNameFallback,
91
- useMirroredInputAttributes
102
+ useMirroredInputAttributes,
103
+ useReportFieldError
92
104
  };
@@ -30,3 +30,4 @@ export declare function dateTimeFormat(locale: string, options?: Intl.DateTimeFo
30
30
  export declare function numberFormat(locale: string, options?: Intl.NumberFormatOptions): Intl.NumberFormat;
31
31
  export declare function pluralRules(locale: string, options?: Intl.PluralRulesOptions): Intl.PluralRules;
32
32
  export declare function listFormat(locale: string, options?: Intl.ListFormatOptions): Intl.ListFormat;
33
+ export declare function displayNames(locale: string, options: Intl.DisplayNamesOptions): Intl.DisplayNames;
@@ -21,8 +21,12 @@ function pluralRules(locale, options) {
21
21
  function listFormat(locale, options) {
22
22
  return memoise("lf", locale, options, () => new Intl.ListFormat(locale, options));
23
23
  }
24
+ function displayNames(locale, options) {
25
+ return memoise("dn", locale, options, () => new Intl.DisplayNames(locale, options));
26
+ }
24
27
  export {
25
28
  dateTimeFormat,
29
+ displayNames,
26
30
  listFormat,
27
31
  numberFormat,
28
32
  pluralRules
@@ -125,6 +125,14 @@ export type CommandProp = {
125
125
  */
126
126
  split?: boolean;
127
127
  };
128
+ export type CommandSeparatorProp = {
129
+ /**
130
+ * Keep the separator while a search query is typed. Default `true` — the opposite of cmdk, which
131
+ * hides it under a query; a `+ Create "<q>"` group only exists while the user types, so the rule
132
+ * above it must stay. `false` restores cmdk's palette behaviour.
133
+ */
134
+ alwaysRender?: boolean;
135
+ };
128
136
  export type InputProp = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "prefix"> & {
129
137
  onValueChange?: (value: string) => void;
130
138
  /**
@@ -221,6 +229,43 @@ export type TextareaProp = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
221
229
  /** Character counter — antd `count`. */
222
230
  count?: ControlCountProp;
223
231
  };
232
+ /**
233
+ * One translatable field's per-locale values, keyed by BCP-47 tag: `{ ja: "…", en: "…", vi: "…" }`.
234
+ * A locale with no key (or `""`) is empty. The shape a `*_translations` backend (Astrotomic,
235
+ * Spatie translatable, Rails Mobility) already sends.
236
+ */
237
+ export type TranslatableValue = Partial<Record<string, string>>;
238
+ /** The locale + value contract shared by {@link TranslatableInputProp} and {@link TranslatableTextareaProp}. */
239
+ type TranslatableFieldProp = {
240
+ /** Controlled per-locale values. */
241
+ value?: ValueProp<TranslatableValue>;
242
+ /** Uncontrolled initial per-locale values. */
243
+ defaultValue?: DefaultValueProp<TranslatableValue>;
244
+ /** The WHOLE map after an edit — every other locale's text is carried over untouched. */
245
+ onValueChange?: OnValueChangeProp<TranslatableValue>;
246
+ /**
247
+ * The locales the field edits, in tab order. Default: every locale registered with the app
248
+ * (`getRegisteredLocales()` — the built-in `vi`/`en`/`ja` plus `registerLocale(...)`).
249
+ */
250
+ locales?: readonly string[];
251
+ /** The locale tab selected first. Default: the AppProvider's active locale when it is in `locales`. */
252
+ defaultLocale?: string;
253
+ /**
254
+ * The locale whose text shows as the placeholder of an EMPTY locale. Default: the AppProvider's
255
+ * `fallbackLocale`, or the first of `locales` when that is not one of them.
256
+ */
257
+ fallbackLocale?: string;
258
+ /**
259
+ * Per-locale validation messages. A locale that has one gets an error mark on its tab (a glyph
260
+ * plus screen-reader text, never colour alone); the ACTIVE locale's message sets `aria-invalid`
261
+ * and is shown by the enclosing `FormField` (or under the field when there is none).
262
+ */
263
+ errors?: Partial<Record<string, ErrorProp>>;
264
+ };
265
+ /** @see TranslatableInput — one `Input` holding a value per locale, switched by locale tabs. */
266
+ export type TranslatableInputProp = Omit<InputProp, "value" | "defaultValue" | "onValueChange" | "lang"> & TranslatableFieldProp;
267
+ /** @see TranslatableTextarea — the `Textarea` counterpart of {@link TranslatableInputProp}. */
268
+ export type TranslatableTextareaProp = Omit<TextareaProp, "value" | "defaultValue" | "onValueChange" | "lang"> & TranslatableFieldProp;
224
269
  /**
225
270
  * @see NumberInput — localized numeric spinbutton (composes `Input` + step `Button`s).
226
271
  * `value`/`defaultValue`/`onValueChange` carry a `number | null` (null = empty). `step` drives both
@@ -2469,3 +2514,4 @@ export type EmojiPickerProp = {
2469
2514
  id?: IdProp;
2470
2515
  className?: ClassNameProp;
2471
2516
  };
2517
+ export {};
@@ -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, ColorPickerPresetProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
3
+ export type { CommandProp, CommandSeparatorProp, 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";
@@ -1641,11 +1641,62 @@ export declare const COMPONENT_PROP_REGISTRY: {
1641
1641
  readonly reason: "antd List `split` — ruled-list presentation (row dividers, 0 list padding) for option/checkbox lists; the rest of the root API is cmdk's (gh#699).";
1642
1642
  }];
1643
1643
  };
1644
+ readonly CommandSeparatorProp: {
1645
+ readonly group: "data-entry";
1646
+ readonly file: "components/data-entry.prop.ts";
1647
+ readonly vocabulary: readonly [{
1648
+ readonly field: "alwaysRender";
1649
+ readonly local: true;
1650
+ readonly reason: "cmdk's own Command.Separator prop name, kept so the cmdk docs still apply; only its default differs (true) so the rule stays above a `+ Create` group while the user types (gh#1335).";
1651
+ }];
1652
+ };
1644
1653
  readonly TextareaProp: {
1645
1654
  readonly group: "data-entry";
1646
1655
  readonly file: "components/data-entry.prop.ts";
1647
1656
  readonly vocabulary: readonly ["PlaceholderProp", "DisabledProp", "ValueProp", "DefaultValueProp", "OnChangeProp", "IdProp", "ClassNameProp"];
1648
1657
  };
1658
+ readonly TranslatableInputProp: {
1659
+ readonly group: "data-entry";
1660
+ readonly file: "components/data-entry.prop.ts";
1661
+ readonly vocabulary: readonly ["ValueProp", "DefaultValueProp", "OnValueChangeProp", "SizeProp", "PlaceholderProp", "DisabledProp", "IdProp", "ClassNameProp", {
1662
+ readonly field: "locales";
1663
+ readonly local: true;
1664
+ readonly reason: "The BCP-47 tags the field edits, in tab order (gh#1336). Defaults to the app's registered locales; a per-field list, not a value.";
1665
+ }, {
1666
+ readonly field: "defaultLocale";
1667
+ readonly local: true;
1668
+ readonly reason: "The locale tab selected first — the AppProvider's own `defaultLocale` spelling, scoped to one field. Defaults to the active app locale.";
1669
+ }, {
1670
+ readonly field: "fallbackLocale";
1671
+ readonly local: true;
1672
+ readonly reason: "The locale whose text an EMPTY locale shows as its placeholder — the AppProvider's own `fallbackLocale` spelling, scoped to one field.";
1673
+ }, {
1674
+ readonly field: "errors";
1675
+ readonly local: true;
1676
+ readonly reason: "Per-locale validation messages keyed by BCP-47 tag; marks each locale's tab and sends the ACTIVE one through FormField. `error` (one message) cannot say which locale failed.";
1677
+ }];
1678
+ };
1679
+ readonly TranslatableTextareaProp: {
1680
+ readonly group: "data-entry";
1681
+ readonly file: "components/data-entry.prop.ts";
1682
+ readonly vocabulary: readonly ["ValueProp", "DefaultValueProp", "OnValueChangeProp", "SizeProp", "PlaceholderProp", "DisabledProp", "IdProp", "ClassNameProp", {
1683
+ readonly field: "locales";
1684
+ readonly local: true;
1685
+ readonly reason: "The BCP-47 tags the field edits, in tab order (gh#1336). Defaults to the app's registered locales; a per-field list, not a value.";
1686
+ }, {
1687
+ readonly field: "defaultLocale";
1688
+ readonly local: true;
1689
+ readonly reason: "The locale tab selected first — the AppProvider's own `defaultLocale` spelling, scoped to one field. Defaults to the active app locale.";
1690
+ }, {
1691
+ readonly field: "fallbackLocale";
1692
+ readonly local: true;
1693
+ readonly reason: "The locale whose text an EMPTY locale shows as its placeholder — the AppProvider's own `fallbackLocale` spelling, scoped to one field.";
1694
+ }, {
1695
+ readonly field: "errors";
1696
+ readonly local: true;
1697
+ readonly reason: "Per-locale validation messages keyed by BCP-47 tag; marks each locale's tab and sends the ACTIVE one through FormField. `error` (one message) cannot say which locale failed.";
1698
+ }];
1699
+ };
1649
1700
  readonly NumberInputProp: {
1650
1701
  readonly group: "data-entry";
1651
1702
  readonly file: "components/data-entry.prop.ts";