twico-ui 1.29.0 → 1.30.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/CHANGELOG.md +7 -0
- package/dist/index.cjs +145 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.mjs +145 -47
- package/dist/index.mjs.map +1 -1
- package/llms.txt +5 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1536,6 +1536,10 @@ interface Option {
|
|
|
1536
1536
|
label: string;
|
|
1537
1537
|
/** Optional second line shown under the label. */
|
|
1538
1538
|
description?: string;
|
|
1539
|
+
/** #326: leading icon/swatch node, rendered before the label (mirrors a Command item's icon). */
|
|
1540
|
+
icon?: React.ReactNode;
|
|
1541
|
+
/** #326: trailing hint node, right-aligned after the label (e.g. a code, shortcut, or badge). */
|
|
1542
|
+
hint?: React.ReactNode;
|
|
1539
1543
|
/** Disable this option — not selectable, skipped by keyboard navigation. */
|
|
1540
1544
|
disabled?: boolean;
|
|
1541
1545
|
}
|
|
@@ -1601,6 +1605,10 @@ interface ComboboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>
|
|
|
1601
1605
|
* ellipsis — useful when options share a long prefix and differ only in a truncated tail. Takes precedence
|
|
1602
1606
|
* over `virtualized` (wrapped rows aren't a fixed height). @default false */
|
|
1603
1607
|
wrapOptions?: boolean;
|
|
1608
|
+
/** #326: render a custom option row body (twico keeps the checkmark, keyboard nav, and ARIA wiring). For
|
|
1609
|
+
* lightweight cases prefer the additive `icon`/`hint` fields on an option instead. Disables `virtualized`
|
|
1610
|
+
* (custom rows aren't a fixed height). */
|
|
1611
|
+
renderOption?: (option: ComboboxOption, state: { selected: boolean; active: boolean }) => React.ReactNode;
|
|
1604
1612
|
/** Composed with the field's open-on-focus behavior — your handler runs first. */
|
|
1605
1613
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
1606
1614
|
/** Composed with the field's keyboard navigation (Arrows/Enter/Escape) — your handler runs first; call `event.preventDefault()` to suppress it. */
|
|
@@ -2704,6 +2712,10 @@ interface MultiSelectProps extends Omit<React.InputHTMLAttributes<HTMLInputEleme
|
|
|
2704
2712
|
virtualized?: boolean;
|
|
2705
2713
|
/** Extra option rows rendered above/below the viewport when `virtualized`, to smooth fast scrolling. @default 8 */
|
|
2706
2714
|
overscan?: number;
|
|
2715
|
+
/** #326: render a custom option row body (twico keeps the checkbox, keyboard nav, and ARIA wiring). For
|
|
2716
|
+
* lightweight cases prefer the additive `icon`/`hint` fields on an option instead. Disables `virtualized`
|
|
2717
|
+
* (custom rows aren't a fixed height). */
|
|
2718
|
+
renderOption?: (option: MultiSelectOption, state: { selected: boolean; active: boolean }) => React.ReactNode;
|
|
2707
2719
|
/** Composed with the field's open-on-focus behavior — your handler runs first. */
|
|
2708
2720
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
2709
2721
|
/** Composed with the field's keyboard navigation (Arrows/Enter/Escape/Backspace) — your handler runs first; call `event.preventDefault()` to suppress it. */
|
|
@@ -3011,6 +3023,10 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
|
3011
3023
|
rightAddon?: React.ReactNode;
|
|
3012
3024
|
/** With `maxLength`, render a live `current / max` character counter on the hint/error line; danger-toned near the limit. @default false */
|
|
3013
3025
|
showCount?: boolean;
|
|
3026
|
+
/** #328: show a trailing clear (X) button when the field is non-empty; clicking it empties the field and
|
|
3027
|
+
* fires `onChange` with the empty value (controlled callers update). Composes with `rightIcon` and, for
|
|
3028
|
+
* `type="password"`, sits alongside the reveal-eye toggle. @default false */
|
|
3029
|
+
clearable?: boolean;
|
|
3014
3030
|
}
|
|
3015
3031
|
|
|
3016
3032
|
declare function Input(props: InputProps): React.JSX.Element;
|
|
@@ -3383,6 +3399,10 @@ interface SelectProps extends Omit<React.HTMLAttributes<HTMLButtonElement>, "onC
|
|
|
3383
3399
|
virtualized?: boolean;
|
|
3384
3400
|
/** Extra option rows rendered above/below the viewport when `virtualized`, to smooth fast scrolling. @default 8 */
|
|
3385
3401
|
overscan?: number;
|
|
3402
|
+
/** #326: render a custom option row body (twico keeps the checkmark, keyboard nav, and ARIA wiring). For
|
|
3403
|
+
* lightweight cases prefer the additive `icon`/`hint` fields on an option instead. Disables `virtualized`
|
|
3404
|
+
* (custom rows aren't a fixed height). */
|
|
3405
|
+
renderOption?: (option: SelectOption, state: { selected: boolean; active: boolean }) => React.ReactNode;
|
|
3386
3406
|
}
|
|
3387
3407
|
|
|
3388
3408
|
/** Alias of the shared {@link Option} type (kept for backward-compatible imports). */
|
|
@@ -3761,6 +3781,9 @@ interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement
|
|
|
3761
3781
|
maxRows?: number;
|
|
3762
3782
|
/** With `maxLength`, render a live `current / max` character counter; danger-toned near the limit. @default false */
|
|
3763
3783
|
showCount?: boolean;
|
|
3784
|
+
/** #328: show a trailing clear (X) button (top-inline-end, clear of the resize handle) when non-empty;
|
|
3785
|
+
* clicking it empties the field and fires `onChange` with the empty value. @default false */
|
|
3786
|
+
clearable?: boolean;
|
|
3764
3787
|
}
|
|
3765
3788
|
|
|
3766
3789
|
/** Forwards `ref` to the inner `<textarea>`. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1536,6 +1536,10 @@ interface Option {
|
|
|
1536
1536
|
label: string;
|
|
1537
1537
|
/** Optional second line shown under the label. */
|
|
1538
1538
|
description?: string;
|
|
1539
|
+
/** #326: leading icon/swatch node, rendered before the label (mirrors a Command item's icon). */
|
|
1540
|
+
icon?: React.ReactNode;
|
|
1541
|
+
/** #326: trailing hint node, right-aligned after the label (e.g. a code, shortcut, or badge). */
|
|
1542
|
+
hint?: React.ReactNode;
|
|
1539
1543
|
/** Disable this option — not selectable, skipped by keyboard navigation. */
|
|
1540
1544
|
disabled?: boolean;
|
|
1541
1545
|
}
|
|
@@ -1601,6 +1605,10 @@ interface ComboboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>
|
|
|
1601
1605
|
* ellipsis — useful when options share a long prefix and differ only in a truncated tail. Takes precedence
|
|
1602
1606
|
* over `virtualized` (wrapped rows aren't a fixed height). @default false */
|
|
1603
1607
|
wrapOptions?: boolean;
|
|
1608
|
+
/** #326: render a custom option row body (twico keeps the checkmark, keyboard nav, and ARIA wiring). For
|
|
1609
|
+
* lightweight cases prefer the additive `icon`/`hint` fields on an option instead. Disables `virtualized`
|
|
1610
|
+
* (custom rows aren't a fixed height). */
|
|
1611
|
+
renderOption?: (option: ComboboxOption, state: { selected: boolean; active: boolean }) => React.ReactNode;
|
|
1604
1612
|
/** Composed with the field's open-on-focus behavior — your handler runs first. */
|
|
1605
1613
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
1606
1614
|
/** Composed with the field's keyboard navigation (Arrows/Enter/Escape) — your handler runs first; call `event.preventDefault()` to suppress it. */
|
|
@@ -2704,6 +2712,10 @@ interface MultiSelectProps extends Omit<React.InputHTMLAttributes<HTMLInputEleme
|
|
|
2704
2712
|
virtualized?: boolean;
|
|
2705
2713
|
/** Extra option rows rendered above/below the viewport when `virtualized`, to smooth fast scrolling. @default 8 */
|
|
2706
2714
|
overscan?: number;
|
|
2715
|
+
/** #326: render a custom option row body (twico keeps the checkbox, keyboard nav, and ARIA wiring). For
|
|
2716
|
+
* lightweight cases prefer the additive `icon`/`hint` fields on an option instead. Disables `virtualized`
|
|
2717
|
+
* (custom rows aren't a fixed height). */
|
|
2718
|
+
renderOption?: (option: MultiSelectOption, state: { selected: boolean; active: boolean }) => React.ReactNode;
|
|
2707
2719
|
/** Composed with the field's open-on-focus behavior — your handler runs first. */
|
|
2708
2720
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
|
2709
2721
|
/** Composed with the field's keyboard navigation (Arrows/Enter/Escape/Backspace) — your handler runs first; call `event.preventDefault()` to suppress it. */
|
|
@@ -3011,6 +3023,10 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
|
3011
3023
|
rightAddon?: React.ReactNode;
|
|
3012
3024
|
/** With `maxLength`, render a live `current / max` character counter on the hint/error line; danger-toned near the limit. @default false */
|
|
3013
3025
|
showCount?: boolean;
|
|
3026
|
+
/** #328: show a trailing clear (X) button when the field is non-empty; clicking it empties the field and
|
|
3027
|
+
* fires `onChange` with the empty value (controlled callers update). Composes with `rightIcon` and, for
|
|
3028
|
+
* `type="password"`, sits alongside the reveal-eye toggle. @default false */
|
|
3029
|
+
clearable?: boolean;
|
|
3014
3030
|
}
|
|
3015
3031
|
|
|
3016
3032
|
declare function Input(props: InputProps): React.JSX.Element;
|
|
@@ -3383,6 +3399,10 @@ interface SelectProps extends Omit<React.HTMLAttributes<HTMLButtonElement>, "onC
|
|
|
3383
3399
|
virtualized?: boolean;
|
|
3384
3400
|
/** Extra option rows rendered above/below the viewport when `virtualized`, to smooth fast scrolling. @default 8 */
|
|
3385
3401
|
overscan?: number;
|
|
3402
|
+
/** #326: render a custom option row body (twico keeps the checkmark, keyboard nav, and ARIA wiring). For
|
|
3403
|
+
* lightweight cases prefer the additive `icon`/`hint` fields on an option instead. Disables `virtualized`
|
|
3404
|
+
* (custom rows aren't a fixed height). */
|
|
3405
|
+
renderOption?: (option: SelectOption, state: { selected: boolean; active: boolean }) => React.ReactNode;
|
|
3386
3406
|
}
|
|
3387
3407
|
|
|
3388
3408
|
/** Alias of the shared {@link Option} type (kept for backward-compatible imports). */
|
|
@@ -3761,6 +3781,9 @@ interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement
|
|
|
3761
3781
|
maxRows?: number;
|
|
3762
3782
|
/** With `maxLength`, render a live `current / max` character counter; danger-toned near the limit. @default false */
|
|
3763
3783
|
showCount?: boolean;
|
|
3784
|
+
/** #328: show a trailing clear (X) button (top-inline-end, clear of the resize handle) when non-empty;
|
|
3785
|
+
* clicking it empties the field and fires `onChange` with the empty value. @default false */
|
|
3786
|
+
clearable?: boolean;
|
|
3764
3787
|
}
|
|
3765
3788
|
|
|
3766
3789
|
/** Forwards `ref` to the inner `<textarea>`. */
|
package/dist/index.mjs
CHANGED
|
@@ -5650,6 +5650,10 @@ var COMBO_CSS = `
|
|
|
5650
5650
|
.twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
|
|
5651
5651
|
.twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
5652
5652
|
.twc-opt__desc { font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
5653
|
+
/* #326: optional leading icon/swatch + trailing (right-aligned) hint on an option. */
|
|
5654
|
+
.twc-opt__icon { flex: none; display: inline-flex; align-items: center; color: var(--color-text-muted); }
|
|
5655
|
+
.twc-opt__icon svg { width: 16px; height: 16px; }
|
|
5656
|
+
.twc-opt__hint { flex: none; margin-inline-start: auto; padding-inline-start: var(--space-2); color: var(--color-text-muted); font-size: var(--text-xs); white-space: nowrap; }
|
|
5653
5657
|
/* #300: wrapOptions \u2014 let long labels/descriptions wrap onto multiple lines instead of truncating.
|
|
5654
5658
|
overflow-wrap: anywhere also breaks a single very long token so it can't overflow the popover edge. */
|
|
5655
5659
|
.twc-opt[data-wrap="true"] { align-items: flex-start; }
|
|
@@ -5717,6 +5721,7 @@ function Combobox({
|
|
|
5717
5721
|
virtualized: virtualizedProp = false,
|
|
5718
5722
|
overscan = 8,
|
|
5719
5723
|
wrapOptions = false,
|
|
5724
|
+
renderOption,
|
|
5720
5725
|
id,
|
|
5721
5726
|
className = "",
|
|
5722
5727
|
onFocus,
|
|
@@ -5724,8 +5729,8 @@ function Combobox({
|
|
|
5724
5729
|
...rest
|
|
5725
5730
|
}) {
|
|
5726
5731
|
const __twcStyles = useScopedStyles("twc-combo-styles", COMBO_CSS);
|
|
5727
|
-
if (virtualizedProp && wrapOptions) warnOnce("combobox-
|
|
5728
|
-
const virtualized = virtualizedProp && !wrapOptions;
|
|
5732
|
+
if (virtualizedProp && (wrapOptions || renderOption)) warnOnce("combobox-var-height-virtualized", "twico-ui Combobox: `wrapOptions`/`renderOption` disable `virtualized` \u2014 those rows aren't a fixed height.");
|
|
5733
|
+
const virtualized = virtualizedProp && !wrapOptions && !renderOption;
|
|
5729
5734
|
const groups = React51__default.useMemo(() => normalizeGroups(options), [options]);
|
|
5730
5735
|
const flat = React51__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
|
|
5731
5736
|
const autoId = React51__default.useId();
|
|
@@ -5896,7 +5901,7 @@ function Combobox({
|
|
|
5896
5901
|
const activeId = open && visible[active] ? optionId(active) : void 0;
|
|
5897
5902
|
const descId = `${fieldId}-desc`;
|
|
5898
5903
|
const describedBy = error || hint ? descId : void 0;
|
|
5899
|
-
const
|
|
5904
|
+
const renderRow = (o, idx) => {
|
|
5900
5905
|
const isSel = o.value === current;
|
|
5901
5906
|
return /* @__PURE__ */ jsxs(
|
|
5902
5907
|
"button",
|
|
@@ -5919,9 +5924,13 @@ function Combobox({
|
|
|
5919
5924
|
onMouseDown: (e) => e.preventDefault(),
|
|
5920
5925
|
onClick: () => commit(o.value),
|
|
5921
5926
|
children: [
|
|
5922
|
-
/* @__PURE__ */
|
|
5923
|
-
/* @__PURE__ */ jsx("span", { className: "twc-
|
|
5924
|
-
|
|
5927
|
+
renderOption ? /* @__PURE__ */ jsx("span", { className: "twc-opt__main", children: renderOption(o, { selected: isSel, active: idx === active }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5928
|
+
o.icon != null ? /* @__PURE__ */ jsx("span", { className: "twc-opt__icon", "aria-hidden": "true", children: o.icon }) : null,
|
|
5929
|
+
/* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
|
|
5930
|
+
/* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
|
|
5931
|
+
o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
|
|
5932
|
+
] }),
|
|
5933
|
+
o.hint != null ? /* @__PURE__ */ jsx("span", { className: "twc-opt__hint", children: o.hint }) : null
|
|
5925
5934
|
] }),
|
|
5926
5935
|
isSel ? /* @__PURE__ */ jsx("span", { className: "twc-opt__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }) : null
|
|
5927
5936
|
]
|
|
@@ -5943,14 +5952,14 @@ function Combobox({
|
|
|
5943
5952
|
"Loading\u2026"
|
|
5944
5953
|
] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : virtualized ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5945
5954
|
vTop > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vTop } }) : null,
|
|
5946
|
-
vShown.map((r2) => r2.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r2.label }, `g${r2.gi}`) :
|
|
5955
|
+
vShown.map((r2) => r2.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r2.label }, `g${r2.gi}`) : renderRow(r2.o, r2.idx)),
|
|
5947
5956
|
vBottom > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vBottom } }) : null
|
|
5948
5957
|
] }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React51__default.Fragment, { children: [
|
|
5949
5958
|
g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
|
|
5950
5959
|
g.options.map((o) => {
|
|
5951
5960
|
counter += 1;
|
|
5952
5961
|
const idx = counter;
|
|
5953
|
-
return
|
|
5962
|
+
return renderRow(o, idx);
|
|
5954
5963
|
})
|
|
5955
5964
|
] }, gi)) });
|
|
5956
5965
|
const RD = { createPortal: typeof createPortal === "function" ? createPortal : typeof window !== "undefined" && window.ReactDOM && window.ReactDOM.createPortal };
|
|
@@ -6487,6 +6496,10 @@ var SELECT_CSS = `
|
|
|
6487
6496
|
.twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
|
|
6488
6497
|
.twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
6489
6498
|
.twc-opt__desc { font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
6499
|
+
/* #326: optional leading icon/swatch + trailing (right-aligned) hint on an option. */
|
|
6500
|
+
.twc-opt__icon { flex: none; display: inline-flex; align-items: center; color: var(--color-text-muted); }
|
|
6501
|
+
.twc-opt__icon svg { width: 16px; height: 16px; }
|
|
6502
|
+
.twc-opt__hint { flex: none; margin-inline-start: auto; padding-inline-start: var(--space-2); color: var(--color-text-muted); font-size: var(--text-xs); white-space: nowrap; }
|
|
6490
6503
|
.twc-opt__check { flex: none; color: var(--color-primary); display: inline-flex; }
|
|
6491
6504
|
.twc-opt__check svg { width: 16px; height: 16px; }
|
|
6492
6505
|
.twc-pop__empty { padding: 14px 12px; text-align: center; font-size: var(--text-sm); color: var(--color-text-subtle); }
|
|
@@ -6547,8 +6560,9 @@ function Select({
|
|
|
6547
6560
|
loading = false,
|
|
6548
6561
|
emptyText = "No results found",
|
|
6549
6562
|
name,
|
|
6550
|
-
virtualized = false,
|
|
6563
|
+
virtualized: virtualizedProp = false,
|
|
6551
6564
|
overscan = 8,
|
|
6565
|
+
renderOption,
|
|
6552
6566
|
id,
|
|
6553
6567
|
className = "",
|
|
6554
6568
|
onClick,
|
|
@@ -6556,6 +6570,8 @@ function Select({
|
|
|
6556
6570
|
...rest
|
|
6557
6571
|
}) {
|
|
6558
6572
|
const __twcStyles = useScopedStyles("twc-select-styles", SELECT_CSS);
|
|
6573
|
+
if (virtualizedProp && renderOption) warnOnce("select-renderoption-virtualized", "twico-ui Select: `renderOption` disables `virtualized` \u2014 custom rows aren't a fixed height.");
|
|
6574
|
+
const virtualized = virtualizedProp && !renderOption;
|
|
6559
6575
|
const bufferRef = React51__default.useRef("");
|
|
6560
6576
|
const bufferTimerRef = React51__default.useRef(null);
|
|
6561
6577
|
const groups = React51__default.useMemo(() => normalizeGroups2(options), [options]);
|
|
@@ -6761,7 +6777,7 @@ function Select({
|
|
|
6761
6777
|
const activeId = open && visible[active] ? optionId(active) : void 0;
|
|
6762
6778
|
const descId = `${fieldId}-desc`;
|
|
6763
6779
|
const describedBy = error || hint ? descId : void 0;
|
|
6764
|
-
const
|
|
6780
|
+
const renderRow = (o, idx) => {
|
|
6765
6781
|
const isSel = o.value === current;
|
|
6766
6782
|
return /* @__PURE__ */ jsxs(
|
|
6767
6783
|
"button",
|
|
@@ -6783,9 +6799,13 @@ function Select({
|
|
|
6783
6799
|
},
|
|
6784
6800
|
onClick: () => commit(o.value),
|
|
6785
6801
|
children: [
|
|
6786
|
-
/* @__PURE__ */
|
|
6787
|
-
/* @__PURE__ */ jsx("span", { className: "twc-
|
|
6788
|
-
|
|
6802
|
+
renderOption ? /* @__PURE__ */ jsx("span", { className: "twc-opt__main", children: renderOption(o, { selected: isSel, active: idx === active }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6803
|
+
o.icon != null ? /* @__PURE__ */ jsx("span", { className: "twc-opt__icon", "aria-hidden": "true", children: o.icon }) : null,
|
|
6804
|
+
/* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
|
|
6805
|
+
/* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
|
|
6806
|
+
o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
|
|
6807
|
+
] }),
|
|
6808
|
+
o.hint != null ? /* @__PURE__ */ jsx("span", { className: "twc-opt__hint", children: o.hint }) : null
|
|
6789
6809
|
] }),
|
|
6790
6810
|
isSel ? /* @__PURE__ */ jsx("span", { className: "twc-opt__check", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }) : null
|
|
6791
6811
|
]
|
|
@@ -6833,14 +6853,14 @@ function Select({
|
|
|
6833
6853
|
"Loading\u2026"
|
|
6834
6854
|
] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : virtualized ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6835
6855
|
vTop > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vTop } }) : null,
|
|
6836
|
-
vShown.map((r2) => r2.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r2.label }, `g${r2.gi}`) :
|
|
6856
|
+
vShown.map((r2) => r2.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r2.label }, `g${r2.gi}`) : renderRow(r2.o, r2.idx)),
|
|
6837
6857
|
vBottom > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vBottom } }) : null
|
|
6838
6858
|
] }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React51__default.Fragment, { children: [
|
|
6839
6859
|
g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
|
|
6840
6860
|
g.options.map((o) => {
|
|
6841
6861
|
counter += 1;
|
|
6842
6862
|
const idx = counter;
|
|
6843
|
-
return
|
|
6863
|
+
return renderRow(o, idx);
|
|
6844
6864
|
})
|
|
6845
6865
|
] }, gi)) }),
|
|
6846
6866
|
/* @__PURE__ */ jsx("div", { className: "twc-sel__sr", role: "status", "aria-live": "polite", children: loading ? "Loading\u2026" : visible.length === 0 ? emptyText : `${visible.length} result${visible.length === 1 ? "" : "s"}` })
|
|
@@ -7144,6 +7164,11 @@ var INPUT_EXTRA_CSS = `
|
|
|
7144
7164
|
.twc-input__reveal:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
7145
7165
|
.twc-input__reveal:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
7146
7166
|
.twc-input__reveal svg { width: 17px; height: 17px; }
|
|
7167
|
+
/* #328: trailing clear (X) button \u2014 mirrors the reveal toggle; sits alongside rightIcon / the password eye. */
|
|
7168
|
+
.twc-input__clear { display: inline-grid; place-items: center; width: 24px; height: 24px; padding: 0; border: none; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-sm); flex: none; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
|
|
7169
|
+
.twc-input__clear:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
7170
|
+
.twc-input__clear:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
7171
|
+
.twc-input__clear svg { width: 15px; height: 15px; }
|
|
7147
7172
|
.twc-input__addon { align-self: stretch; display: inline-flex; align-items: center; padding-inline: var(--space-3);
|
|
7148
7173
|
background: var(--color-surface-sunken); color: var(--color-text-muted); font-size: var(--text-sm);
|
|
7149
7174
|
font-weight: var(--font-semibold); white-space: nowrap; flex: none; }
|
|
@@ -7165,6 +7190,7 @@ function Input({
|
|
|
7165
7190
|
leftAddon,
|
|
7166
7191
|
rightAddon,
|
|
7167
7192
|
showCount = false,
|
|
7193
|
+
clearable = false,
|
|
7168
7194
|
type = "text",
|
|
7169
7195
|
disabled = false,
|
|
7170
7196
|
id,
|
|
@@ -7186,8 +7212,25 @@ function Input({
|
|
|
7186
7212
|
const near = showCounter && count >= Math.floor(max * 0.9);
|
|
7187
7213
|
const handleChange = (e) => {
|
|
7188
7214
|
rest.onChange?.(e);
|
|
7189
|
-
if (showCount && !countControlled) setLen(e.target.value.length);
|
|
7215
|
+
if ((showCount || clearable) && !countControlled) setLen(e.target.value.length);
|
|
7190
7216
|
};
|
|
7217
|
+
const inputRef = React51__default.useRef(null);
|
|
7218
|
+
const userRef = rest.ref;
|
|
7219
|
+
const setRef = React51__default.useCallback((node) => {
|
|
7220
|
+
inputRef.current = node;
|
|
7221
|
+
if (typeof userRef === "function") userRef(node);
|
|
7222
|
+
else if (userRef && typeof userRef === "object") userRef.current = node;
|
|
7223
|
+
}, [userRef]);
|
|
7224
|
+
const clearField = () => {
|
|
7225
|
+
const el = inputRef.current;
|
|
7226
|
+
if (!el) return;
|
|
7227
|
+
const setter = typeof HTMLInputElement !== "undefined" && Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
7228
|
+
if (setter) setter.call(el, "");
|
|
7229
|
+
else el.value = "";
|
|
7230
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
7231
|
+
el.focus();
|
|
7232
|
+
};
|
|
7233
|
+
const showClear = clearable && count > 0 && !disabled && !rest.readOnly;
|
|
7191
7234
|
const ariaInvalid = invalid ? true : rest["aria-invalid"] ?? void 0;
|
|
7192
7235
|
const describedBy = [error || hint ? descId : null, showCounter ? countId : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
|
|
7193
7236
|
const isPassword = type === "password";
|
|
@@ -7234,11 +7277,16 @@ function Input({
|
|
|
7234
7277
|
required: required || void 0,
|
|
7235
7278
|
"aria-required": required || void 0,
|
|
7236
7279
|
...rest,
|
|
7280
|
+
ref: setRef,
|
|
7237
7281
|
onChange: handleChange,
|
|
7238
7282
|
"aria-invalid": ariaInvalid,
|
|
7239
7283
|
"aria-describedby": describedBy
|
|
7240
7284
|
}
|
|
7241
7285
|
),
|
|
7286
|
+
showClear ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-input__clear", "aria-label": "Clear", tabIndex: 0, onMouseDown: (e) => e.preventDefault(), onClick: clearField, children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
7287
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
7288
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
7289
|
+
] }) }) : null,
|
|
7242
7290
|
suffix,
|
|
7243
7291
|
rightAddon != null ? /* @__PURE__ */ jsx("span", { className: "twc-input__addon twc-input__addon--end", children: rightAddon }) : null
|
|
7244
7292
|
] }),
|
|
@@ -7326,6 +7374,10 @@ var MULTI_CSS = `
|
|
|
7326
7374
|
.twc-opt__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
|
|
7327
7375
|
.twc-opt__label { line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
7328
7376
|
.twc-opt__desc { font-size: var(--text-xs); color: var(--color-text-muted); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
7377
|
+
/* #326: optional leading icon/swatch + trailing (right-aligned) hint on an option. */
|
|
7378
|
+
.twc-opt__icon { flex: none; display: inline-flex; align-items: center; color: var(--color-text-muted); }
|
|
7379
|
+
.twc-opt__icon svg { width: 16px; height: 16px; }
|
|
7380
|
+
.twc-opt__hint { flex: none; margin-inline-start: auto; padding-inline-start: var(--space-2); color: var(--color-text-muted); font-size: var(--text-xs); white-space: nowrap; }
|
|
7329
7381
|
.twc-pop__empty { padding: 14px 12px; text-align: center; font-size: var(--text-sm); color: var(--color-text-subtle); }
|
|
7330
7382
|
.twc-opt[data-disabled="true"] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
|
|
7331
7383
|
.twc-pop__loading { display: flex; align-items: center; justify-content: center; gap: var(--space-2); padding: 14px 12px; font-size: var(--text-sm); color: var(--color-text-muted); }
|
|
@@ -7387,8 +7439,9 @@ function MultiSelect({
|
|
|
7387
7439
|
maxTagCount,
|
|
7388
7440
|
filter,
|
|
7389
7441
|
onInputChange,
|
|
7390
|
-
virtualized = false,
|
|
7442
|
+
virtualized: virtualizedProp = false,
|
|
7391
7443
|
overscan = 8,
|
|
7444
|
+
renderOption,
|
|
7392
7445
|
id,
|
|
7393
7446
|
className = "",
|
|
7394
7447
|
onFocus,
|
|
@@ -7396,6 +7449,8 @@ function MultiSelect({
|
|
|
7396
7449
|
...rest
|
|
7397
7450
|
}) {
|
|
7398
7451
|
const __twcStyles = useScopedStyles("twc-ms-styles", MULTI_CSS);
|
|
7452
|
+
if (virtualizedProp && renderOption) warnOnce("multiselect-renderoption-virtualized", "twico-ui MultiSelect: `renderOption` disables `virtualized` \u2014 custom rows aren't a fixed height.");
|
|
7453
|
+
const virtualized = virtualizedProp && !renderOption;
|
|
7399
7454
|
const groups = React51__default.useMemo(() => normalizeGroups3(options), [options]);
|
|
7400
7455
|
const flat = React51__default.useMemo(() => groups.flatMap((g) => g.options), [groups]);
|
|
7401
7456
|
const autoId = React51__default.useId();
|
|
@@ -7555,7 +7610,7 @@ function MultiSelect({
|
|
|
7555
7610
|
const activeId = open && visible[active] ? optionId(active) : void 0;
|
|
7556
7611
|
const descId = `${fieldId}-desc`;
|
|
7557
7612
|
const describedBy = error || hint ? descId : void 0;
|
|
7558
|
-
const
|
|
7613
|
+
const renderRow = (o, idx) => {
|
|
7559
7614
|
const isSel = selected.includes(o.value);
|
|
7560
7615
|
const optDisabled = isOptDisabled(o);
|
|
7561
7616
|
return /* @__PURE__ */ jsxs(
|
|
@@ -7579,9 +7634,13 @@ function MultiSelect({
|
|
|
7579
7634
|
onClick: () => toggle(o.value),
|
|
7580
7635
|
children: [
|
|
7581
7636
|
/* @__PURE__ */ jsx("span", { className: "twc-opt__box", "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) }) }),
|
|
7582
|
-
/* @__PURE__ */
|
|
7583
|
-
/* @__PURE__ */ jsx("span", { className: "twc-
|
|
7584
|
-
|
|
7637
|
+
renderOption ? /* @__PURE__ */ jsx("span", { className: "twc-opt__main", children: renderOption(o, { selected: isSel, active: idx === active }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7638
|
+
o.icon != null ? /* @__PURE__ */ jsx("span", { className: "twc-opt__icon", "aria-hidden": "true", children: o.icon }) : null,
|
|
7639
|
+
/* @__PURE__ */ jsxs("span", { className: "twc-opt__main", children: [
|
|
7640
|
+
/* @__PURE__ */ jsx("span", { className: "twc-opt__label", children: o.label }),
|
|
7641
|
+
o.description ? /* @__PURE__ */ jsx("span", { className: "twc-opt__desc", children: o.description }) : null
|
|
7642
|
+
] }),
|
|
7643
|
+
o.hint != null ? /* @__PURE__ */ jsx("span", { className: "twc-opt__hint", children: o.hint }) : null
|
|
7585
7644
|
] })
|
|
7586
7645
|
]
|
|
7587
7646
|
},
|
|
@@ -7611,14 +7670,14 @@ function MultiSelect({
|
|
|
7611
7670
|
"Loading\u2026"
|
|
7612
7671
|
] }) : visible.length === 0 ? /* @__PURE__ */ jsx("div", { className: "twc-pop__empty", children: emptyText }) : virtualized ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7613
7672
|
vTop > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vTop } }) : null,
|
|
7614
|
-
vShown.map((r2) => r2.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r2.label }, `g${r2.gi}`) :
|
|
7673
|
+
vShown.map((r2) => r2.kind === "group" ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: r2.label }, `g${r2.gi}`) : renderRow(r2.o, r2.idx)),
|
|
7615
7674
|
vBottom > 0 ? /* @__PURE__ */ jsx("div", { "aria-hidden": "true", style: { height: vBottom } }) : null
|
|
7616
7675
|
] }) : fGroups.map((g, gi) => /* @__PURE__ */ jsxs(React51__default.Fragment, { children: [
|
|
7617
7676
|
g.group ? /* @__PURE__ */ jsx("div", { className: "twc-pop__group", children: g.group }) : null,
|
|
7618
7677
|
g.options.map((o) => {
|
|
7619
7678
|
counter += 1;
|
|
7620
7679
|
const idx = counter;
|
|
7621
|
-
return
|
|
7680
|
+
return renderRow(o, idx);
|
|
7622
7681
|
})
|
|
7623
7682
|
] }, gi))
|
|
7624
7683
|
}
|
|
@@ -8202,6 +8261,11 @@ var DT_CSS = `
|
|
|
8202
8261
|
font-size: var(--text-sm); color: var(--color-text); width: 150px; }
|
|
8203
8262
|
.twc-dt__search input:focus, .twc-dt__search input:focus-visible { outline: none; box-shadow: none; }
|
|
8204
8263
|
.twc-dt__search input::placeholder { color: var(--color-text-subtle); }
|
|
8264
|
+
/* #327: trailing clear (X) for the built-in search inputs (quick-search + column-menu search). */
|
|
8265
|
+
.twc-dt__search-clear { border: none; background: transparent; color: var(--color-text-subtle); cursor: pointer; display: inline-grid; place-items: center; width: 20px; height: 20px; padding: 0; border-radius: var(--radius-sm); flex: none; }
|
|
8266
|
+
.twc-dt__search-clear:hover { color: var(--color-text); background: var(--color-surface-sunken); }
|
|
8267
|
+
.twc-dt__search-clear:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
8268
|
+
.twc-dt__search-clear svg { width: 14px; height: 14px; }
|
|
8205
8269
|
.twc-dt__tlabel { display: inline; }
|
|
8206
8270
|
/* Narrow grid: collapse the toolbar to icon-only buttons (labels survive as
|
|
8207
8271
|
hover tooltips via data-tip) and let the search flex so nothing wraps. */
|
|
@@ -9570,6 +9634,8 @@ function Datatable({
|
|
|
9570
9634
|
const colMenuRef = React51__default.useRef(null);
|
|
9571
9635
|
const rowMenuRef = React51__default.useRef(null);
|
|
9572
9636
|
const exportMenuRef = React51__default.useRef(null);
|
|
9637
|
+
const quickSearchRef = React51__default.useRef(null);
|
|
9638
|
+
const colSearchRef = React51__default.useRef(null);
|
|
9573
9639
|
function focusFirstItem(container) {
|
|
9574
9640
|
if (!container) return;
|
|
9575
9641
|
const first = container.querySelector('[role="menuitem"]:not([disabled])');
|
|
@@ -11584,7 +11650,11 @@ function Datatable({
|
|
|
11584
11650
|
] }) : null,
|
|
11585
11651
|
searchable ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__search", children: [
|
|
11586
11652
|
/* @__PURE__ */ jsx(Svg, { d: I.search }),
|
|
11587
|
-
/* @__PURE__ */ jsx("input", { placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) => commitQuick(e.target.value) })
|
|
11653
|
+
/* @__PURE__ */ jsx("input", { ref: quickSearchRef, placeholder: "Search\u2026", "aria-label": "Search rows", value: quick, onChange: (e) => commitQuick(e.target.value) }),
|
|
11654
|
+
quick ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__search-clear", "aria-label": "Clear search", onMouseDown: (e) => e.preventDefault(), onClick: () => {
|
|
11655
|
+
commitQuick("");
|
|
11656
|
+
quickSearchRef.current?.focus();
|
|
11657
|
+
}, children: /* @__PURE__ */ jsx(Svg, { d: I.x }) }) : null
|
|
11588
11658
|
] }) : null
|
|
11589
11659
|
] }),
|
|
11590
11660
|
!pivotActive && activeGroupBy.length ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__groupbar", children: [
|
|
@@ -12177,7 +12247,11 @@ function Datatable({
|
|
|
12177
12247
|
] }),
|
|
12178
12248
|
/* @__PURE__ */ jsxs("div", { className: "twc-dt__col-search", children: [
|
|
12179
12249
|
/* @__PURE__ */ jsx(Svg, { d: I.search }),
|
|
12180
|
-
/* @__PURE__ */ jsx("input", { autoFocus: true, placeholder: "Find column\u2026", "aria-label": "Find column", value: colQuery, onChange: (e) => setColQuery(e.target.value) })
|
|
12250
|
+
/* @__PURE__ */ jsx("input", { ref: colSearchRef, autoFocus: true, placeholder: "Find column\u2026", "aria-label": "Find column", value: colQuery, onChange: (e) => setColQuery(e.target.value) }),
|
|
12251
|
+
colQuery ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-dt__search-clear", "aria-label": "Clear column search", onMouseDown: (e) => e.preventDefault(), onClick: () => {
|
|
12252
|
+
setColQuery("");
|
|
12253
|
+
colSearchRef.current?.focus();
|
|
12254
|
+
}, children: /* @__PURE__ */ jsx(Svg, { d: I.x }) }) : null
|
|
12181
12255
|
] }),
|
|
12182
12256
|
/* @__PURE__ */ jsxs("div", { className: "twc-dt__col-list", children: [
|
|
12183
12257
|
rowNumMatch ? /* @__PURE__ */ jsxs("div", { className: "twc-dt__col-row", onClick: () => setShowRowNum((v) => !v), children: [
|
|
@@ -12547,6 +12621,7 @@ function Datatable({
|
|
|
12547
12621
|
Input,
|
|
12548
12622
|
{
|
|
12549
12623
|
size: "sm",
|
|
12624
|
+
clearable: true,
|
|
12550
12625
|
type: filterTypeOf(col) === "number" ? "number" : "text",
|
|
12551
12626
|
placeholder: "Value",
|
|
12552
12627
|
value: f.value,
|
|
@@ -17635,6 +17710,12 @@ var TEXTAREA_CSS = `
|
|
|
17635
17710
|
.twc-textarea__el:disabled { background: var(--color-surface-sunken); opacity: 0.7; cursor: not-allowed; }
|
|
17636
17711
|
.twc-textarea__el[data-readonly] { background: var(--color-surface-sunken); }
|
|
17637
17712
|
.twc-textarea__el[data-autosize="true"] { resize: none; overflow: hidden; }
|
|
17713
|
+
/* #328: clearable (X). Wrap positions the button top-inline-end so it dodges the bottom-right resize handle. */
|
|
17714
|
+
.twc-textarea__wrap { position: relative; display: block; }
|
|
17715
|
+
.twc-textarea__clear { position: absolute; top: 6px; inset-inline-end: 8px; display: inline-grid; place-items: center; width: 22px; height: 22px; padding: 0; border: none; background: var(--color-surface); color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-sm); transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
|
|
17716
|
+
.twc-textarea__clear:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
17717
|
+
.twc-textarea__clear:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
17718
|
+
.twc-textarea__clear svg { width: 15px; height: 15px; }
|
|
17638
17719
|
.twc-field__footer { display: flex; align-items: center; gap: var(--space-2); }
|
|
17639
17720
|
.twc-field__count { margin-inline-start: auto; font-size: var(--text-xs); color: var(--color-text-muted); font-variant-numeric: tabular-nums; flex: none; }
|
|
17640
17721
|
.twc-field__count[data-danger="true"] { color: var(--color-danger-subtle-fg); }
|
|
@@ -17651,6 +17732,7 @@ var Textarea = React51__default.forwardRef(function Textarea2({
|
|
|
17651
17732
|
minRows,
|
|
17652
17733
|
maxRows,
|
|
17653
17734
|
showCount = false,
|
|
17735
|
+
clearable = false,
|
|
17654
17736
|
disabled = false,
|
|
17655
17737
|
id,
|
|
17656
17738
|
className = "",
|
|
@@ -17697,8 +17779,18 @@ var Textarea = React51__default.forwardRef(function Textarea2({
|
|
|
17697
17779
|
};
|
|
17698
17780
|
const handleChange = (e) => {
|
|
17699
17781
|
rest.onChange?.(e);
|
|
17700
|
-
if (showCount && !countControlled) setLen(e.target.value.length);
|
|
17782
|
+
if ((showCount || clearable) && !countControlled) setLen(e.target.value.length);
|
|
17783
|
+
};
|
|
17784
|
+
const clearField = () => {
|
|
17785
|
+
const el = innerRef.current;
|
|
17786
|
+
if (!el) return;
|
|
17787
|
+
const setter = typeof HTMLTextAreaElement !== "undefined" && Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
|
|
17788
|
+
if (setter) setter.call(el, "");
|
|
17789
|
+
else el.value = "";
|
|
17790
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
17791
|
+
el.focus();
|
|
17701
17792
|
};
|
|
17793
|
+
const showClear = clearable && count > 0 && !disabled && !rest.readOnly;
|
|
17702
17794
|
const ariaInvalid = invalid ? true : rest["aria-invalid"] ?? void 0;
|
|
17703
17795
|
const describedBy = [error || hint ? descId : null, showCounter ? countId : null, rest["aria-describedby"]].filter(Boolean).join(" ") || void 0;
|
|
17704
17796
|
return /* @__PURE__ */ jsxs("div", { className: `twc-field ${className}`, children: [
|
|
@@ -17707,27 +17799,33 @@ var Textarea = React51__default.forwardRef(function Textarea2({
|
|
|
17707
17799
|
label,
|
|
17708
17800
|
required ? /* @__PURE__ */ jsx("span", { className: "twc-field__req", children: "*" }) : null
|
|
17709
17801
|
] }) : null,
|
|
17710
|
-
/* @__PURE__ */
|
|
17711
|
-
|
|
17712
|
-
|
|
17713
|
-
|
|
17714
|
-
|
|
17715
|
-
|
|
17716
|
-
|
|
17717
|
-
|
|
17718
|
-
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
|
|
17723
|
-
|
|
17724
|
-
|
|
17725
|
-
|
|
17726
|
-
|
|
17727
|
-
|
|
17728
|
-
|
|
17729
|
-
|
|
17730
|
-
|
|
17802
|
+
/* @__PURE__ */ jsxs("div", { className: "twc-textarea__wrap", children: [
|
|
17803
|
+
/* @__PURE__ */ jsx(
|
|
17804
|
+
"textarea",
|
|
17805
|
+
{
|
|
17806
|
+
ref: setRef,
|
|
17807
|
+
id: fieldId,
|
|
17808
|
+
className: "twc-textarea__el",
|
|
17809
|
+
"data-size": size,
|
|
17810
|
+
"data-tone": tone,
|
|
17811
|
+
"data-autosize": autosize || void 0,
|
|
17812
|
+
"data-readonly": rest.readOnly || void 0,
|
|
17813
|
+
rows: autosize ? minRows ?? rows : rows,
|
|
17814
|
+
disabled,
|
|
17815
|
+
required: required || void 0,
|
|
17816
|
+
"aria-required": required || void 0,
|
|
17817
|
+
...rest,
|
|
17818
|
+
onInput: handleInput,
|
|
17819
|
+
onChange: handleChange,
|
|
17820
|
+
"aria-invalid": ariaInvalid,
|
|
17821
|
+
"aria-describedby": describedBy
|
|
17822
|
+
}
|
|
17823
|
+
),
|
|
17824
|
+
showClear ? /* @__PURE__ */ jsx("button", { type: "button", className: "twc-textarea__clear", "aria-label": "Clear", tabIndex: 0, onMouseDown: (e) => e.preventDefault(), onClick: clearField, children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
17825
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
17826
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
17827
|
+
] }) }) : null
|
|
17828
|
+
] }),
|
|
17731
17829
|
error || hint || showCounter ? /* @__PURE__ */ jsxs("div", { className: "twc-field__footer", children: [
|
|
17732
17830
|
error ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null,
|
|
17733
17831
|
showCounter ? /* @__PURE__ */ jsxs("span", { id: countId, className: "twc-field__count", "data-danger": near || void 0, "aria-live": "polite", children: [
|