@viax.io/uxm 4.39.0 → 4.40.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +33 -44
  4. package/dist/hooks/index.cjs.map +1 -1
  5. package/dist/hooks/index.d.ts +1 -1
  6. package/dist/hooks/index.js.map +1 -1
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/previews/index.cjs.map +1 -1
  11. package/dist/previews/index.d.ts +2 -2
  12. package/dist/previews/index.js.map +1 -1
  13. package/dist/studio/index.cjs.map +1 -1
  14. package/dist/studio/index.d.ts +2 -2
  15. package/dist/studio/index.js.map +1 -1
  16. package/dist/studio/lib/registry/buttons.cjs +2 -2
  17. package/dist/studio/lib/registry/buttons.cjs.map +1 -1
  18. package/dist/studio/lib/registry/buttons.js +2 -2
  19. package/dist/studio/lib/registry/buttons.js.map +1 -1
  20. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.cjs +1 -1
  21. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.cjs.map +1 -1
  22. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.js +1 -1
  23. package/dist/studio/lib/registry/composite/sidebar-nav-trigger.js.map +1 -1
  24. package/dist/studio/lib/registry/diagram.cjs +1 -1
  25. package/dist/studio/lib/registry/diagram.cjs.map +1 -1
  26. package/dist/studio/lib/registry/diagram.js +1 -1
  27. package/dist/studio/lib/registry/diagram.js.map +1 -1
  28. package/dist/studio/lib/registry/display.cjs +2 -2
  29. package/dist/studio/lib/registry/display.cjs.map +1 -1
  30. package/dist/studio/lib/registry/display.js +2 -2
  31. package/dist/studio/lib/registry/display.js.map +1 -1
  32. package/dist/studio/lib/registry/feedback.cjs +3 -3
  33. package/dist/studio/lib/registry/feedback.cjs.map +1 -1
  34. package/dist/studio/lib/registry/feedback.js +3 -3
  35. package/dist/studio/lib/registry/feedback.js.map +1 -1
  36. package/dist/studio/lib/registry/inputs/color-input.cjs +1 -1
  37. package/dist/studio/lib/registry/inputs/color-input.cjs.map +1 -1
  38. package/dist/studio/lib/registry/inputs/color-input.js +1 -1
  39. package/dist/studio/lib/registry/inputs/color-input.js.map +1 -1
  40. package/dist/studio/lib/registry/inputs/currency-input.cjs +1 -1
  41. package/dist/studio/lib/registry/inputs/currency-input.cjs.map +1 -1
  42. package/dist/studio/lib/registry/inputs/currency-input.js +1 -1
  43. package/dist/studio/lib/registry/inputs/currency-input.js.map +1 -1
  44. package/dist/studio/lib/registry/inputs/editable-cell.cjs +1 -1
  45. package/dist/studio/lib/registry/inputs/editable-cell.cjs.map +1 -1
  46. package/dist/studio/lib/registry/inputs/editable-cell.js +1 -1
  47. package/dist/studio/lib/registry/inputs/editable-cell.js.map +1 -1
  48. package/dist/studio/lib/registry/inputs/file-upload.cjs +1 -1
  49. package/dist/studio/lib/registry/inputs/file-upload.cjs.map +1 -1
  50. package/dist/studio/lib/registry/inputs/file-upload.js +1 -1
  51. package/dist/studio/lib/registry/inputs/file-upload.js.map +1 -1
  52. package/dist/studio/lib/registry/inputs/input-text.cjs +1 -1
  53. package/dist/studio/lib/registry/inputs/input-text.cjs.map +1 -1
  54. package/dist/studio/lib/registry/inputs/input-text.js +1 -1
  55. package/dist/studio/lib/registry/inputs/input-text.js.map +1 -1
  56. package/dist/studio/lib/registry/inputs/listbox.cjs +1 -1
  57. package/dist/studio/lib/registry/inputs/listbox.cjs.map +1 -1
  58. package/dist/studio/lib/registry/inputs/listbox.js +1 -1
  59. package/dist/studio/lib/registry/inputs/listbox.js.map +1 -1
  60. package/dist/studio/lib/registry/inputs/menu.cjs +1 -1
  61. package/dist/studio/lib/registry/inputs/menu.cjs.map +1 -1
  62. package/dist/studio/lib/registry/inputs/menu.js +1 -1
  63. package/dist/studio/lib/registry/inputs/menu.js.map +1 -1
  64. package/dist/studio/lib/registry/inputs/number-input.cjs +1 -1
  65. package/dist/studio/lib/registry/inputs/number-input.cjs.map +1 -1
  66. package/dist/studio/lib/registry/inputs/number-input.js +1 -1
  67. package/dist/studio/lib/registry/inputs/number-input.js.map +1 -1
  68. package/dist/studio/lib/registry/inputs/password-input.cjs +1 -1
  69. package/dist/studio/lib/registry/inputs/password-input.cjs.map +1 -1
  70. package/dist/studio/lib/registry/inputs/password-input.js +1 -1
  71. package/dist/studio/lib/registry/inputs/password-input.js.map +1 -1
  72. package/dist/studio/lib/registry/inputs/phone-input.cjs +1 -1
  73. package/dist/studio/lib/registry/inputs/phone-input.cjs.map +1 -1
  74. package/dist/studio/lib/registry/inputs/phone-input.js +1 -1
  75. package/dist/studio/lib/registry/inputs/phone-input.js.map +1 -1
  76. package/dist/studio/lib/registry/inputs/slider.cjs +1 -1
  77. package/dist/studio/lib/registry/inputs/slider.cjs.map +1 -1
  78. package/dist/studio/lib/registry/inputs/slider.js +1 -1
  79. package/dist/studio/lib/registry/inputs/slider.js.map +1 -1
  80. package/dist/studio/lib/registry/inputs/time-input.cjs +1 -1
  81. package/dist/studio/lib/registry/inputs/time-input.cjs.map +1 -1
  82. package/dist/studio/lib/registry/inputs/time-input.js +1 -1
  83. package/dist/studio/lib/registry/inputs/time-input.js.map +1 -1
  84. package/dist/studio/lib/types.cjs.map +1 -1
  85. package/dist/studio/persistence/generate-css.cjs.map +1 -1
  86. package/dist/studio/persistence/generate-css.js.map +1 -1
  87. package/dist/ui/editable-cell/editable-cell-date.cjs +226 -0
  88. package/dist/ui/editable-cell/editable-cell-date.cjs.map +1 -0
  89. package/dist/ui/editable-cell/editable-cell-date.d.ts +4 -0
  90. package/dist/ui/editable-cell/editable-cell-date.d.ts.map +1 -0
  91. package/dist/ui/editable-cell/editable-cell-date.js +202 -0
  92. package/dist/ui/editable-cell/editable-cell-date.js.map +1 -0
  93. package/dist/ui/editable-cell/editable-cell-select.cjs +297 -0
  94. package/dist/ui/editable-cell/editable-cell-select.cjs.map +1 -0
  95. package/dist/ui/editable-cell/editable-cell-select.d.ts +4 -0
  96. package/dist/ui/editable-cell/editable-cell-select.d.ts.map +1 -0
  97. package/dist/ui/editable-cell/editable-cell-select.js +273 -0
  98. package/dist/ui/editable-cell/editable-cell-select.js.map +1 -0
  99. package/dist/ui/editable-cell/editable-cell-text.cjs +175 -0
  100. package/dist/ui/editable-cell/editable-cell-text.cjs.map +1 -0
  101. package/dist/ui/editable-cell/editable-cell-text.d.ts +4 -0
  102. package/dist/ui/editable-cell/editable-cell-text.d.ts.map +1 -0
  103. package/dist/ui/editable-cell/editable-cell-text.js +151 -0
  104. package/dist/ui/editable-cell/editable-cell-text.js.map +1 -0
  105. package/dist/ui/editable-cell/editable-cell.cjs +27 -705
  106. package/dist/ui/editable-cell/editable-cell.cjs.map +1 -1
  107. package/dist/ui/editable-cell/editable-cell.d.ts +1 -1
  108. package/dist/ui/editable-cell/editable-cell.d.ts.map +1 -1
  109. package/dist/ui/editable-cell/editable-cell.js +28 -706
  110. package/dist/ui/editable-cell/editable-cell.js.map +1 -1
  111. package/dist/ui/editable-cell/use-editable-cell.cjs +284 -0
  112. package/dist/ui/editable-cell/use-editable-cell.cjs.map +1 -0
  113. package/dist/ui/editable-cell/use-editable-cell.d.ts +51 -0
  114. package/dist/ui/editable-cell/use-editable-cell.d.ts.map +1 -0
  115. package/dist/ui/editable-cell/use-editable-cell.js +260 -0
  116. package/dist/ui/editable-cell/use-editable-cell.js.map +1 -0
  117. package/dist/ui/page-shell/page-shell.cjs.map +1 -1
  118. package/dist/ui/page-shell/page-shell.d.ts +1 -1
  119. package/dist/ui/page-shell/page-shell.d.ts.map +1 -1
  120. package/dist/ui/page-shell/page-shell.js.map +1 -1
  121. package/dist/ui/styles.css +1 -1
  122. package/package.json +5 -5
