@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.
- package/README.md +4 -4
- package/agent/START-HERE.md +6 -6
- package/agent/components/Command.json +9 -1
- package/agent/components/TranslatableInput.json +92 -0
- package/agent/components/TranslatableTextarea.json +84 -0
- package/agent/components-index.json +10 -0
- package/agent/components.json +185 -1
- package/agent/index.json +7 -7
- package/agent/llms.txt +7 -7
- package/agent/tokens.json +12 -0
- package/dist/components/data-entry/command.d.ts +22 -1
- package/dist/components/data-entry/command.js +14 -1
- package/dist/components/data-entry/form-field.js +10 -4
- package/dist/components/data-entry/index.d.ts +4 -2
- package/dist/components/data-entry/index.js +6 -1
- package/dist/components/data-entry/translatable-input.d.ts +29 -0
- package/dist/components/data-entry/translatable-input.js +184 -0
- package/dist/contracts/measurement.json +1 -1
- package/dist/i18n/messages/en.json +4 -0
- package/dist/i18n/messages/ja.json +4 -0
- package/dist/i18n/messages/vi.json +4 -0
- package/dist/lib/field-a11y.d.ts +15 -0
- package/dist/lib/field-a11y.js +13 -1
- package/dist/lib/intl-cache.d.ts +1 -0
- package/dist/lib/intl-cache.js +4 -0
- package/dist/props/components/data-entry.prop.d.ts +46 -0
- package/dist/props/components/index.d.ts +1 -1
- package/dist/props/registry.d.ts +51 -0
- package/dist/props/registry.js +79 -0
- package/dist/styles/control.css +15 -0
- package/dist/styles/data-entry-layout.css +25 -0
- package/dist/styles/layers.json +19 -1
- package/dist/styles.css +1 -1
- package/dist/tokens/components/data-entry.css +4 -0
- 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 {
|
|
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
|
|
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.
|
|
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,
|
package/dist/lib/field-a11y.d.ts
CHANGED
|
@@ -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;
|
package/dist/lib/field-a11y.js
CHANGED
|
@@ -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
|
};
|
package/dist/lib/intl-cache.d.ts
CHANGED
|
@@ -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;
|
package/dist/lib/intl-cache.js
CHANGED
|
@@ -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";
|
package/dist/props/registry.d.ts
CHANGED
|
@@ -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";
|