@skiddph/prui 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +1 -0
- package/dist/core/input.d.ts +5 -1
- package/dist/core/input.js +61 -37
- package/dist/core/tag-input.d.ts +47 -0
- package/dist/core/tag-input.js +140 -0
- package/dist/core.js +140 -137
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n.js +27 -24
- package/dist/index.js +240 -237
- package/dist/prui-utilities.css +1 -1
- package/dist/prui.css +1 -1
- package/package.json +1 -1
package/dist/core/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { Portal, useReducedMotion, useFocusTrap, useEscapeKey, useScrollLock, us
|
|
|
6
6
|
export { moveIndex, homeIndex, endIndex, typeaheadIndex } from './list-nav';
|
|
7
7
|
export { Button, buttonPropsMeta, type ButtonProps, type ButtonVariant, type ButtonSize, } from './button';
|
|
8
8
|
export { Input, inputPropsMeta, Textarea, textareaPropsMeta, type InputProps, type TextareaProps, } from './input';
|
|
9
|
+
export { TagInput, tagInputPropsMeta, type TagInputProps, type TagInputSize, } from './tag-input';
|
|
9
10
|
export { Label, labelPropsMeta, Separator, separatorPropsMeta, type LabelProps, type SeparatorProps } from './label';
|
|
10
11
|
export { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, selectPropsMeta, type SelectProps, type SelectOption, type SelectTriggerProps, type SelectValueProps, type SelectContentProps, type SelectItemProps, } from './select';
|
|
11
12
|
export { Switch, switchPropsMeta, type SwitchProps } from './switch';
|
package/dist/core/input.d.ts
CHANGED
|
@@ -14,8 +14,12 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
|
|
|
14
14
|
variant?: "default" | "filled";
|
|
15
15
|
/** Icon rendered inside the field's leading edge. */
|
|
16
16
|
icon?: React.ReactNode;
|
|
17
|
-
/** Icon rendered inside the field's trailing edge.
|
|
17
|
+
/** Icon rendered inside the field's trailing edge. A custom trailingIcon
|
|
18
|
+
* takes over the slot and suppresses the password eye toggle. */
|
|
18
19
|
trailingIcon?: React.ReactNode;
|
|
20
|
+
/** With type="password", render an eye show/hide toggle in the trailing
|
|
21
|
+
* slot (the default). Set false to keep a plain masked field. */
|
|
22
|
+
passwordToggle?: boolean;
|
|
19
23
|
}
|
|
20
24
|
export declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
|
|
21
25
|
export declare const inputPropsMeta: PropsMeta;
|
package/dist/core/input.js
CHANGED
|
@@ -1,59 +1,83 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import * as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { jsx as e, jsxs as S } from "react/jsx-runtime";
|
|
2
|
+
import * as u from "react";
|
|
3
|
+
import { EyeOff as T, Eye as k } from "lucide-react";
|
|
4
|
+
import { resolveSurface as z, withSurface as E } from "./surface.js";
|
|
5
|
+
import { cn as h } from "./cn.js";
|
|
6
|
+
import { usePruiI18n as M } from "../i18n.js";
|
|
7
|
+
const v = "prui-f-control prui-input w-full bg-[var(--prui-s-bg,var(--prui-background))] text-[var(--prui-s-fg,var(--prui-fg))] placeholder:text-[var(--prui-dim)] border border-[var(--prui-line)] rounded-[var(--prui-s-radius,var(--prui-radius))] text-sm outline-none transition-colors focus:border-[var(--prui-brand)] focus:ring-2 focus:ring-[var(--prui-brand)]/30 disabled:opacity-50 disabled:cursor-not-allowed", D = {
|
|
6
8
|
sm: "h-8 px-2.5",
|
|
7
9
|
md: "h-9 px-3",
|
|
8
10
|
lg: "h-11 px-4 text-base"
|
|
9
|
-
},
|
|
10
|
-
({ className:
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
t && "pr-9",
|
|
18
|
-
|
|
11
|
+
}, B = u.forwardRef(
|
|
12
|
+
({ className: s, style: l, type: a = "text", size: i = "md", variant: g = "default", icon: r, trailingIcon: t, passwordToggle: y = !0, bg: b, fg: x, radius: w, texture: N, textureColor: R, elevation: P, ...p }, j) => {
|
|
13
|
+
const { t: c } = M(), [n, C] = u.useState(!1), o = a === "password" && y !== !1 && !t, I = z({ bg: b, fg: x, radius: w, texture: N, textureColor: R, elevation: P }), f = E(
|
|
14
|
+
h(
|
|
15
|
+
v,
|
|
16
|
+
D[i],
|
|
17
|
+
g === "filled" && "bg-[var(--prui-s-bg,var(--prui-raise))] border-transparent",
|
|
18
|
+
r && "pl-9",
|
|
19
|
+
(t || o) && "pr-9",
|
|
20
|
+
s
|
|
19
21
|
),
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
l,
|
|
23
|
+
I
|
|
24
|
+
), m = /* @__PURE__ */ e(
|
|
25
|
+
"input",
|
|
26
|
+
{
|
|
27
|
+
ref: j,
|
|
28
|
+
type: o && n ? "text" : a,
|
|
29
|
+
className: f.className,
|
|
30
|
+
style: f.style,
|
|
31
|
+
...p
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
return !r && !t && !o ? m : /* @__PURE__ */ S("span", { className: "relative inline-flex w-full", children: [
|
|
35
|
+
r ? /* @__PURE__ */ e("span", { "aria-hidden": !0, className: "pointer-events-none absolute left-3 top-1/2 flex -translate-y-1/2 items-center text-[var(--prui-dim)] [&>svg]:h-4 [&>svg]:w-4", children: r }) : null,
|
|
36
|
+
m,
|
|
37
|
+
t ? /* @__PURE__ */ e("span", { "aria-hidden": !0, className: "pointer-events-none absolute right-3 top-1/2 flex -translate-y-1/2 items-center text-[var(--prui-dim)] [&>svg]:h-4 [&>svg]:w-4", children: t }) : o ? /* @__PURE__ */ e(
|
|
38
|
+
"button",
|
|
39
|
+
{
|
|
40
|
+
type: "button",
|
|
41
|
+
"aria-label": n ? c.hidePassword : c.showPassword,
|
|
42
|
+
"aria-pressed": n,
|
|
43
|
+
disabled: p.disabled,
|
|
44
|
+
onMouseDown: (d) => d.preventDefault(),
|
|
45
|
+
onClick: () => C((d) => !d),
|
|
46
|
+
className: "absolute right-1.5 top-1/2 flex h-6 w-6 -translate-y-1/2 cursor-pointer items-center justify-center rounded-[var(--prui-radius-1)] text-[var(--prui-dim)] hover:bg-[var(--prui-raise)] hover:text-[var(--prui-fg)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
47
|
+
children: n ? /* @__PURE__ */ e(T, { className: "h-4 w-4", "aria-hidden": !0 }) : /* @__PURE__ */ e(k, { className: "h-4 w-4", "aria-hidden": !0 })
|
|
48
|
+
}
|
|
49
|
+
) : null
|
|
27
50
|
] });
|
|
28
51
|
}
|
|
29
52
|
);
|
|
30
|
-
|
|
31
|
-
const
|
|
53
|
+
B.displayName = "Input";
|
|
54
|
+
const J = {
|
|
32
55
|
name: "Input",
|
|
33
56
|
props: [
|
|
34
57
|
{ name: "type", type: "string", default: "'text'", control: "select", options: ["text", "password", "email", "number", "search"] },
|
|
35
58
|
{ name: "size", type: "'sm' | 'md' | 'lg'", default: "'md'", control: "select", options: ["sm", "md", "lg"] },
|
|
36
59
|
{ name: "variant", type: "'default' | 'filled'", default: "'default'", control: "select", options: ["default", "filled"] },
|
|
37
60
|
{ name: "icon", type: "ReactNode", default: "undefined", control: "none", description: "Icon inside the leading edge (padding adjusts)." },
|
|
38
|
-
{ name: "trailingIcon", type: "ReactNode", default: "undefined", control: "none", description: "Icon inside the trailing edge." },
|
|
61
|
+
{ name: "trailingIcon", type: "ReactNode", default: "undefined", control: "none", description: "Icon inside the trailing edge; takes over the slot from the password eye." },
|
|
62
|
+
{ name: "passwordToggle", type: "boolean", default: "true", control: "boolean", description: "type=password renders an eye show/hide toggle unless a trailingIcon owns the slot." },
|
|
39
63
|
{ name: "value", type: "string", default: null, control: "text" },
|
|
40
64
|
{ name: "placeholder", type: "string", default: "undefined", control: "text" },
|
|
41
65
|
{ name: "disabled", type: "boolean", default: "false", control: "boolean" },
|
|
42
66
|
{ name: "onChange", type: "(e) => void", default: null, control: "none" }
|
|
43
67
|
]
|
|
44
|
-
},
|
|
45
|
-
({ className:
|
|
68
|
+
}, O = u.forwardRef(
|
|
69
|
+
({ className: s, style: l, ...a }, i) => /* @__PURE__ */ e(
|
|
46
70
|
"textarea",
|
|
47
71
|
{
|
|
48
|
-
ref:
|
|
49
|
-
style:
|
|
50
|
-
className:
|
|
51
|
-
...
|
|
72
|
+
ref: i,
|
|
73
|
+
style: l,
|
|
74
|
+
className: h(v, "h-auto min-h-20 resize-y px-3 py-2", s),
|
|
75
|
+
...a
|
|
52
76
|
}
|
|
53
77
|
)
|
|
54
78
|
);
|
|
55
|
-
|
|
56
|
-
const
|
|
79
|
+
O.displayName = "Textarea";
|
|
80
|
+
const K = {
|
|
57
81
|
name: "Textarea",
|
|
58
82
|
props: [
|
|
59
83
|
{ name: "value", type: "string", default: null, control: "textarea" },
|
|
@@ -63,8 +87,8 @@ const k = {
|
|
|
63
87
|
]
|
|
64
88
|
};
|
|
65
89
|
export {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
B as Input,
|
|
91
|
+
O as Textarea,
|
|
92
|
+
J as inputPropsMeta,
|
|
93
|
+
K as textareaPropsMeta
|
|
70
94
|
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SurfaceProps } from './surface';
|
|
2
|
+
import { PropsMeta } from './props-meta';
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
/**
|
|
5
|
+
* TagInput: comma-separated entry as removable chips (tags, email
|
|
6
|
+
* recipients, keywords). Text commits on a separator, Enter, paste of
|
|
7
|
+
* multi-value text, or blur; Backspace on an empty field removes the last
|
|
8
|
+
* tag. The chip and the value are separate concerns: labelFor decides what
|
|
9
|
+
* the chip displays while onChange keeps emitting the original strings, and
|
|
10
|
+
* renderTag takes over the chip entirely.
|
|
11
|
+
*/
|
|
12
|
+
export type TagInputSize = "sm" | "md" | "lg";
|
|
13
|
+
export interface TagInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "defaultValue" | "onChange" | "children">, SurfaceProps {
|
|
14
|
+
/** Control height step (the field grows vertically with wrapped chips). */
|
|
15
|
+
size?: TagInputSize;
|
|
16
|
+
/** Visual variant: outlined (default) or filled. */
|
|
17
|
+
variant?: "default" | "filled";
|
|
18
|
+
/** Controlled tag values. */
|
|
19
|
+
value?: string[];
|
|
20
|
+
/** Initial tags for the uncontrolled field. */
|
|
21
|
+
defaultValue?: string[];
|
|
22
|
+
/** Emits the full tag array on every add/remove. */
|
|
23
|
+
onChange?: (tags: string[]) => void;
|
|
24
|
+
/** Characters that commit the typed text as a tag (default: comma). */
|
|
25
|
+
separators?: string[];
|
|
26
|
+
/** Commit the pending text when the field blurs (default true). */
|
|
27
|
+
commitOnBlur?: boolean;
|
|
28
|
+
/** Programmable commit: split raw text into tag values. Defaults to
|
|
29
|
+
* splitting on `separators`, trimming, and dropping empties. Use it to
|
|
30
|
+
* accept pair syntaxes (e.g. "Name, email" -> "Name <email>"). */
|
|
31
|
+
parseInput?: (raw: string) => string[];
|
|
32
|
+
/** Reject a candidate; rejected text stays editable in the field. */
|
|
33
|
+
validate?: (tag: string) => boolean;
|
|
34
|
+
/** Stop accepting new tags at this count. */
|
|
35
|
+
maxTags?: number;
|
|
36
|
+
/** Allow the same value more than once (default false). */
|
|
37
|
+
allowDuplicates?: boolean;
|
|
38
|
+
/** What the chip displays — the emitted value keeps the original string
|
|
39
|
+
* (e.g. show only the name for "Name <email>"). */
|
|
40
|
+
labelFor?: (tag: string) => React.ReactNode;
|
|
41
|
+
/** Fully custom chip: (tag, { remove }) => node. */
|
|
42
|
+
renderTag?: (tag: string, api: {
|
|
43
|
+
remove: () => void;
|
|
44
|
+
}) => React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
export declare const TagInput: React.ForwardRefExoticComponent<TagInputProps & React.RefAttributes<HTMLInputElement>>;
|
|
47
|
+
export declare const tagInputPropsMeta: PropsMeta;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { jsxs as I, jsx as u } from "react/jsx-runtime";
|
|
2
|
+
import * as c from "react";
|
|
3
|
+
import { X as L } from "lucide-react";
|
|
4
|
+
import { resolveSurface as Q, withSurface as W } from "./surface.js";
|
|
5
|
+
import { cn as Y } from "./cn.js";
|
|
6
|
+
import { usePruiI18n as Z } from "../i18n.js";
|
|
7
|
+
const ee = (v) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), te = {
|
|
8
|
+
sm: "min-h-8 text-sm",
|
|
9
|
+
md: "min-h-9 text-sm",
|
|
10
|
+
lg: "min-h-11 text-base"
|
|
11
|
+
}, ne = c.forwardRef(function({
|
|
12
|
+
className: j,
|
|
13
|
+
style: k,
|
|
14
|
+
size: R = "md",
|
|
15
|
+
variant: T = "default",
|
|
16
|
+
value: b,
|
|
17
|
+
defaultValue: B,
|
|
18
|
+
onChange: d,
|
|
19
|
+
separators: l = [","],
|
|
20
|
+
commitOnBlur: P = !0,
|
|
21
|
+
parseInput: S,
|
|
22
|
+
validate: h,
|
|
23
|
+
maxTags: y,
|
|
24
|
+
allowDuplicates: C = !1,
|
|
25
|
+
labelFor: x,
|
|
26
|
+
renderTag: w,
|
|
27
|
+
disabled: m,
|
|
28
|
+
bg: z,
|
|
29
|
+
fg: E,
|
|
30
|
+
radius: F,
|
|
31
|
+
texture: K,
|
|
32
|
+
textureColor: A,
|
|
33
|
+
elevation: M,
|
|
34
|
+
...n
|
|
35
|
+
}, O) {
|
|
36
|
+
const { t: U } = Z(), N = b !== void 0, [V, X] = c.useState(B ?? []), r = N ? b : V, [o, f] = c.useState(""), _ = S ?? ((e) => e.split(new RegExp(l.map(ee).join("|"))).map((t) => t.trim()).filter(Boolean)), $ = (e) => {
|
|
37
|
+
N || X(e), d == null || d(e);
|
|
38
|
+
}, p = (e) => {
|
|
39
|
+
const t = _(e);
|
|
40
|
+
if (!t.length) {
|
|
41
|
+
f("");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const a = [...r], i = [];
|
|
45
|
+
for (const s of t)
|
|
46
|
+
y !== void 0 && a.length >= y ? i.push(s) : !C && a.includes(s) || (h && !h(s) ? i.push(s) : a.push(s));
|
|
47
|
+
f(i.join(l[0] ?? ", ")), a.length !== r.length && $(a);
|
|
48
|
+
}, g = (e) => $(r.filter((t, a) => a !== e)), q = (e) => {
|
|
49
|
+
var t;
|
|
50
|
+
e.key === "Enter" || l.includes(e.key) ? (e.preventDefault(), p(o)) : e.key === "Backspace" && !o && r.length && (e.preventDefault(), g(r.length - 1)), (t = n.onKeyDown) == null || t.call(n, e);
|
|
51
|
+
}, G = (e) => {
|
|
52
|
+
var a;
|
|
53
|
+
const t = e.clipboardData.getData("text");
|
|
54
|
+
if (t && l.some((i) => t.includes(i))) {
|
|
55
|
+
e.preventDefault(), p(o ? `${o}${l[0] ?? ","}${t}` : t);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
(a = n.onPaste) == null || a.call(n, e);
|
|
59
|
+
}, H = (e) => {
|
|
60
|
+
var t;
|
|
61
|
+
P && p(o), (t = n.onBlur) == null || t.call(n, e);
|
|
62
|
+
}, J = Q({ bg: z, fg: E, radius: F, texture: K, textureColor: A, elevation: M }), D = W(
|
|
63
|
+
Y(
|
|
64
|
+
"prui-f-control prui-taginput flex w-full flex-wrap items-center gap-1 px-1.5 py-1",
|
|
65
|
+
"border border-[var(--prui-line)] rounded-[var(--prui-s-radius,var(--prui-radius))]",
|
|
66
|
+
"bg-[var(--prui-s-bg,var(--prui-background))] text-[var(--prui-s-fg,var(--prui-fg))] placeholder:text-[var(--prui-dim)]",
|
|
67
|
+
"outline-none transition-colors focus-within:border-[var(--prui-brand)] focus-within:ring-2 focus-within:ring-[var(--prui-brand)]/30",
|
|
68
|
+
te[R],
|
|
69
|
+
T === "filled" && "bg-[var(--prui-s-bg,var(--prui-raise))] border-transparent",
|
|
70
|
+
m && "opacity-50 cursor-not-allowed",
|
|
71
|
+
j
|
|
72
|
+
),
|
|
73
|
+
k,
|
|
74
|
+
J
|
|
75
|
+
);
|
|
76
|
+
return /* @__PURE__ */ I("div", { className: D.className, style: D.style, children: [
|
|
77
|
+
r.map(
|
|
78
|
+
(e, t) => w ? /* @__PURE__ */ u(c.Fragment, { children: w(e, { remove: () => g(t) }) }, `${e}-${t}`) : /* @__PURE__ */ I(
|
|
79
|
+
"span",
|
|
80
|
+
{
|
|
81
|
+
className: "inline-flex max-w-full items-center gap-1 rounded-[var(--prui-radius-full)] border border-[var(--prui-line)] bg-[var(--prui-raise)] py-0.5 pl-2 pr-1 text-xs text-[var(--prui-fg)]",
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ u("span", { className: "max-w-64 truncate", children: x ? x(e) : e }),
|
|
84
|
+
/* @__PURE__ */ u(
|
|
85
|
+
"button",
|
|
86
|
+
{
|
|
87
|
+
type: "button",
|
|
88
|
+
"aria-label": U.removeTag.replace("{label}", e),
|
|
89
|
+
disabled: m,
|
|
90
|
+
onClick: () => g(t),
|
|
91
|
+
className: "flex h-4 w-4 cursor-pointer items-center justify-center rounded-full text-[var(--prui-dim)] hover:bg-[var(--prui-line)] hover:text-[var(--prui-fg)] disabled:cursor-not-allowed",
|
|
92
|
+
children: /* @__PURE__ */ u(L, { className: "h-3 w-3", "aria-hidden": !0 })
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
`${e}-${t}`
|
|
98
|
+
)
|
|
99
|
+
),
|
|
100
|
+
/* @__PURE__ */ u(
|
|
101
|
+
"input",
|
|
102
|
+
{
|
|
103
|
+
ref: O,
|
|
104
|
+
value: o,
|
|
105
|
+
onChange: (e) => f(e.target.value),
|
|
106
|
+
onKeyDown: q,
|
|
107
|
+
onPaste: G,
|
|
108
|
+
onBlur: H,
|
|
109
|
+
disabled: m,
|
|
110
|
+
...n,
|
|
111
|
+
className: "h-7 min-w-16 flex-1 bg-transparent text-sm outline-none placeholder:text-[var(--prui-dim)] disabled:cursor-not-allowed"
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
] });
|
|
115
|
+
});
|
|
116
|
+
ne.displayName = "TagInput";
|
|
117
|
+
const se = {
|
|
118
|
+
name: "TagInput",
|
|
119
|
+
props: [
|
|
120
|
+
{ name: "value", type: "string[]", default: "uncontrolled", control: "none" },
|
|
121
|
+
{ name: "defaultValue", type: "string[]", default: "[]", control: "none" },
|
|
122
|
+
{ name: "onChange", type: "(tags: string[]) => void", default: null, control: "none" },
|
|
123
|
+
{ name: "separators", type: "string[]", default: "[',']", control: "none", description: "Characters that commit the typed text (plus Enter, paste, blur)." },
|
|
124
|
+
{ name: "commitOnBlur", type: "boolean", default: "true", control: "boolean" },
|
|
125
|
+
{ name: "parseInput", type: "(raw: string) => string[]", default: "split on separators", control: "none", description: "Programmable commit: build tag values from raw text (pair syntaxes, normalization)." },
|
|
126
|
+
{ name: "validate", type: "(tag: string) => boolean", default: "undefined", control: "none", description: "Reject a candidate; it stays editable in the field." },
|
|
127
|
+
{ name: "labelFor", type: "(tag: string) => ReactNode", default: "undefined", control: "none", description: "Chip display; onChange keeps emitting the original strings." },
|
|
128
|
+
{ name: "renderTag", type: "(tag, { remove }) => ReactNode", default: "default chip", control: "none", description: "Fully custom chip rendering." },
|
|
129
|
+
{ name: "maxTags", type: "number", default: "undefined", control: "number" },
|
|
130
|
+
{ name: "allowDuplicates", type: "boolean", default: "false", control: "boolean" },
|
|
131
|
+
{ name: "size", type: "'sm' | 'md' | 'lg'", default: "'md'", control: "select", options: ["sm", "md", "lg"] },
|
|
132
|
+
{ name: "variant", type: "'default' | 'filled'", default: "'default'", control: "select", options: ["default", "filled"] },
|
|
133
|
+
{ name: "placeholder", type: "string", default: "undefined", control: "text" },
|
|
134
|
+
{ name: "disabled", type: "boolean", default: "false", control: "boolean" }
|
|
135
|
+
]
|
|
136
|
+
};
|
|
137
|
+
export {
|
|
138
|
+
ne as TagInput,
|
|
139
|
+
se as tagInputPropsMeta
|
|
140
|
+
};
|