@@ -0,0 +1,273 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../helpers/index.js";
3
+ import { Banner } from "../banner/index.js";
4
+ import { ButtonGhost } from "../button/index.js";
5
+ import { HoverTooltip } from "../hover-tooltip/index.js";
6
+ import { Icon } from "../icon/index.js";
7
+ import { Listbox, MultiListbox } from "../listbox/index.js";
8
+ import { Popover } from "../popover/index.js";
9
+ function EditableCellSelectView({ props, cell }) {
10
+ const {
11
+ value,
12
+ options,
13
+ requiredMessage,
14
+ disabled,
15
+ className,
16
+ style,
17
+ "aria-label": ariaLabel,
18
+ type,
19
+ searchable,
20
+ clearable,
21
+ align,
22
+ size,
23
+ required,
24
+ clearSelectionLabel
25
+ } = props;
26
+ const {
27
+ submitting,
28
+ setError,
29
+ open,
30
+ setOpen,
31
+ wrapRef,
32
+ commitValue,
33
+ isEmpty,
34
+ display,
35
+ titleText,
36
+ shownError
37
+ } = cell;
38
+ if (type === "select" || type === "multiselect") {
39
+ const optionItems = options ?? [];
40
+ const getKey = (o) => o.value;
41
+ const getLabel = (o) => o.label;
42
+ if (type === "select") {
43
+ const selectedItem = Array.isArray(value) ? null : optionItems.find((o) => o.value === String(value ?? "")) ?? null;
44
+ return /* @__PURE__ */ jsxs(
45
+ "span",
46
+ {
47
+ ref: wrapRef,
48
+ className: cn(
49
+ "uxm-editable-cell",
50
+ `uxm-editable-cell--${size}`,
51
+ `uxm-editable-cell--align-${align}`,
52
+ `uxm-editable-cell--type-${type}`,
53
+ clearable && "uxm-editable-cell--clearable",
54
+ disabled && "uxm-editable-cell--disabled",
55
+ isEmpty && "uxm-editable-cell--empty",
56
+ open && "uxm-editable-cell--open",
57
+ className
58
+ ),
59
+ style,
60
+ children: [
61
+ /* @__PURE__ */ jsx(
62
+ Listbox,
63
+ {
64
+ items: optionItems,
65
+ getKey,
66
+ getLabel,
67
+ value: selectedItem,
68
+ onChange: async (next) => {
69
+ if (next) await commitValue(next.value);
70
+ },
71
+ disabled,
72
+ searchable,
73
+ matchAnchorWidth: true,
74
+ onOpenChange: setOpen,
75
+ renderTrigger: ({ open: isOpen, triggerProps }) => /* @__PURE__ */ jsxs(
76
+ "button",
77
+ {
78
+ type: "button",
79
+ ...triggerProps,
80
+ className: cn(
81
+ "uxm-editable-cell__select-trigger",
82
+ isOpen && "uxm-editable-cell__select-trigger--open"
83
+ ),
84
+ "aria-label": ariaLabel ?? `Edit ${String(value ?? "")}`,
85
+ children: [
86
+ /* @__PURE__ */ jsx(HoverTooltip, { content: titleText, disabled, children: /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__value uxm-editable-cell__option-label", children: display }) }),
87
+ /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, { glyph: "chevron-down", size: 12 }) })
88
+ ]
89
+ }
90
+ ),
91
+ renderItem: (o) => /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__option-label", children: o.label }),
92
+ footer: clearable && selectedItem ? ({ close }) => /* @__PURE__ */ jsxs(
93
+ ButtonGhost,
94
+ {
95
+ className: "uxm-listbox__footer-clear-option",
96
+ onClick: () => {
97
+ commitValue("");
98
+ close();
99
+ },
100
+ children: [
101
+ /* @__PURE__ */ jsx(Icon, { glyph: "close", size: 12 }),
102
+ "Clear"
103
+ ]
104
+ }
105
+ ) : void 0
106
+ }
107
+ ),
108
+ clearable && !disabled && !submitting && !isEmpty && /* Trigger ✕ — clear from the field itself (the input-family
109
+ convention), on every size: commits the empty value directly,
110
+ complementing the panel-footer Clear. Sibling of the trigger (a
111
+ button can't nest a button), absolutely positioned into the
112
+ reserved second gutter slot. Revealed only while the panel is
113
+ open (see the `--open` gate in the stylesheet) — unlike the
114
+ chevron, which also shows on hover. */
115
+ /* @__PURE__ */ jsx(
116
+ "button",
117
+ {
118
+ type: "button",
119
+ className: "uxm-editable-cell__trigger-clear",
120
+ tabIndex: -1,
121
+ onMouseDown: (e) => e.stopPropagation(),
122
+ onClick: () => void commitValue(""),
123
+ "aria-label": clearSelectionLabel,
124
+ children: /* @__PURE__ */ jsx(Icon, { glyph: "close", size: 12 })
125
+ }
126
+ ),
127
+ /* @__PURE__ */ jsx(
128
+ Popover,
129
+ {
130
+ open: Boolean(shownError),
131
+ onOpenChange: (next) => {
132
+ if (!next) setError(null);
133
+ },
134
+ anchor: wrapRef,
135
+ placement: "bottom-start",
136
+ closeOnEscape: false,
137
+ closeOnOutsideClick: false,
138
+ restoreFocus: false,
139
+ role: "presentation",
140
+ children: shownError && /* @__PURE__ */ jsx(
141
+ Banner,
142
+ {
143
+ variant: shownError.severity,
144
+ id: "uxm-editable-cell__error",
145
+ className: "uxm-editable-cell__error-banner",
146
+ children: shownError.message
147
+ }
148
+ )
149
+ }
150
+ )
151
+ ]
152
+ }
153
+ );
154
+ }
155
+ const selectedItems = Array.isArray(value) ? optionItems.filter((o) => value.includes(o.value)) : [];
156
+ return /* @__PURE__ */ jsxs(
157
+ "span",
158
+ {
159
+ ref: wrapRef,
160
+ className: cn(
161
+ "uxm-editable-cell",
162
+ `uxm-editable-cell--${size}`,
163
+ `uxm-editable-cell--align-${align}`,
164
+ `uxm-editable-cell--type-${type}`,
165
+ clearable && "uxm-editable-cell--clearable",
166
+ disabled && "uxm-editable-cell--disabled",
167
+ isEmpty && "uxm-editable-cell--empty",
168
+ open && "uxm-editable-cell--open",
169
+ className
170
+ ),
171
+ style,
172
+ children: [
173
+ /* @__PURE__ */ jsx(
174
+ MultiListbox,
175
+ {
176
+ items: optionItems,
177
+ getKey,
178
+ getLabel,
179
+ value: selectedItems,
180
+ onChange: (items) => void commitValue(items.map((o) => o.value)),
181
+ commitMode: "close",
182
+ required,
183
+ requiredMessage,
184
+ onRequiredViolation: (message) => setError({ message, severity: "warning" }),
185
+ disabled,
186
+ searchable,
187
+ matchAnchorWidth: true,
188
+ onOpenChange: (next) => {
189
+ setOpen(next);
190
+ if (next) setError(null);
191
+ },
192
+ renderTrigger: ({ open: isOpen, triggerProps }) => /* @__PURE__ */ jsxs(
193
+ "button",
194
+ {
195
+ type: "button",
196
+ ...triggerProps,
197
+ className: cn(
198
+ "uxm-editable-cell__select-trigger",
199
+ isOpen && "uxm-editable-cell__select-trigger--open"
200
+ ),
201
+ "aria-label": ariaLabel ?? `Edit ${String(value ?? "")}`,
202
+ children: [
203
+ /* @__PURE__ */ jsx(HoverTooltip, { content: titleText, disabled, children: /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__value uxm-editable-cell__option-label", children: display }) }),
204
+ /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, { glyph: "chevron-down", size: 12 }) })
205
+ ]
206
+ }
207
+ ),
208
+ renderItem: (o) => /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__option-label", children: o.label }),
209
+ footer: clearable ? ({ clear, selected }) => selected.length > 0 ? /* @__PURE__ */ jsxs(
210
+ ButtonGhost,
211
+ {
212
+ className: "uxm-listbox__footer-clear-option",
213
+ onClick: clear,
214
+ children: [
215
+ /* @__PURE__ */ jsx(Icon, { glyph: "close", size: 12 }),
216
+ "Clear all"
217
+ ]
218
+ }
219
+ ) : null : void 0
220
+ }
221
+ ),
222
+ clearable && !disabled && !submitting && !isEmpty && /* Trigger ✕ — clear from the field itself (the input-family
223
+ convention), on every size: commits the empty value directly,
224
+ complementing the panel-footer Clear. Sibling of the trigger (a
225
+ button can't nest a button), absolutely positioned into the
226
+ reserved second gutter slot. Revealed only while the panel is
227
+ open (see the `--open` gate in the stylesheet) — unlike the
228
+ chevron, which also shows on hover. */
229
+ /* @__PURE__ */ jsx(
230
+ "button",
231
+ {
232
+ type: "button",
233
+ className: "uxm-editable-cell__trigger-clear",
234
+ tabIndex: -1,
235
+ onMouseDown: (e) => e.stopPropagation(),
236
+ onClick: () => void commitValue([]),
237
+ "aria-label": clearSelectionLabel,
238
+ children: /* @__PURE__ */ jsx(Icon, { glyph: "close", size: 12 })
239
+ }
240
+ ),
241
+ /* @__PURE__ */ jsx(
242
+ Popover,
243
+ {
244
+ open: Boolean(shownError),
245
+ onOpenChange: (next) => {
246
+ if (!next) setError(null);
247
+ },
248
+ anchor: wrapRef,
249
+ placement: "bottom-start",
250
+ closeOnEscape: false,
251
+ closeOnOutsideClick: false,
252
+ restoreFocus: false,
253
+ role: "presentation",
254
+ children: shownError && /* @__PURE__ */ jsx(
255
+ Banner,
256
+ {
257
+ variant: shownError.severity,
258
+ id: "uxm-editable-cell__error",
259
+ className: "uxm-editable-cell__error-banner",
260
+ children: shownError.message
261
+ }
262
+ )
263
+ }
264
+ )
265
+ ]
266
+ }
267
+ );
268
+ }
269
+ }
270
+ export {
271
+ EditableCellSelectView
272
+ };
273
+ //# sourceMappingURL=editable-cell-select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/ui/editable-cell/editable-cell-select.tsx"],"sourcesContent":["import { cn } from '@/helpers';\n\nimport { Banner } from '../banner';\nimport { ButtonGhost } from '../button';\nimport { HoverTooltip } from '../hover-tooltip';\nimport { Icon } from '../icon';\nimport { Listbox, MultiListbox, type ListboxRenderTriggerState } from '../listbox';\nimport { Popover } from '../popover';\n\nimport type { EditableCellOption } from './editable-cell.types';\nimport type { EditableCellViewProps } from './use-editable-cell';\n\n/** `type=\"select\"` / `\"multiselect\"` — a Listbox-driven trigger; no display/edit split. */\nexport function EditableCellSelectView({ props, cell }: EditableCellViewProps) {\n const {\n value,\n options,\n requiredMessage,\n disabled,\n className,\n style,\n 'aria-label': ariaLabel,\n type,\n searchable,\n clearable,\n align,\n size,\n required,\n clearSelectionLabel,\n } = props;\n const {\n submitting,\n setError,\n open,\n setOpen,\n wrapRef,\n commitValue,\n isEmpty,\n display,\n titleText,\n shownError,\n } = cell;\n\n // For select/multiselect in open state, we render a Listbox-driven UI\n if (type === 'select' || type === 'multiselect') {\n const optionItems = options ?? [];\n const getKey = (o: EditableCellOption) => o.value;\n const getLabel = (o: EditableCellOption) => o.label;\n\n if (type === 'select') {\n const selectedItem = Array.isArray(value)\n ? null\n : optionItems.find((o) => o.value === String(value ?? '')) ?? null;\n\n return (\n <span\n ref={wrapRef}\n className={cn(\n 'uxm-editable-cell',\n `uxm-editable-cell--${size}`,\n `uxm-editable-cell--align-${align}`,\n `uxm-editable-cell--type-${type}`,\n clearable && 'uxm-editable-cell--clearable',\n disabled && 'uxm-editable-cell--disabled',\n isEmpty && 'uxm-editable-cell--empty',\n open && 'uxm-editable-cell--open',\n className,\n )}\n style={style}\n >\n <Listbox<EditableCellOption>\n items={optionItems}\n getKey={getKey}\n getLabel={getLabel}\n value={selectedItem}\n onChange={async (next) => {\n if (next) await commitValue(next.value);\n }}\n disabled={disabled}\n searchable={searchable}\n matchAnchorWidth\n onOpenChange={setOpen}\n renderTrigger={({ open: isOpen, triggerProps }: ListboxRenderTriggerState<EditableCellOption>) => (\n <button\n type=\"button\"\n {...triggerProps}\n className={cn(\n 'uxm-editable-cell__select-trigger',\n isOpen && 'uxm-editable-cell__select-trigger--open',\n )}\n aria-label={ariaLabel ?? `Edit ${String(value ?? '')}`}\n >\n <HoverTooltip content={titleText} disabled={disabled}>\n <span className=\"uxm-editable-cell__value uxm-editable-cell__option-label\">\n {display}\n </span>\n </HoverTooltip>\n <span className=\"uxm-editable-cell__chevron\" aria-hidden=\"true\">\n <Icon glyph=\"chevron-down\" size={12} />\n </span>\n </button>\n )}\n renderItem={(o) => (\n <span className=\"uxm-editable-cell__option-label\">{o.label}</span>\n )}\n footer={clearable && selectedItem ? ({ close }: { close: () => void }) => (\n <ButtonGhost\n className=\"uxm-listbox__footer-clear-option\"\n onClick={() => {\n commitValue('');\n close();\n }}\n >\n <Icon glyph=\"close\" size={12} />\n Clear\n </ButtonGhost>\n ) : undefined}\n />\n {clearable && !disabled && !submitting && !isEmpty && (\n /* Trigger ✕ — clear from the field itself (the input-family\n convention), on every size: commits the empty value directly,\n complementing the panel-footer Clear. Sibling of the trigger (a\n button can't nest a button), absolutely positioned into the\n reserved second gutter slot. Revealed only while the panel is\n open (see the `--open` gate in the stylesheet) — unlike the\n chevron, which also shows on hover. */\n <button\n type=\"button\"\n className=\"uxm-editable-cell__trigger-clear\"\n // Out of the tab order, same as every in-field clear here.\n tabIndex={-1}\n // This button is a SIBLING of the Listbox trigger, so it sits\n // outside the refs `useDismiss` treats as \"inside\" — and dismiss\n // runs on mousedown, i.e. BEFORE this click. Left alone, pressing\n // ✕ would first dismiss the panel and only then clear. Stop the\n // mousedown here so the clear below is the single thing that acts.\n onMouseDown={(e) => e.stopPropagation()}\n onClick={() => void commitValue('')}\n aria-label={clearSelectionLabel}\n >\n <Icon glyph=\"close\" size={12} />\n </button>\n )}\n <Popover\n open={Boolean(shownError)}\n onOpenChange={(next) => {\n if (!next) setError(null);\n }}\n anchor={wrapRef}\n placement=\"bottom-start\"\n closeOnEscape={false}\n closeOnOutsideClick={false}\n restoreFocus={false}\n role=\"presentation\"\n >\n {shownError && (\n <Banner\n variant={shownError.severity}\n id=\"uxm-editable-cell__error\"\n className=\"uxm-editable-cell__error-banner\"\n >\n {shownError.message}\n </Banner>\n )}\n </Popover>\n </span>\n );\n }\n\n // multiselect. A cell is a commit boundary, so this branch opts into\n // MultiListbox's staged mode (`commitMode=\"close\"`: draft while open, one\n // commit on close) — a required cell then survives \"clear all → pick one\"\n // and N picks are one `onCommit`. It just hands over the committed\n // selection and commits the final array back.\n const selectedItems = Array.isArray(value)\n ? optionItems.filter((o) => value.includes(o.value))\n : [];\n\n return (\n <span\n ref={wrapRef}\n className={cn(\n 'uxm-editable-cell',\n `uxm-editable-cell--${size}`,\n `uxm-editable-cell--align-${align}`,\n `uxm-editable-cell--type-${type}`,\n clearable && 'uxm-editable-cell--clearable',\n disabled && 'uxm-editable-cell--disabled',\n isEmpty && 'uxm-editable-cell--empty',\n open && 'uxm-editable-cell--open',\n className,\n )}\n style={style}\n >\n <MultiListbox<EditableCellOption>\n items={optionItems}\n getKey={getKey}\n getLabel={getLabel}\n value={selectedItems}\n onChange={(items) => void commitValue(items.map((o) => o.value))}\n // Commit on close, not per toggle — see the note above.\n commitMode=\"close\"\n required={required}\n requiredMessage={requiredMessage}\n // MultiListbox owns the empty rule for multi (shared with every\n // picker); route its violation into this cell's error Banner.\n onRequiredViolation={(message) => setError({ message, severity: 'warning' })}\n disabled={disabled}\n searchable={searchable}\n matchAnchorWidth\n // Clear a stale required warning when the panel reopens for a fresh edit.\n onOpenChange={(next) => {\n setOpen(next);\n if (next) setError(null);\n }}\n renderTrigger={({ open: isOpen, triggerProps }: ListboxRenderTriggerState<EditableCellOption>) => (\n <button\n type=\"button\"\n {...triggerProps}\n className={cn(\n 'uxm-editable-cell__select-trigger',\n isOpen && 'uxm-editable-cell__select-trigger--open',\n )}\n aria-label={ariaLabel ?? `Edit ${String(value ?? '')}`}\n >\n <HoverTooltip content={titleText} disabled={disabled}>\n <span className=\"uxm-editable-cell__value uxm-editable-cell__option-label\">\n {display}\n </span>\n </HoverTooltip>\n <span className=\"uxm-editable-cell__chevron\" aria-hidden=\"true\">\n <Icon glyph=\"chevron-down\" size={12} />\n </span>\n </button>\n )}\n renderItem={(o) => (\n <span className=\"uxm-editable-cell__option-label\">{o.label}</span>\n )}\n footer={clearable ? ({ clear, selected }: { clear: () => void; selected: EditableCellOption[] }) =>\n selected.length > 0 ? (\n <ButtonGhost\n className=\"uxm-listbox__footer-clear-option\"\n // `clear` (from MultiListbox) empties the draft and keeps the\n // panel open, so \"clear all then pick one\" works even on a\n // required cell — the empty state is transient and never\n // reaches `validate` / `onCommit`. `selected` is the live\n // draft, so the button hides itself once nothing is picked.\n onClick={clear}\n >\n <Icon glyph=\"close\" size={12} />\n Clear all\n </ButtonGhost>\n ) : null\n : undefined}\n />\n {clearable && !disabled && !submitting && !isEmpty && (\n /* Trigger ✕ — clear from the field itself (the input-family\n convention), on every size: commits the empty value directly,\n complementing the panel-footer Clear. Sibling of the trigger (a\n button can't nest a button), absolutely positioned into the\n reserved second gutter slot. Revealed only while the panel is\n open (see the `--open` gate in the stylesheet) — unlike the\n chevron, which also shows on hover. */\n <button\n type=\"button\"\n className=\"uxm-editable-cell__trigger-clear\"\n // Out of the tab order, same as every in-field clear here.\n tabIndex={-1}\n // Same sibling-of-the-trigger problem as the select ✕ above, but\n // costlier here: `useDismiss` fires on mousedown, and this panel\n // runs `commitMode=\"close\"`, so an unswallowed mousedown would\n // commit the STAGED DRAFT first and only then clear — two commits\n // for one press, and if the first is still in flight the\n // re-entrancy guard in `commitValue` drops the clear entirely.\n // Stopping it leaves the panel open, which is deliberate and\n // matches the footer's \"Clear all\": clear, then pick afresh.\n // MultiListbox re-seeds its draft from `value` under an open panel,\n // so the later close commits the cleared set, not the stale draft.\n onMouseDown={(e) => e.stopPropagation()}\n onClick={() => void commitValue([])}\n aria-label={clearSelectionLabel}\n >\n <Icon glyph=\"close\" size={12} />\n </button>\n )}\n <Popover\n open={Boolean(shownError)}\n onOpenChange={(next) => {\n if (!next) setError(null);\n }}\n anchor={wrapRef}\n placement=\"bottom-start\"\n closeOnEscape={false}\n closeOnOutsideClick={false}\n restoreFocus={false}\n role=\"presentation\"\n >\n {shownError && (\n <Banner\n variant={shownError.severity}\n id=\"uxm-editable-cell__error\"\n className=\"uxm-editable-cell__error-banner\"\n >\n {shownError.message}\n </Banner>\n )}\n </Popover>\n </span>\n );\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var editable_cell_text_exports = {};
20
+ __export(editable_cell_text_exports, {
21
+ EditableCellTextView: () => EditableCellTextView
22
+ });
23
+ module.exports = __toCommonJS(editable_cell_text_exports);
24
+ var import_jsx_runtime = require("react/jsx-runtime");
25
+ var import_helpers = require("../../helpers/index.cjs");
26
+ var import_banner = require("../banner/index.cjs");
27
+ var import_hover_tooltip = require("../hover-tooltip/index.cjs");
28
+ var import_icon = require("../icon/index.cjs");
29
+ var import_number_input = require("../number-input/index.cjs");
30
+ var import_popover = require("../popover/index.cjs");
31
+ function EditableCellTextView({ props, cell }) {
32
+ const {
33
+ value,
34
+ disabled,
35
+ placeholder,
36
+ className,
37
+ style,
38
+ "aria-label": ariaLabel,
39
+ type,
40
+ clearable,
41
+ align,
42
+ size,
43
+ clearValueLabel
44
+ } = props;
45
+ const {
46
+ setIsEditing,
47
+ draft,
48
+ setDraft,
49
+ submitting,
50
+ error,
51
+ setError,
52
+ inputRef,
53
+ wrapRef,
54
+ handleCommit,
55
+ handleClearDraft,
56
+ handleKeyDown,
57
+ editing,
58
+ isEmpty,
59
+ display,
60
+ titleText,
61
+ shownError
62
+ } = cell;
63
+ if (!editing) {
64
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
65
+ "button",
66
+ {
67
+ type: "button",
68
+ className: (0, import_helpers.cn)(
69
+ "uxm-editable-cell",
70
+ `uxm-editable-cell--${size}`,
71
+ `uxm-editable-cell--align-${align}`,
72
+ disabled && "uxm-editable-cell--disabled",
73
+ isEmpty && "uxm-editable-cell--empty",
74
+ className
75
+ ),
76
+ style,
77
+ onClick: () => {
78
+ if (!disabled) setIsEditing(true);
79
+ },
80
+ disabled,
81
+ "aria-label": ariaLabel ?? `Edit ${String(value ?? "")}`,
82
+ children: [
83
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_hover_tooltip.HoverTooltip, { content: titleText, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "uxm-editable-cell__value", children: display }) }),
84
+ !disabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "uxm-editable-cell__pencil", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icon.Icon, { glyph: "pencil", size: 16, strokeWidth: 1.75 }) })
85
+ ]
86
+ }
87
+ );
88
+ }
89
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
90
+ "span",
91
+ {
92
+ ref: wrapRef,
93
+ className: (0, import_helpers.cn)(
94
+ "uxm-editable-cell uxm-editable-cell--editing",
95
+ `uxm-editable-cell--${size}`,
96
+ `uxm-editable-cell--align-${align}`,
97
+ clearable && "uxm-editable-cell--clearable",
98
+ shownError?.severity === "error" && "uxm-editable-cell--error",
99
+ shownError?.severity === "warning" && "uxm-editable-cell--warning",
100
+ className
101
+ ),
102
+ style,
103
+ children: [
104
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "uxm-editable-cell__ghost", "aria-hidden": "true", children: display }),
105
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "uxm-editable-cell__ghost", "aria-hidden": "true", children: draft }),
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
107
+ "input",
108
+ {
109
+ ref: inputRef,
110
+ type: "text",
111
+ inputMode: type === "number" ? "decimal" : void 0,
112
+ autoComplete: "off",
113
+ className: "uxm-editable-cell__input",
114
+ value: draft,
115
+ onChange: (e) => {
116
+ setDraft(
117
+ type === "number" ? (0, import_number_input.maskNumeric)(e.target.value, true, true, Number.POSITIVE_INFINITY) : e.target.value
118
+ );
119
+ if (error) setError(null);
120
+ },
121
+ onBlur: () => {
122
+ if (!submitting) handleCommit();
123
+ },
124
+ onKeyDown: handleKeyDown,
125
+ disabled: submitting,
126
+ placeholder,
127
+ "aria-invalid": Boolean(shownError),
128
+ "aria-describedby": shownError ? "uxm-editable-cell__error" : void 0
129
+ }
130
+ ),
131
+ clearable && !submitting && draft !== "" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
132
+ "button",
133
+ {
134
+ type: "button",
135
+ className: "uxm-editable-cell__clear",
136
+ tabIndex: -1,
137
+ onMouseDown: (e) => e.preventDefault(),
138
+ onClick: handleClearDraft,
139
+ "aria-label": clearValueLabel,
140
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_icon.Icon, { glyph: "close", size: 12 })
141
+ }
142
+ ),
143
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
144
+ import_popover.Popover,
145
+ {
146
+ open: Boolean(shownError),
147
+ onOpenChange: (next) => {
148
+ if (!next) setError(null);
149
+ },
150
+ anchor: wrapRef,
151
+ placement: "bottom-start",
152
+ closeOnEscape: false,
153
+ closeOnOutsideClick: false,
154
+ restoreFocus: false,
155
+ role: "presentation",
156
+ children: shownError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
157
+ import_banner.Banner,
158
+ {
159
+ variant: shownError.severity,
160
+ id: "uxm-editable-cell__error",
161
+ className: "uxm-editable-cell__error-banner",
162
+ children: shownError.message
163
+ }
164
+ )
165
+ }
166
+ )
167
+ ]
168
+ }
169
+ );
170
+ }
171
+ // Annotate the CommonJS export names for ESM import in node:
172
+ 0 && (module.exports = {
173
+ EditableCellTextView
174
+ });
175
+ //# sourceMappingURL=editable-cell-text.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/ui/editable-cell/editable-cell-text.tsx"],"sourcesContent":["import { cn } from '@/helpers';\n\nimport { Banner } from '../banner';\nimport { HoverTooltip } from '../hover-tooltip';\nimport { Icon } from '../icon';\nimport { maskNumeric } from '../number-input';\nimport { Popover } from '../popover';\n\nimport type { EditableCellViewProps } from './use-editable-cell';\n\n/** `type=\"text\"` / `\"number\"` — a button in display mode, an input in edit mode. */\nexport function EditableCellTextView({ props, cell }: EditableCellViewProps) {\n const {\n value,\n disabled,\n placeholder,\n className,\n style,\n 'aria-label': ariaLabel,\n type,\n clearable,\n align,\n size,\n clearValueLabel,\n } = props;\n const {\n setIsEditing,\n draft,\n setDraft,\n submitting,\n error,\n setError,\n inputRef,\n wrapRef,\n handleCommit,\n handleClearDraft,\n handleKeyDown,\n editing,\n isEmpty,\n display,\n titleText,\n shownError,\n } = cell;\n\n // Text / number types\n if (!editing) {\n return (\n <button\n type=\"button\"\n className={cn(\n 'uxm-editable-cell',\n `uxm-editable-cell--${size}`,\n `uxm-editable-cell--align-${align}`,\n disabled && 'uxm-editable-cell--disabled',\n isEmpty && 'uxm-editable-cell--empty',\n className,\n )}\n style={style}\n onClick={() => {\n if (!disabled) setIsEditing(true);\n }}\n disabled={disabled}\n aria-label={ariaLabel ?? `Edit ${String(value ?? '')}`}\n >\n {/* The value needs its own element for ellipsis — text-overflow\n doesn't apply to a flex container's anonymous text. Values wider\n than the cell's max-width truncate instead of growing the column\n unboundedly; the hidden text surfaces in a hover tooltip (only\n when actually clipped) and stays editable by entering edit mode. */}\n <HoverTooltip content={titleText} disabled={disabled}>\n <span className=\"uxm-editable-cell__value\">{display}</span>\n </HoverTooltip>\n {/* Hover affordance — a pencil glyph fades in on hover / keyboard\n focus. The background tint alone can't signal editability inside\n a DataTable, where the row's own hover tint coincides with it.\n Absolute overlay in a reserved gutter (see editable-cell.scss) so\n it never shifts or collides with the value. Hidden when disabled. */}\n {!disabled && (\n <span className=\"uxm-editable-cell__pencil\" aria-hidden=\"true\">\n <Icon glyph=\"pencil\" size={16} strokeWidth={1.75} />\n </span>\n )}\n </button>\n );\n }\n\n return (\n <span\n ref={wrapRef}\n className={cn(\n 'uxm-editable-cell uxm-editable-cell--editing',\n `uxm-editable-cell--${size}`,\n `uxm-editable-cell--align-${align}`,\n clearable && 'uxm-editable-cell--clearable',\n shownError?.severity === 'error' && 'uxm-editable-cell--error',\n shownError?.severity === 'warning' && 'uxm-editable-cell--warning',\n className,\n )}\n style={style}\n >\n {/* Invisible width-keepers, stacked in the same grid cell as the\n input. The display content ghost preserves the exact min-content\n width this cell contributed before entering edit mode — without\n it, editing the column's WIDEST row would drop its contribution\n from auto table-column sizing and the column would visibly\n shrink. The draft ghost grows the cell naturally as the user\n types past the original width. */}\n <span className=\"uxm-editable-cell__ghost\" aria-hidden=\"true\">\n {display}\n </span>\n <span className=\"uxm-editable-cell__ghost\" aria-hidden=\"true\">\n {draft}\n </span>\n <input\n ref={inputRef}\n // `type=\"text\"` + `inputMode` — the input-family convention (see\n // NumberInput): native number inputs ship browser spinner UI, trigger\n // autofill, and disagree across browsers on accepted characters.\n // `maskNumeric` replaces the native filtering per keystroke (same as\n // the date editor's `maskDate`); without it, `Number()`'s loose\n // coercion would let e.g. \"0x1A\" commit as 26.\n type=\"text\"\n inputMode={type === 'number' ? 'decimal' : undefined}\n autoComplete=\"off\"\n className=\"uxm-editable-cell__input\"\n value={draft}\n onChange={(e) => {\n setDraft(\n type === 'number'\n ? maskNumeric(e.target.value, true, true, Number.POSITIVE_INFINITY)\n : e.target.value,\n );\n // Clear stale validation error as the user types — they'll\n // see a new one on the next commit attempt if it still fails.\n if (error) setError(null);\n }}\n onBlur={() => {\n // Don't double-commit while a previous commit is still pending.\n if (!submitting) handleCommit();\n }}\n onKeyDown={handleKeyDown}\n disabled={submitting}\n placeholder={placeholder}\n aria-invalid={Boolean(shownError)}\n aria-describedby={shownError ? 'uxm-editable-cell__error' : undefined}\n />\n {/* One-click ✕ (mirrors TextInput/NumberInput): empties the draft and\n keeps focus; hidden while the draft is already empty. The gutter is\n reserved via `--clearable` so its appearance never shifts text. */}\n {clearable && !submitting && draft !== '' && (\n <button\n type=\"button\"\n className=\"uxm-editable-cell__clear\"\n // Out of the tab order — see the date branch's note: the blur Tab\n // fires commits and unmounts this button, so leaving it focusable\n // would strand focus on a removed node instead of advancing to the\n // next cell.\n tabIndex={-1}\n onMouseDown={(e) => e.preventDefault()}\n onClick={handleClearDraft}\n aria-label={clearValueLabel}\n >\n <Icon glyph=\"close\" size={12} />\n </button>\n )}\n {/* Problems hang under the cell in a portal'd popover so the table\n row never changes height. The popover must not manage focus —\n the input keeps it for in-place correction / retry. Escape and\n outside clicks already have edit-mode semantics (cancel / blur-\n commit), so the popover's own close triggers are disabled; it\n opens and closes purely with the error state. */}\n <Popover\n open={Boolean(shownError)}\n onOpenChange={(next) => {\n if (!next) setError(null);\n }}\n anchor={wrapRef}\n placement=\"bottom-start\"\n closeOnEscape={false}\n closeOnOutsideClick={false}\n restoreFocus={false}\n role=\"presentation\"\n >\n {shownError && (\n <Banner\n variant={shownError.severity}\n id=\"uxm-editable-cell__error\"\n className=\"uxm-editable-cell__error-banner\"\n >\n {shownError.message}\n </Banner>\n )}\n </Popover>\n </span>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,4 @@
1
+ import type { EditableCellViewProps } from './use-editable-cell.js';
2
+ /** `type="text"` / `"number"` — a button in display mode, an input in edit mode. */
3
+ export declare function EditableCellTextView({ props, cell }: EditableCellViewProps): import("react").JSX.Element;
4
+ //# sourceMappingURL=editable-cell-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editable-cell-text.d.ts","sourceRoot":"","sources":["../../../src/ui/editable-cell/editable-cell-text.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjE,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,qBAAqB,+BAwL1E"}
@@ -0,0 +1,151 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../helpers/index.js";
3
+ import { Banner } from "../banner/index.js";
4
+ import { HoverTooltip } from "../hover-tooltip/index.js";
5
+ import { Icon } from "../icon/index.js";
6
+ import { maskNumeric } from "../number-input/index.js";
7
+ import { Popover } from "../popover/index.js";
8
+ function EditableCellTextView({ props, cell }) {
9
+ const {
10
+ value,
11
+ disabled,
12
+ placeholder,
13
+ className,
14
+ style,
15
+ "aria-label": ariaLabel,
16
+ type,
17
+ clearable,
18
+ align,
19
+ size,
20
+ clearValueLabel
21
+ } = props;
22
+ const {
23
+ setIsEditing,
24
+ draft,
25
+ setDraft,
26
+ submitting,
27
+ error,
28
+ setError,
29
+ inputRef,
30
+ wrapRef,
31
+ handleCommit,
32
+ handleClearDraft,
33
+ handleKeyDown,
34
+ editing,
35
+ isEmpty,
36
+ display,
37
+ titleText,
38
+ shownError
39
+ } = cell;
40
+ if (!editing) {
41
+ return /* @__PURE__ */ jsxs(
42
+ "button",
43
+ {
44
+ type: "button",
45
+ className: cn(
46
+ "uxm-editable-cell",
47
+ `uxm-editable-cell--${size}`,
48
+ `uxm-editable-cell--align-${align}`,
49
+ disabled && "uxm-editable-cell--disabled",
50
+ isEmpty && "uxm-editable-cell--empty",
51
+ className
52
+ ),
53
+ style,
54
+ onClick: () => {
55
+ if (!disabled) setIsEditing(true);
56
+ },
57
+ disabled,
58
+ "aria-label": ariaLabel ?? `Edit ${String(value ?? "")}`,
59
+ children: [
60
+ /* @__PURE__ */ jsx(HoverTooltip, { content: titleText, disabled, children: /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__value", children: display }) }),
61
+ !disabled && /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__pencil", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, { glyph: "pencil", size: 16, strokeWidth: 1.75 }) })
62
+ ]
63
+ }
64
+ );
65
+ }
66
+ return /* @__PURE__ */ jsxs(
67
+ "span",
68
+ {
69
+ ref: wrapRef,
70
+ className: cn(
71
+ "uxm-editable-cell uxm-editable-cell--editing",
72
+ `uxm-editable-cell--${size}`,
73
+ `uxm-editable-cell--align-${align}`,
74
+ clearable && "uxm-editable-cell--clearable",
75
+ shownError?.severity === "error" && "uxm-editable-cell--error",
76
+ shownError?.severity === "warning" && "uxm-editable-cell--warning",
77
+ className
78
+ ),
79
+ style,
80
+ children: [
81
+ /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__ghost", "aria-hidden": "true", children: display }),
82
+ /* @__PURE__ */ jsx("span", { className: "uxm-editable-cell__ghost", "aria-hidden": "true", children: draft }),
83
+ /* @__PURE__ */ jsx(
84
+ "input",
85
+ {
86
+ ref: inputRef,
87
+ type: "text",
88
+ inputMode: type === "number" ? "decimal" : void 0,
89
+ autoComplete: "off",
90
+ className: "uxm-editable-cell__input",
91
+ value: draft,
92
+ onChange: (e) => {
93
+ setDraft(
94
+ type === "number" ? maskNumeric(e.target.value, true, true, Number.POSITIVE_INFINITY) : e.target.value
95
+ );
96
+ if (error) setError(null);
97
+ },
98
+ onBlur: () => {
99
+ if (!submitting) handleCommit();
100
+ },
101
+ onKeyDown: handleKeyDown,
102
+ disabled: submitting,
103
+ placeholder,
104
+ "aria-invalid": Boolean(shownError),
105
+ "aria-describedby": shownError ? "uxm-editable-cell__error" : void 0
106
+ }
107
+ ),
108
+ clearable && !submitting && draft !== "" && /* @__PURE__ */ jsx(
109
+ "button",
110
+ {
111
+ type: "button",
112
+ className: "uxm-editable-cell__clear",
113
+ tabIndex: -1,
114
+ onMouseDown: (e) => e.preventDefault(),
115
+ onClick: handleClearDraft,
116
+ "aria-label": clearValueLabel,
117
+ children: /* @__PURE__ */ jsx(Icon, { glyph: "close", size: 12 })
118
+ }
119
+ ),
120
+ /* @__PURE__ */ jsx(
121
+ Popover,
122
+ {
123
+ open: Boolean(shownError),
124
+ onOpenChange: (next) => {
125
+ if (!next) setError(null);
126
+ },
127
+ anchor: wrapRef,
128
+ placement: "bottom-start",
129
+ closeOnEscape: false,
130
+ closeOnOutsideClick: false,
131
+ restoreFocus: false,
132
+ role: "presentation",
133
+ children: shownError && /* @__PURE__ */ jsx(
134
+ Banner,
135
+ {
136
+ variant: shownError.severity,
137
+ id: "uxm-editable-cell__error",
138
+ className: "uxm-editable-cell__error-banner",
139
+ children: shownError.message
140
+ }
141
+ )
142
+ }
143
+ )
144
+ ]
145
+ }
146
+ );
147
+ }
148
+ export {
149
+ EditableCellTextView
150
+ };
151
+ //# sourceMappingURL=editable-cell-text.js.map