hazo_ui 6.15.0 → 6.18.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/CHANGE_LOG.md +91 -0
- package/README.md +13 -0
- package/dist/index.cjs +536 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +539 -7
- package/dist/index.js.map +1 -1
- package/dist/index.locale-picker.cjs +7 -1
- package/dist/index.locale-picker.cjs.map +1 -1
- package/dist/index.locale-picker.js +7 -1
- package/dist/index.locale-picker.js.map +1 -1
- package/package.json +6 -4
- package/tailwind-preset.cjs +120 -0
package/dist/index.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { clsx } from 'clsx';
|
|
3
3
|
import { twMerge } from 'tailwind-merge';
|
|
4
4
|
import * as React27 from 'react';
|
|
5
|
-
import React27__default, { createContext, lazy,
|
|
5
|
+
import React27__default, { createContext, lazy, useRef, useContext, useState, useCallback, useEffect, useMemo, Fragment, Suspense, useSyncExternalStore } from 'react';
|
|
6
6
|
import { generateRequestId } from 'hazo_core';
|
|
7
7
|
import { withContext, setBrowserCorrelationId } from 'hazo_core/client';
|
|
8
8
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
9
9
|
import { Slot } from '@radix-ui/react-slot';
|
|
10
10
|
import { cva } from 'class-variance-authority';
|
|
11
11
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
12
|
-
import { X, ChevronDown, ChevronUp, Check, Circle, ChevronRight, ChevronLeft, Filter, Plus, ArrowUpDown, icons, Loader2, AlertTriangle, OctagonAlert, CheckCircle2, ChevronsUpDown, Download, Share2, Copy,
|
|
12
|
+
import { X, ChevronDown, ChevronUp, Check, Circle, ChevronRight, GripVertical, Trash2, ChevronLeft, Filter, Plus, ArrowUpDown, icons, Loader2, AlertTriangle, OctagonAlert, CheckCircle2, ChevronsUpDown, Download, Share2, Copy, Menu, ArrowUp, ArrowDown, Pencil, Calendar as Calendar$1, Globe } from 'lucide-react';
|
|
13
13
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
14
14
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
15
15
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
@@ -17,7 +17,7 @@ import { DayPicker } from 'react-day-picker';
|
|
|
17
17
|
import { format } from 'date-fns';
|
|
18
18
|
import { createPackageT, resolvePackageLocale } from 'hazo_core/i18n';
|
|
19
19
|
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter, pointerWithin, rectIntersection, closestCorners, DragOverlay, useDroppable } from '@dnd-kit/core';
|
|
20
|
-
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, arrayMove
|
|
20
|
+
import { useSortable, sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, arrayMove } from '@dnd-kit/sortable';
|
|
21
21
|
import { CSS } from '@dnd-kit/utilities';
|
|
22
22
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
23
23
|
import * as FaIcons from 'react-icons/fa';
|
|
@@ -807,6 +807,8 @@ var en_default = {
|
|
|
807
807
|
"locale_picker.change_language": "Change language",
|
|
808
808
|
"app_logo.alt_fallback": "Logo",
|
|
809
809
|
"app_header.aria_label": "Application header",
|
|
810
|
+
"app_header.menu_label": "Menu",
|
|
811
|
+
"app_header.nav_title": "Navigation",
|
|
810
812
|
"skeleton.loading_content": "Loading content",
|
|
811
813
|
"spinner.loading": "Loading",
|
|
812
814
|
"spinner.loading_text": "Loading...",
|
|
@@ -864,7 +866,11 @@ var en_default = {
|
|
|
864
866
|
"charts.pct_of_first": "% of first: {{pct}}%",
|
|
865
867
|
"charts.pct_of_prev": "% of prev: {{pct}}%",
|
|
866
868
|
"charts.dropoff": "Drop-off: \u2212{{value}}",
|
|
867
|
-
"toast.missing_prefix": "Missing: {{items}}"
|
|
869
|
+
"toast.missing_prefix": "Missing: {{items}}",
|
|
870
|
+
"editable_data_table.add": "Add",
|
|
871
|
+
"editable_data_table.delete": "Delete row",
|
|
872
|
+
"editable_data_table.empty": "No rows yet. Click Add to start.",
|
|
873
|
+
"editable_data_table.drag_to_reorder": "Drag to reorder"
|
|
868
874
|
};
|
|
869
875
|
var default_t = createPackageT("hazo_ui", en_default);
|
|
870
876
|
var defaultHazoUiT = default_t;
|
|
@@ -12457,6 +12463,7 @@ function Logo({
|
|
|
12457
12463
|
}
|
|
12458
12464
|
function AppHeader({ identity, homeHref, navItems, actions, className }) {
|
|
12459
12465
|
const t = useHazoUiT();
|
|
12466
|
+
const [drawerOpen, setDrawerOpen] = React27.useState(false);
|
|
12460
12467
|
return /* @__PURE__ */ jsxs(
|
|
12461
12468
|
"header",
|
|
12462
12469
|
{
|
|
@@ -12476,9 +12483,34 @@ function AppHeader({ identity, homeHref, navItems, actions, className }) {
|
|
|
12476
12483
|
href: homeHref
|
|
12477
12484
|
}
|
|
12478
12485
|
),
|
|
12479
|
-
navItems
|
|
12486
|
+
navItems && /* @__PURE__ */ jsx("div", { className: "hidden md:flex items-center", children: navItems })
|
|
12480
12487
|
] }),
|
|
12481
|
-
/* @__PURE__ */
|
|
12488
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
12489
|
+
actions,
|
|
12490
|
+
navItems && /* @__PURE__ */ jsxs(Drawer, { open: drawerOpen, onOpenChange: setDrawerOpen, children: [
|
|
12491
|
+
/* @__PURE__ */ jsx(DrawerTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
12492
|
+
"button",
|
|
12493
|
+
{
|
|
12494
|
+
className: "md:hidden rounded-md p-1.5 hover:bg-navbar-active/10",
|
|
12495
|
+
"aria-label": t("app_header.menu_label"),
|
|
12496
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "h-5 w-5" })
|
|
12497
|
+
}
|
|
12498
|
+
) }),
|
|
12499
|
+
/* @__PURE__ */ jsxs(DrawerContent, { children: [
|
|
12500
|
+
/* @__PURE__ */ jsx(DrawerTitle, { className: "sr-only", children: t("app_header.nav_title") }),
|
|
12501
|
+
/* @__PURE__ */ jsx(
|
|
12502
|
+
"div",
|
|
12503
|
+
{
|
|
12504
|
+
className: "p-4 [&_nav]:flex-col [&_nav]:gap-2 [&_nav]:items-stretch",
|
|
12505
|
+
onClick: (e) => {
|
|
12506
|
+
if (e.target.closest("a")) setDrawerOpen(false);
|
|
12507
|
+
},
|
|
12508
|
+
children: navItems
|
|
12509
|
+
}
|
|
12510
|
+
)
|
|
12511
|
+
] })
|
|
12512
|
+
] })
|
|
12513
|
+
] })
|
|
12482
12514
|
]
|
|
12483
12515
|
}
|
|
12484
12516
|
);
|
|
@@ -13126,7 +13158,507 @@ function useHazoEvent(pkg, event, handler) {
|
|
|
13126
13158
|
return () => window.removeEventListener(event_name, listener);
|
|
13127
13159
|
}, [pkg, event]);
|
|
13128
13160
|
}
|
|
13161
|
+
function EditableCell({
|
|
13162
|
+
value,
|
|
13163
|
+
type,
|
|
13164
|
+
options,
|
|
13165
|
+
defaultColorValue,
|
|
13166
|
+
clearable,
|
|
13167
|
+
onCommit,
|
|
13168
|
+
editable,
|
|
13169
|
+
forceEdit,
|
|
13170
|
+
onTabOut,
|
|
13171
|
+
onEnterDown,
|
|
13172
|
+
onPaste,
|
|
13173
|
+
onActivated
|
|
13174
|
+
}) {
|
|
13175
|
+
const [editing, setEditing] = useState(false);
|
|
13176
|
+
const [draft, setDraft] = useState(String(value ?? ""));
|
|
13177
|
+
const inputRef = useRef(null);
|
|
13178
|
+
useEffect(() => {
|
|
13179
|
+
if (forceEdit) {
|
|
13180
|
+
setDraft(String(value ?? ""));
|
|
13181
|
+
setEditing(true);
|
|
13182
|
+
}
|
|
13183
|
+
}, [forceEdit]);
|
|
13184
|
+
useEffect(() => {
|
|
13185
|
+
if (editing && inputRef.current) {
|
|
13186
|
+
inputRef.current.focus();
|
|
13187
|
+
inputRef.current.select();
|
|
13188
|
+
if (forceEdit) {
|
|
13189
|
+
onActivated?.();
|
|
13190
|
+
}
|
|
13191
|
+
}
|
|
13192
|
+
}, [editing]);
|
|
13193
|
+
const commit = useCallback(() => {
|
|
13194
|
+
setEditing(false);
|
|
13195
|
+
if (type === "number") {
|
|
13196
|
+
const n = Number(draft);
|
|
13197
|
+
onCommit(Number.isNaN(n) || draft.trim() === "" ? 0 : n);
|
|
13198
|
+
} else {
|
|
13199
|
+
onCommit(draft);
|
|
13200
|
+
}
|
|
13201
|
+
}, [draft, onCommit, type]);
|
|
13202
|
+
const cancel = useCallback(() => {
|
|
13203
|
+
setEditing(false);
|
|
13204
|
+
setDraft(String(value ?? ""));
|
|
13205
|
+
}, [value]);
|
|
13206
|
+
const handleKeyDown = useCallback(
|
|
13207
|
+
(e) => {
|
|
13208
|
+
if (e.key === "Enter") {
|
|
13209
|
+
e.preventDefault();
|
|
13210
|
+
onEnterDown?.();
|
|
13211
|
+
commit();
|
|
13212
|
+
} else if (e.key === "Escape") {
|
|
13213
|
+
e.preventDefault();
|
|
13214
|
+
cancel();
|
|
13215
|
+
} else if (e.key === "Tab") {
|
|
13216
|
+
const direction = e.shiftKey ? -1 : 1;
|
|
13217
|
+
const handled = onTabOut?.(direction) ?? false;
|
|
13218
|
+
if (handled) {
|
|
13219
|
+
e.preventDefault();
|
|
13220
|
+
commit();
|
|
13221
|
+
}
|
|
13222
|
+
}
|
|
13223
|
+
},
|
|
13224
|
+
[commit, cancel, onTabOut, onEnterDown]
|
|
13225
|
+
);
|
|
13226
|
+
if (!editable) {
|
|
13227
|
+
return /* @__PURE__ */ jsx("span", { className: "text-xs truncate block px-1 py-1.5", children: String(value ?? "") });
|
|
13228
|
+
}
|
|
13229
|
+
if (type === "color") {
|
|
13230
|
+
const colorValue = String(
|
|
13231
|
+
value ?? defaultColorValue ?? "#94a3b8"
|
|
13232
|
+
);
|
|
13233
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
|
|
13234
|
+
/* @__PURE__ */ jsx(
|
|
13235
|
+
"input",
|
|
13236
|
+
{
|
|
13237
|
+
type: "color",
|
|
13238
|
+
className: "h-7 w-8 cursor-pointer border border-border rounded p-0.5",
|
|
13239
|
+
value: colorValue,
|
|
13240
|
+
onChange: (e) => onCommit(e.target.value)
|
|
13241
|
+
}
|
|
13242
|
+
),
|
|
13243
|
+
clearable && value != null && /* @__PURE__ */ jsx(
|
|
13244
|
+
"button",
|
|
13245
|
+
{
|
|
13246
|
+
type: "button",
|
|
13247
|
+
className: "text-xs leading-none text-muted-foreground hover:text-foreground px-0.5",
|
|
13248
|
+
onClick: () => onCommit(void 0),
|
|
13249
|
+
children: "\xD7"
|
|
13250
|
+
}
|
|
13251
|
+
)
|
|
13252
|
+
] });
|
|
13253
|
+
}
|
|
13254
|
+
if (type === "select") {
|
|
13255
|
+
return /* @__PURE__ */ jsxs(
|
|
13256
|
+
Select,
|
|
13257
|
+
{
|
|
13258
|
+
value: String(value ?? ""),
|
|
13259
|
+
onValueChange: (v) => onCommit(v),
|
|
13260
|
+
children: [
|
|
13261
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-7 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
13262
|
+
/* @__PURE__ */ jsx(SelectContent, { children: (options ?? []).map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt }, opt)) })
|
|
13263
|
+
]
|
|
13264
|
+
}
|
|
13265
|
+
);
|
|
13266
|
+
}
|
|
13267
|
+
if (!editing) {
|
|
13268
|
+
return /* @__PURE__ */ jsx(
|
|
13269
|
+
"span",
|
|
13270
|
+
{
|
|
13271
|
+
className: "text-xs truncate block px-1 py-1.5 cursor-text hover:bg-muted/50 rounded",
|
|
13272
|
+
onClick: () => {
|
|
13273
|
+
setDraft(String(value ?? ""));
|
|
13274
|
+
setEditing(true);
|
|
13275
|
+
},
|
|
13276
|
+
role: "button",
|
|
13277
|
+
tabIndex: 0,
|
|
13278
|
+
onKeyDown: (e) => {
|
|
13279
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
13280
|
+
setDraft(String(value ?? ""));
|
|
13281
|
+
setEditing(true);
|
|
13282
|
+
}
|
|
13283
|
+
},
|
|
13284
|
+
children: String(value ?? "")
|
|
13285
|
+
}
|
|
13286
|
+
);
|
|
13287
|
+
}
|
|
13288
|
+
return /* @__PURE__ */ jsx(
|
|
13289
|
+
"input",
|
|
13290
|
+
{
|
|
13291
|
+
ref: inputRef,
|
|
13292
|
+
type: type === "number" ? "number" : "text",
|
|
13293
|
+
className: "h-7 text-xs border border-input rounded-md px-2 bg-background focus:outline-none focus:ring-1 focus:ring-ring w-full",
|
|
13294
|
+
value: draft,
|
|
13295
|
+
onChange: (e) => setDraft(e.target.value),
|
|
13296
|
+
onKeyDown: handleKeyDown,
|
|
13297
|
+
onPaste: (e) => {
|
|
13298
|
+
const text = e.clipboardData.getData("text/plain") || e.clipboardData.getData("text");
|
|
13299
|
+
if (!text) return;
|
|
13300
|
+
const handled = onPaste?.(text) ?? false;
|
|
13301
|
+
if (handled) {
|
|
13302
|
+
e.preventDefault();
|
|
13303
|
+
setEditing(false);
|
|
13304
|
+
}
|
|
13305
|
+
},
|
|
13306
|
+
onBlur: commit
|
|
13307
|
+
}
|
|
13308
|
+
);
|
|
13309
|
+
}
|
|
13310
|
+
var SortableRow = React27__default.memo(function SortableRow2({
|
|
13311
|
+
id,
|
|
13312
|
+
highlighted,
|
|
13313
|
+
children
|
|
13314
|
+
}) {
|
|
13315
|
+
const t = useHazoUiT();
|
|
13316
|
+
const {
|
|
13317
|
+
attributes,
|
|
13318
|
+
listeners,
|
|
13319
|
+
setNodeRef,
|
|
13320
|
+
setActivatorNodeRef,
|
|
13321
|
+
transform,
|
|
13322
|
+
transition,
|
|
13323
|
+
isDragging
|
|
13324
|
+
} = useSortable({ id });
|
|
13325
|
+
const style = {
|
|
13326
|
+
transform: CSS.Transform.toString(transform),
|
|
13327
|
+
transition,
|
|
13328
|
+
opacity: isDragging ? 0.5 : 1
|
|
13329
|
+
};
|
|
13330
|
+
return /* @__PURE__ */ jsxs(
|
|
13331
|
+
TableRow2,
|
|
13332
|
+
{
|
|
13333
|
+
ref: setNodeRef,
|
|
13334
|
+
style,
|
|
13335
|
+
"data-sortable-id": id,
|
|
13336
|
+
className: cn(highlighted && "bg-blue-50 ring-1 ring-blue-300"),
|
|
13337
|
+
children: [
|
|
13338
|
+
/* @__PURE__ */ jsx(TableCell2, { className: "px-0 py-0.5 w-6", children: /* @__PURE__ */ jsx(
|
|
13339
|
+
"div",
|
|
13340
|
+
{
|
|
13341
|
+
ref: setActivatorNodeRef,
|
|
13342
|
+
className: "cursor-grab active:cursor-grabbing text-muted-foreground hover:text-foreground flex items-center justify-center",
|
|
13343
|
+
title: t("editable_data_table.drag_to_reorder"),
|
|
13344
|
+
...attributes,
|
|
13345
|
+
...listeners,
|
|
13346
|
+
children: /* @__PURE__ */ jsx(GripVertical, { className: "h-3.5 w-3.5" })
|
|
13347
|
+
}
|
|
13348
|
+
) }),
|
|
13349
|
+
children
|
|
13350
|
+
]
|
|
13351
|
+
}
|
|
13352
|
+
);
|
|
13353
|
+
});
|
|
13354
|
+
SortableRow.displayName = "SortableRow";
|
|
13355
|
+
var EditableTableRow = React27__default.memo(function EditableTableRow2({
|
|
13356
|
+
row,
|
|
13357
|
+
rowIndex,
|
|
13358
|
+
rowKey,
|
|
13359
|
+
isHighlighted,
|
|
13360
|
+
columns,
|
|
13361
|
+
activeEditColKey,
|
|
13362
|
+
deleteLabel,
|
|
13363
|
+
onCellCommit,
|
|
13364
|
+
onDeleteRow,
|
|
13365
|
+
onTabOutCell,
|
|
13366
|
+
onEnterDownCell,
|
|
13367
|
+
onPasteCell,
|
|
13368
|
+
onActivated
|
|
13369
|
+
}) {
|
|
13370
|
+
const renderCountRef = useRef(0);
|
|
13371
|
+
renderCountRef.current += 1;
|
|
13372
|
+
return /* @__PURE__ */ jsxs(SortableRow, { id: rowKey, highlighted: isHighlighted, children: [
|
|
13373
|
+
columns.map((col, colIndex) => {
|
|
13374
|
+
const resolvedOptions = typeof col.options === "function" ? col.options(row) : col.options;
|
|
13375
|
+
return /* @__PURE__ */ jsx(
|
|
13376
|
+
TableCell2,
|
|
13377
|
+
{
|
|
13378
|
+
className: cn("px-1 py-0.5", col.width),
|
|
13379
|
+
"data-row-render-count": colIndex === 0 ? renderCountRef.current : void 0,
|
|
13380
|
+
children: /* @__PURE__ */ jsx(
|
|
13381
|
+
EditableCell,
|
|
13382
|
+
{
|
|
13383
|
+
value: row[col.key],
|
|
13384
|
+
type: col.type ?? "text",
|
|
13385
|
+
options: resolvedOptions,
|
|
13386
|
+
defaultColorValue: col.defaultValue?.(rowIndex),
|
|
13387
|
+
clearable: col.clearable,
|
|
13388
|
+
editable: col.editable !== false,
|
|
13389
|
+
forceEdit: activeEditColKey === col.key,
|
|
13390
|
+
onTabOut: (direction) => onTabOutCell(rowIndex, col.key, direction),
|
|
13391
|
+
onEnterDown: () => onEnterDownCell(rowIndex, col.key),
|
|
13392
|
+
onPaste: (text) => onPasteCell(rowIndex, col.key, text),
|
|
13393
|
+
onActivated,
|
|
13394
|
+
onCommit: (v) => onCellCommit(rowIndex, col.key, v)
|
|
13395
|
+
}
|
|
13396
|
+
)
|
|
13397
|
+
},
|
|
13398
|
+
col.key
|
|
13399
|
+
);
|
|
13400
|
+
}),
|
|
13401
|
+
/* @__PURE__ */ jsx(TableCell2, { className: "px-0 py-0.5 w-8", children: /* @__PURE__ */ jsx(
|
|
13402
|
+
Button,
|
|
13403
|
+
{
|
|
13404
|
+
variant: "ghost",
|
|
13405
|
+
size: "icon",
|
|
13406
|
+
className: "h-7 w-7 text-muted-foreground hover:text-destructive",
|
|
13407
|
+
onClick: () => onDeleteRow(rowIndex),
|
|
13408
|
+
"aria-label": deleteLabel,
|
|
13409
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
13410
|
+
}
|
|
13411
|
+
) })
|
|
13412
|
+
] });
|
|
13413
|
+
});
|
|
13414
|
+
EditableTableRow.displayName = "EditableTableRow";
|
|
13415
|
+
function EditableDataTable({
|
|
13416
|
+
columns,
|
|
13417
|
+
rows,
|
|
13418
|
+
onChange,
|
|
13419
|
+
getRowKey,
|
|
13420
|
+
createRow,
|
|
13421
|
+
highlightedKey,
|
|
13422
|
+
className,
|
|
13423
|
+
label
|
|
13424
|
+
}) {
|
|
13425
|
+
const t = useHazoUiT();
|
|
13426
|
+
const editableColumns = useMemo(
|
|
13427
|
+
() => columns.filter(
|
|
13428
|
+
(col) => col.editable !== false && (col.type ?? "text") !== "select" && (col.type ?? "text") !== "color"
|
|
13429
|
+
).map((col) => col.key),
|
|
13430
|
+
[columns]
|
|
13431
|
+
);
|
|
13432
|
+
const [activeEditCell, setActiveEditCell] = useState(null);
|
|
13433
|
+
const rowsRef = useRef(rows);
|
|
13434
|
+
rowsRef.current = rows;
|
|
13435
|
+
const onChangeRef = useRef(onChange);
|
|
13436
|
+
onChangeRef.current = onChange;
|
|
13437
|
+
const handleTabOut = useCallback(
|
|
13438
|
+
(rowIndex, colKey, direction) => {
|
|
13439
|
+
const idx = editableColumns.indexOf(colKey);
|
|
13440
|
+
if (idx === -1) return false;
|
|
13441
|
+
if (direction === 1) {
|
|
13442
|
+
if (idx < editableColumns.length - 1) {
|
|
13443
|
+
setActiveEditCell({ row: rowIndex, col: editableColumns[idx + 1] });
|
|
13444
|
+
return true;
|
|
13445
|
+
}
|
|
13446
|
+
if (rowIndex + 1 < rows.length) {
|
|
13447
|
+
setActiveEditCell({ row: rowIndex + 1, col: editableColumns[0] });
|
|
13448
|
+
return true;
|
|
13449
|
+
}
|
|
13450
|
+
return false;
|
|
13451
|
+
}
|
|
13452
|
+
if (idx > 0) {
|
|
13453
|
+
setActiveEditCell({ row: rowIndex, col: editableColumns[idx - 1] });
|
|
13454
|
+
return true;
|
|
13455
|
+
}
|
|
13456
|
+
if (rowIndex - 1 >= 0) {
|
|
13457
|
+
setActiveEditCell({
|
|
13458
|
+
row: rowIndex - 1,
|
|
13459
|
+
col: editableColumns[editableColumns.length - 1]
|
|
13460
|
+
});
|
|
13461
|
+
return true;
|
|
13462
|
+
}
|
|
13463
|
+
return false;
|
|
13464
|
+
},
|
|
13465
|
+
[editableColumns, rows.length]
|
|
13466
|
+
);
|
|
13467
|
+
const handleEnterDown = useCallback(
|
|
13468
|
+
(rowIndex, colKey) => {
|
|
13469
|
+
if (rowIndex + 1 < rows.length) {
|
|
13470
|
+
setActiveEditCell({ row: rowIndex + 1, col: colKey });
|
|
13471
|
+
return true;
|
|
13472
|
+
}
|
|
13473
|
+
return false;
|
|
13474
|
+
},
|
|
13475
|
+
[rows.length]
|
|
13476
|
+
);
|
|
13477
|
+
const handlePaste = useCallback(
|
|
13478
|
+
(rowIndex, colKey, text) => {
|
|
13479
|
+
const startColIdx = editableColumns.indexOf(
|
|
13480
|
+
colKey
|
|
13481
|
+
);
|
|
13482
|
+
if (startColIdx === -1) return false;
|
|
13483
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
13484
|
+
const lines = normalized.split("\n");
|
|
13485
|
+
if (lines.length > 1 && lines[lines.length - 1] === "") {
|
|
13486
|
+
lines.pop();
|
|
13487
|
+
}
|
|
13488
|
+
const hasTab = normalized.includes(" ");
|
|
13489
|
+
const delimiter = hasTab ? " " : ",";
|
|
13490
|
+
const grid = lines.map((line) => line.split(delimiter));
|
|
13491
|
+
const isSingleCell = grid.length === 1 && grid[0].length === 1;
|
|
13492
|
+
if (isSingleCell) return false;
|
|
13493
|
+
const currentRows = rowsRef.current;
|
|
13494
|
+
const nextRows = currentRows.slice();
|
|
13495
|
+
grid.forEach((lineCells, rowOffset) => {
|
|
13496
|
+
const targetRowIndex = rowIndex + rowOffset;
|
|
13497
|
+
while (targetRowIndex >= nextRows.length) {
|
|
13498
|
+
nextRows.push(createRow());
|
|
13499
|
+
}
|
|
13500
|
+
const targetRow = {
|
|
13501
|
+
...nextRows[targetRowIndex]
|
|
13502
|
+
};
|
|
13503
|
+
lineCells.forEach((cellValue, colOffset) => {
|
|
13504
|
+
const targetColIdx = startColIdx + colOffset;
|
|
13505
|
+
if (targetColIdx >= editableColumns.length) return;
|
|
13506
|
+
const targetColKey = editableColumns[targetColIdx];
|
|
13507
|
+
const col = columns.find((c) => c.key === targetColKey);
|
|
13508
|
+
if (col?.type === "number") {
|
|
13509
|
+
const n = Number(cellValue);
|
|
13510
|
+
targetRow[targetColKey] = Number.isNaN(n) || cellValue.trim() === "" ? 0 : n;
|
|
13511
|
+
} else {
|
|
13512
|
+
targetRow[targetColKey] = cellValue;
|
|
13513
|
+
}
|
|
13514
|
+
});
|
|
13515
|
+
nextRows[targetRowIndex] = targetRow;
|
|
13516
|
+
});
|
|
13517
|
+
onChangeRef.current(nextRows);
|
|
13518
|
+
return true;
|
|
13519
|
+
},
|
|
13520
|
+
[editableColumns, columns, createRow]
|
|
13521
|
+
);
|
|
13522
|
+
const handleCellChange = useCallback(
|
|
13523
|
+
(rowIndex, colKey, value) => {
|
|
13524
|
+
const currentRows = rowsRef.current;
|
|
13525
|
+
const next = currentRows.map(
|
|
13526
|
+
(row, i) => i === rowIndex ? { ...row, [colKey]: value } : row
|
|
13527
|
+
);
|
|
13528
|
+
onChangeRef.current(next);
|
|
13529
|
+
},
|
|
13530
|
+
[]
|
|
13531
|
+
);
|
|
13532
|
+
const handleDelete = useCallback((rowIndex) => {
|
|
13533
|
+
const currentRows = rowsRef.current;
|
|
13534
|
+
onChangeRef.current(currentRows.filter((_, i) => i !== rowIndex));
|
|
13535
|
+
}, []);
|
|
13536
|
+
const onCellActivated = useCallback(() => setActiveEditCell(null), []);
|
|
13537
|
+
const handleAdd = () => {
|
|
13538
|
+
onChange([...rows, createRow()]);
|
|
13539
|
+
};
|
|
13540
|
+
const sensors = useSensors(
|
|
13541
|
+
useSensor(PointerSensor),
|
|
13542
|
+
useSensor(KeyboardSensor, {
|
|
13543
|
+
coordinateGetter: sortableKeyboardCoordinates
|
|
13544
|
+
})
|
|
13545
|
+
);
|
|
13546
|
+
const rowKeys = useMemo(
|
|
13547
|
+
() => rows.map((row, i) => getRowKey(row, i)),
|
|
13548
|
+
[rows, getRowKey]
|
|
13549
|
+
);
|
|
13550
|
+
const handleDragEnd = useCallback(
|
|
13551
|
+
(event) => {
|
|
13552
|
+
const { active, over } = event;
|
|
13553
|
+
if (!over || active.id === over.id) return;
|
|
13554
|
+
const oldIndex = rows.findIndex(
|
|
13555
|
+
(row, i) => getRowKey(row, i) === active.id
|
|
13556
|
+
);
|
|
13557
|
+
const newIndex = rows.findIndex(
|
|
13558
|
+
(row, i) => getRowKey(row, i) === over.id
|
|
13559
|
+
);
|
|
13560
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
13561
|
+
onChange(arrayMove(rows, oldIndex, newIndex));
|
|
13562
|
+
},
|
|
13563
|
+
[rows, getRowKey, onChange]
|
|
13564
|
+
);
|
|
13565
|
+
return (
|
|
13566
|
+
// DndContext wraps the whole component rather than just <TableBody> —
|
|
13567
|
+
// it renders its own hidden accessibility helpers (RestoreFocus,
|
|
13568
|
+
// live-region announcer) as DOM siblings of its children. Nesting it
|
|
13569
|
+
// directly inside <tbody> would make those helpers invalid children of
|
|
13570
|
+
// <tbody> (only <tr> is valid there); wrapping the outer <div> instead
|
|
13571
|
+
// gives them a valid home. <SortableContext> is a plain context
|
|
13572
|
+
// provider with no DOM output of its own, so it can stay right inside
|
|
13573
|
+
// <TableBody>, wrapping only the actual <tr> rows.
|
|
13574
|
+
/* @__PURE__ */ jsx(
|
|
13575
|
+
DndContext,
|
|
13576
|
+
{
|
|
13577
|
+
sensors,
|
|
13578
|
+
collisionDetection: closestCenter,
|
|
13579
|
+
onDragEnd: handleDragEnd,
|
|
13580
|
+
children: /* @__PURE__ */ jsxs("div", { "data-editable-data-table": true, className: cn("flex flex-col gap-1", className), children: [
|
|
13581
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-1", children: [
|
|
13582
|
+
label && /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: label }),
|
|
13583
|
+
/* @__PURE__ */ jsxs(
|
|
13584
|
+
Button,
|
|
13585
|
+
{
|
|
13586
|
+
variant: "ghost",
|
|
13587
|
+
size: "sm",
|
|
13588
|
+
className: "h-6 px-2 text-xs ml-auto",
|
|
13589
|
+
onClick: handleAdd,
|
|
13590
|
+
"aria-label": t("editable_data_table.add"),
|
|
13591
|
+
children: [
|
|
13592
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3 w-3 mr-1" }),
|
|
13593
|
+
t("editable_data_table.add")
|
|
13594
|
+
]
|
|
13595
|
+
}
|
|
13596
|
+
)
|
|
13597
|
+
] }),
|
|
13598
|
+
/* @__PURE__ */ jsxs(Table2, { children: [
|
|
13599
|
+
/* @__PURE__ */ jsx(TableHeader2, { children: /* @__PURE__ */ jsxs(TableRow2, { className: "bg-muted/60 hover:bg-muted/60 border-b-2 border-border", children: [
|
|
13600
|
+
/* @__PURE__ */ jsx(TableHead, { className: "w-6 px-0" }),
|
|
13601
|
+
columns.map((col) => /* @__PURE__ */ jsx(
|
|
13602
|
+
TableHead,
|
|
13603
|
+
{
|
|
13604
|
+
className: cn(
|
|
13605
|
+
"text-[11px] font-semibold uppercase tracking-wide text-foreground px-1 py-1 h-8",
|
|
13606
|
+
col.width
|
|
13607
|
+
),
|
|
13608
|
+
children: col.label
|
|
13609
|
+
},
|
|
13610
|
+
col.key
|
|
13611
|
+
)),
|
|
13612
|
+
/* @__PURE__ */ jsx(TableHead, { className: "w-8 px-0" })
|
|
13613
|
+
] }) }),
|
|
13614
|
+
/* @__PURE__ */ jsxs(TableBody, { children: [
|
|
13615
|
+
rows.length === 0 && /* @__PURE__ */ jsx(TableRow2, { children: /* @__PURE__ */ jsx(
|
|
13616
|
+
TableCell2,
|
|
13617
|
+
{
|
|
13618
|
+
colSpan: columns.length + 2,
|
|
13619
|
+
className: "text-center text-xs text-muted-foreground italic py-4",
|
|
13620
|
+
children: t("editable_data_table.empty")
|
|
13621
|
+
}
|
|
13622
|
+
) }),
|
|
13623
|
+
/* @__PURE__ */ jsx(
|
|
13624
|
+
SortableContext,
|
|
13625
|
+
{
|
|
13626
|
+
items: rowKeys,
|
|
13627
|
+
strategy: verticalListSortingStrategy,
|
|
13628
|
+
children: rows.map((row, rowIndex) => {
|
|
13629
|
+
const key = rowKeys[rowIndex];
|
|
13630
|
+
const isHighlighted = highlightedKey != null && key === highlightedKey;
|
|
13631
|
+
const activeEditColKey = activeEditCell?.row === rowIndex ? activeEditCell.col : null;
|
|
13632
|
+
return /* @__PURE__ */ jsx(
|
|
13633
|
+
EditableTableRow,
|
|
13634
|
+
{
|
|
13635
|
+
row,
|
|
13636
|
+
rowIndex,
|
|
13637
|
+
rowKey: key,
|
|
13638
|
+
isHighlighted,
|
|
13639
|
+
columns,
|
|
13640
|
+
activeEditColKey,
|
|
13641
|
+
deleteLabel: t("editable_data_table.delete"),
|
|
13642
|
+
onCellCommit: handleCellChange,
|
|
13643
|
+
onDeleteRow: handleDelete,
|
|
13644
|
+
onTabOutCell: handleTabOut,
|
|
13645
|
+
onEnterDownCell: handleEnterDown,
|
|
13646
|
+
onPasteCell: handlePaste,
|
|
13647
|
+
onActivated: onCellActivated
|
|
13648
|
+
},
|
|
13649
|
+
key
|
|
13650
|
+
);
|
|
13651
|
+
})
|
|
13652
|
+
}
|
|
13653
|
+
)
|
|
13654
|
+
] })
|
|
13655
|
+
] })
|
|
13656
|
+
] })
|
|
13657
|
+
}
|
|
13658
|
+
)
|
|
13659
|
+
);
|
|
13660
|
+
}
|
|
13129
13661
|
|
|
13130
|
-
export { ANIMATION_PRESETS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AppFooter, AppHeader, Badge, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CELEBRATION_GRADIENT, Calendar, CanvasTextToolbar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CelebrationProvider, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, CommandNodeExtension, CommandPill, CommandPopover, DEFAULT_ANNOUNCE_EVENT, DateRangeSelector, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ErrorBanner, ErrorPage, FunnelChart, HazoBrowserTab, HazoContextProvider, HazoUiConfirmDialog, HazoUiDialog, DialogClose as HazoUiDialogClose, DialogContent as HazoUiDialogContent, DialogDescription as HazoUiDialogDescription, DialogFooter as HazoUiDialogFooter, DialogHeader as HazoUiDialogHeader, DialogOverlay as HazoUiDialogOverlay, DialogPortal as HazoUiDialogPortal, Dialog as HazoUiDialogRoot, DialogTitle as HazoUiDialogTitle, DialogTrigger as HazoUiDialogTrigger, HazoUiEtaProgress, HazoUiFlexInput, HazoUiFlexRadio, HazoUiI18nProvider, HazoUiIcon, HazoUiIconPicker, HazoUiImageCropper, HazoUiImageCropperDialog, HazoUiKanban, HazoUiKanbanFilter, HazoUiMemoryDropdown, HazoUiMultiFilterDialog, HazoUiMultiSortDialog, HazoUiPillRadio, HazoUiProgressBar, HazoUiRte, HazoUiTable, HazoUiTextarea, HazoUiTextbox, HazoUiToaster, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputAffix, InverseSparkline, Label3 as Label, LiveRegion, LoadingTimeout, LocalePicker, Logo, MarkdownEditor, NotificationCountBadge, NotificationItem, NotificationPanel, Popover, PopoverContent, PopoverTrigger, ProgressiveImage, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Command as ShadcnCommand, CommandEmpty as ShadcnCommandEmpty, CommandGroup as ShadcnCommandGroup, CommandInput as ShadcnCommandInput, CommandItem as ShadcnCommandItem, CommandList as ShadcnCommandList, Skeleton, SkeletonBar, SkeletonCircle, SkeletonGroup, SkeletonRect, Slider, Sparkline, Spinner, StackedBars, StatusBadge, Switch, Table2 as Table, TableBody, TableCaption, TableCell2 as TableCell, TableFooter, TableHead, TableHeader2 as TableHeader, TableRow2 as TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, announce, applyKanbanFilter, buttonGroupVariants, celebrate, cn, computeEta, create_command_suggestion_extension, defaultHazoUiT, easeToward, errorToast, format_num, generateUUID, get_hazo_ui_config, get_logger, hasUrlParam, isLucideValue, makeStatusBadge, median, parse_commands_from_text, permissionToast, pick_x_label_indices, readRememberedState, reset_hazo_ui_config, resolve_animation_classes, safeHref, set_hazo_ui_config, set_logger, successToast, text_to_tiptap_content, toggleVariants, upsertEntry as upsertMemoryEntry, useClickOutside, useCopyToClipboard, useDebounce, useErrorDisplay, useEtaProgress, useFullscreen, useHazoEvent, useHazoUiT, useIsMobile, useLoadingState, useLocalStorage, useLongPress, useMediaQuery, useRememberedState, useScrollRestore, useSessionStorage, useViewport, useWakeLock, use_fullscreen, use_wake_lock, writeRememberedState };
|
|
13662
|
+
export { ANIMATION_PRESETS, Accordion, AccordionContent, AccordionItem, AccordionTrigger, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AppFooter, AppHeader, Badge, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CELEBRATION_GRADIENT, Calendar, CanvasTextToolbar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CelebrationProvider, Checkbox, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, CommandNodeExtension, CommandPill, CommandPopover, DEFAULT_ANNOUNCE_EVENT, DateRangeSelector, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EditableDataTable, EmptyState, ErrorBanner, ErrorPage, FunnelChart, HazoBrowserTab, HazoContextProvider, HazoUiConfirmDialog, HazoUiDialog, DialogClose as HazoUiDialogClose, DialogContent as HazoUiDialogContent, DialogDescription as HazoUiDialogDescription, DialogFooter as HazoUiDialogFooter, DialogHeader as HazoUiDialogHeader, DialogOverlay as HazoUiDialogOverlay, DialogPortal as HazoUiDialogPortal, Dialog as HazoUiDialogRoot, DialogTitle as HazoUiDialogTitle, DialogTrigger as HazoUiDialogTrigger, HazoUiEtaProgress, HazoUiFlexInput, HazoUiFlexRadio, HazoUiI18nProvider, HazoUiIcon, HazoUiIconPicker, HazoUiImageCropper, HazoUiImageCropperDialog, HazoUiKanban, HazoUiKanbanFilter, HazoUiMemoryDropdown, HazoUiMultiFilterDialog, HazoUiMultiSortDialog, HazoUiPillRadio, HazoUiProgressBar, HazoUiRte, HazoUiTable, HazoUiTextarea, HazoUiTextbox, HazoUiToaster, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputAffix, InverseSparkline, Label3 as Label, LiveRegion, LoadingTimeout, LocalePicker, Logo, MarkdownEditor, NotificationCountBadge, NotificationItem, NotificationPanel, Popover, PopoverContent, PopoverTrigger, ProgressiveImage, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Command as ShadcnCommand, CommandEmpty as ShadcnCommandEmpty, CommandGroup as ShadcnCommandGroup, CommandInput as ShadcnCommandInput, CommandItem as ShadcnCommandItem, CommandList as ShadcnCommandList, Skeleton, SkeletonBar, SkeletonCircle, SkeletonGroup, SkeletonRect, Slider, Sparkline, Spinner, StackedBars, StatusBadge, Switch, Table2 as Table, TableBody, TableCaption, TableCell2 as TableCell, TableFooter, TableHead, TableHeader2 as TableHeader, TableRow2 as TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, announce, applyKanbanFilter, buttonGroupVariants, celebrate, cn, computeEta, create_command_suggestion_extension, defaultHazoUiT, easeToward, errorToast, format_num, generateUUID, get_hazo_ui_config, get_logger, hasUrlParam, isLucideValue, makeStatusBadge, median, parse_commands_from_text, permissionToast, pick_x_label_indices, readRememberedState, reset_hazo_ui_config, resolve_animation_classes, safeHref, set_hazo_ui_config, set_logger, successToast, text_to_tiptap_content, toggleVariants, upsertEntry as upsertMemoryEntry, useClickOutside, useCopyToClipboard, useDebounce, useErrorDisplay, useEtaProgress, useFullscreen, useHazoEvent, useHazoUiT, useIsMobile, useLoadingState, useLocalStorage, useLongPress, useMediaQuery, useRememberedState, useScrollRestore, useSessionStorage, useViewport, useWakeLock, use_fullscreen, use_wake_lock, writeRememberedState };
|
|
13131
13663
|
//# sourceMappingURL=index.js.map
|
|
13132
13664
|
//# sourceMappingURL=index.js.map
|