sharpcodes-heroui 1.0.1 → 1.0.2

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 (35) hide show
  1. package/dist/components/fields/autocomplete.js +44 -0
  2. package/dist/components/fields/breadcrumbs.js +13 -0
  3. package/dist/components/fields/button.js +9 -0
  4. package/dist/components/fields/date-range.js +42 -0
  5. package/dist/components/fields/index.js +10 -0
  6. package/dist/components/fields/modal.js +13 -0
  7. package/dist/components/fields/number.js +7 -0
  8. package/dist/components/fields/scroll.js +3 -0
  9. package/dist/components/fields/search.js +15 -0
  10. package/dist/components/fields/table/base.js +130 -0
  11. package/dist/components/fields/table/empty.js +8 -0
  12. package/dist/components/fields/table/index.js +70 -0
  13. package/dist/components/fields/table/pagination.js +51 -0
  14. package/dist/components/fields/tabs.js +27 -0
  15. package/dist/components/form-fields/autocomplete.js +45 -0
  16. package/dist/components/form-fields/date-range.js +46 -0
  17. package/dist/components/form-fields/date.js +37 -0
  18. package/dist/components/form-fields/error.js +7 -0
  19. package/dist/components/form-fields/field.js +7 -0
  20. package/dist/components/form-fields/index.js +6 -0
  21. package/dist/components/form-fields/input.js +15 -0
  22. package/dist/components/index.js +2 -0
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +2 -0
  25. package/dist/libs/index.js +2 -0
  26. package/dist/libs/next/axios-client.js +18 -0
  27. package/dist/libs/next/axios-server.js +49 -0
  28. package/dist/libs/next/index.js +2 -0
  29. package/dist/libs/utils/date.js +5 -0
  30. package/dist/libs/utils/form.js +42 -0
  31. package/dist/libs/utils/index.js +3 -0
  32. package/dist/libs/utils/response.js +70 -0
  33. package/package.json +4 -4
  34. package/dist/index.cjs.js +0 -75
  35. package/dist/index.es.js +0 -23088
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import { Autocomplete as HeroUIAutoComplete, EmptyState, Label, ListBox, SearchField, Tag, TagGroup, useFilter, } from "@heroui/react";
5
+ // prettier-ignore
6
+ export const AutoComplete = ({ emptyMessage, items, idKey, nameKey, properties, label, onChange, value }) => {
7
+ const { contains } = useFilter({ sensitivity: "base" });
8
+ const isSingle = properties?.base?.autoComplete?.selectionMode === "single";
9
+ // @ts-expect-error values
10
+ return _jsxs(HeroUIAutoComplete, { selectionMode: "multiple", variant: "secondary", value: isSingle ? value :
11
+ !value ? undefined : _.isArray(value) ? value : [value], ...properties?.base?.autoComplete, onChange: (keys) => {
12
+ if (isSingle)
13
+ // @ts-expect-error keys
14
+ return onChange(keys);
15
+ if (!_.isArray(keys))
16
+ return onChange([]);
17
+ // @ts-expect-error keys
18
+ return onChange(keys);
19
+ }, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(HeroUIAutoComplete.Trigger, { ...properties?.base?.trigger, children: [_jsx(HeroUIAutoComplete.Value, { ...properties?.base?.value, children: ({ defaultChildren, isPlaceholder, state }) => {
20
+ if (isPlaceholder || !state.selectedItems.length)
21
+ return defaultChildren;
22
+ const selectedItemKeys = state.selectedItems.map((item) => item.key);
23
+ return _jsx(TagGroup, { size: "sm", "aria-label": "autocomplete tags", ...properties?.tag?.group, onRemove: (keys) => {
24
+ const keysToRemove = _.toArray(keys);
25
+ const keysCurrent = _.isArray(value) ? value : [value];
26
+ return onChange(keysCurrent.filter((key) => !keysToRemove.includes(key)));
27
+ }, children: _jsx(TagGroup.List, { ...properties?.tag?.list, children: selectedItemKeys.map((selectedItemKey) => {
28
+ const item = items.find((s) => _.get(s, idKey) == selectedItemKey);
29
+ if (!item)
30
+ return null;
31
+ const current = {
32
+ id: _.get(item, idKey),
33
+ name: _.get(item, nameKey)
34
+ };
35
+ return _jsx(Tag, { id: current.id, ...properties?.tag?.item, children: current.name }, current.id);
36
+ }) }) });
37
+ } }), _jsx(HeroUIAutoComplete.Indicator, {})] }), _jsx(HeroUIAutoComplete.Popover, { isNonModal: true, placement: "bottom left", ...properties?.popover?.popover, children: _jsxs(HeroUIAutoComplete.Filter, { filter: contains, ...properties?.popover?.filter, children: [_jsx(SearchField, { autoFocus: true, fullWidth: true, "aria-label": "autocomplete search", name: "search", variant: "secondary", ...properties?.search?.field, children: _jsxs(SearchField.Group, { ...properties?.search?.group, children: [_jsx(SearchField.SearchIcon, { ...properties?.search?.icon }), _jsx(SearchField.Input, { placeholder: "Search...", ...properties?.search?.input }), _jsx(SearchField.ClearButton, { ...properties?.search?.clear })] }) }), _jsx(ListBox, { renderEmptyState: () => _jsx(EmptyState, { ...properties?.list?.empty, children: _jsx("span", { children: emptyMessage || "No results found" }) }), children: items.map((item) => {
38
+ const current = {
39
+ id: _.get(item, idKey),
40
+ name: _.get(item, nameKey)
41
+ };
42
+ return _jsxs(ListBox.Item, { id: current.id, textValue: current.name, "aria-label": current.name, ...properties?.list?.item, children: [_jsx("span", { children: current.name }), _jsx(ListBox.ItemIndicator, { ...properties?.list?.check })] }, current.id);
43
+ }) })] }) })] });
44
+ };
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Breadcrumbs } from "@heroui/react";
4
+ // prettier-ignore
5
+ export const BreadCrumbs = ({ data }) => {
6
+ return _jsx(Breadcrumbs, { children: !data ? null :
7
+ Object.keys(data).map((key, index) => {
8
+ const item = data[key];
9
+ if (!item)
10
+ return;
11
+ return _jsx(Breadcrumbs.Item, { ...item, children: _jsx("span", { children: key }) }, index);
12
+ }) });
13
+ };
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, cn, Spinner, Tooltip, } from "@heroui/react";
4
+ import { Ripple } from "m3-ripple";
5
+ // prettier-ignore
6
+ export const RippledButton = ({ onPress, isLoading, type, tooltipContent, children, properties }) => {
7
+ return _jsxs(Tooltip, { delay: 0, isDisabled: !tooltipContent, ...properties?.tooltip, children: [_jsx(Tooltip.Content, { ...properties?.tooltipContent, children: tooltipContent }), _jsxs(Button, { type: type, variant: "secondary", isPending: isLoading, ...properties?.button, className: cn("font-semibold text-xs active:scale-95 shadow transition-all", properties?.button?.className), onPress: onPress, children: [_jsx(Ripple, { ...properties?.ripple }), isLoading ?
8
+ _jsx(Spinner, { size: "sm", ...properties?.spinner, className: cn("text-accent-foreground", properties?.spinner?.className) }) : null, isLoading && properties?.button?.isIconOnly ? null : children] })] });
9
+ };
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import { DateField, DateRangePicker, Label, RangeCalendar } from "@heroui/react";
5
+ import { parseAbsoluteToLocal } from "@internationalized/date";
6
+ import { toMoment } from "../../libs/utils/date";
7
+ // prettier-ignore
8
+ export const DateRange = ({ onChange, value, properties, label }) => {
9
+ const parsed = {
10
+ start: _.isDate(value?.from) ? parseAbsoluteToLocal(value.from.toISOString()) : undefined,
11
+ end: _.isDate(value?.to) ? parseAbsoluteToLocal(value.to.toISOString()) : undefined,
12
+ };
13
+ return _jsxs(DateRangePicker, { hideTimeZone: true, "aria-label": "date range picker", granularity: "day",
14
+ // defaultValue={parsed.start && parsed.end ? parsed : undefined}
15
+ value: parsed, ...properties?.picker, startName: "from", endName: "to", onChange: (value) => {
16
+ if (!value)
17
+ return onChange?.(null);
18
+ const { start, end } = value;
19
+ const from = toMoment().set({
20
+ month: start.month - 1,
21
+ date: start.day,
22
+ year: start.year,
23
+ hour: start.hour,
24
+ minute: start.minute,
25
+ second: start.second,
26
+ millisecond: start.millisecond
27
+ });
28
+ const to = toMoment().set({
29
+ month: end.month - 1,
30
+ date: end.day,
31
+ year: end.year,
32
+ hour: end.hour,
33
+ minute: end.minute,
34
+ second: end.second,
35
+ millisecond: end.millisecond
36
+ });
37
+ return onChange?.({
38
+ from: from.toDate(),
39
+ to: to.toDate()
40
+ });
41
+ }, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(DateField.Group, { variant: "secondary", ...properties?.input?.group, children: [_jsx(DateField.Input, { ...properties?.input?.input, slot: "start", children: (segment) => _jsx(DateField.Segment, { segment: segment, ...properties?.input?.segment }) }), _jsx(DateRangePicker.RangeSeparator, { ...properties?.input?.separator }), _jsx(DateField.Input, { ...properties?.input?.input, slot: "end", children: (segment) => _jsx(DateField.Segment, { segment: segment, ...properties?.input?.segment }) }), _jsx(DateField.Suffix, { ...properties?.input?.trigger?.suffix, children: _jsx(DateRangePicker.Trigger, { ...properties?.input?.trigger?.trigger, children: _jsx(DateRangePicker.TriggerIndicator, { ...properties?.input?.trigger?.indicator }) }) })] }), _jsx(DateRangePicker.Popover, { isNonModal: true, placement: "bottom end", ...properties?.calendar?.popover, children: _jsxs(RangeCalendar, { "aria-label": "calendar period", ...properties?.calendar?.calendar, children: [_jsxs(RangeCalendar.Header, { ...properties?.calendar?.header, children: [_jsxs(RangeCalendar.YearPickerTrigger, { ...properties?.calendar?.yearPicker?.tigger, children: [_jsx(RangeCalendar.YearPickerTriggerHeading, { ...properties?.calendar?.yearPicker?.heading }), _jsx(RangeCalendar.YearPickerTriggerIndicator, { ...properties?.calendar?.yearPicker?.indicator })] }), _jsx(RangeCalendar.NavButton, { slot: "previous", ...properties?.calendar?.previous }), _jsx(RangeCalendar.NavButton, { slot: "next", ...properties?.calendar?.next })] }), _jsxs(RangeCalendar.Grid, { children: [_jsx(RangeCalendar.GridHeader, { children: (day) => _jsx(RangeCalendar.HeaderCell, { children: day }) }), _jsx(RangeCalendar.GridBody, { children: (date) => _jsx(RangeCalendar.Cell, { date: date }) })] }), _jsx(RangeCalendar.YearPickerGrid, { children: _jsx(RangeCalendar.YearPickerGridBody, { children: ({ year }) => _jsx(RangeCalendar.YearPickerCell, { year: year }) }) })] }) })] });
42
+ };
@@ -0,0 +1,10 @@
1
+ export * from "./autocomplete";
2
+ export * from "./breadcrumbs";
3
+ export * from "./button";
4
+ export * from "./date-range";
5
+ export * from "./modal";
6
+ export * from "./number";
7
+ export * from "./scroll";
8
+ export * from "./search";
9
+ export * from "./table";
10
+ export * from "./tabs";
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn, Description, Modal as HeroUIModal, Separator, } from "@heroui/react";
4
+ import { createElement } from "react";
5
+ // prettier-ignore
6
+ export const Modal = ({ isOpen, icon, footer, onOpenChange, properties, showCloseButton, description, heading, children }) => {
7
+ return _jsx(HeroUIModal, { isOpen: isOpen, onOpenChange: onOpenChange, ...properties?.modal, children: _jsx(HeroUIModal.Backdrop, { isDismissable: false, ...properties?.backdrop, children: _jsx(HeroUIModal.Container, { size: "lg", ...properties?.container, children: _jsxs(HeroUIModal.Dialog, { ...properties?.dialog, children: [!showCloseButton ? null :
8
+ _jsx(HeroUIModal.CloseTrigger, { ...properties?.close, className: cn("text-danger bg-danger-soft", properties?.close?.className) }), _jsxs(HeroUIModal.Header, { ...properties?.header, children: [!icon ? null :
9
+ _jsx(HeroUIModal.Icon, { ...properties?.icon, className: cn("bg-default text-foreground", properties?.icon?.className), children: createElement(icon) }), !heading ? null :
10
+ _jsx(HeroUIModal.Heading, { ...properties?.heading, children: heading }), !description ? null :
11
+ _jsx(Description, { ...properties?.description, className: cn("text-muted text-sm", properties?.description?.className), children: description })] }), _jsx(Separator, { ...properties?.separator, className: cn("mt-5 mb-3", properties?.separator?.className) }), _jsx(HeroUIModal.Body, { ...properties?.body, children: children }), !footer ? null :
12
+ _jsx(HeroUIModal.Footer, { ...properties?.footer, children: footer })] }) }) }) });
13
+ };
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn, Label, NumberField, } from "@heroui/react";
4
+ // prettier-ignore
5
+ export const NumericInput = ({ label, onChange, properties, value }) => {
6
+ return _jsxs(NumberField, { minValue: 0, fullWidth: true, ...properties?.field, className: cn("max-w-32", properties?.field?.className), value: value, onChange: onChange, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(NumberField.Group, { ...properties?.group, children: [_jsx(NumberField.DecrementButton, { ...properties?.decrement }), _jsx(NumberField.Input, { ...properties?.input }), _jsx(NumberField.IncrementButton, { ...properties?.increment })] })] });
7
+ };
@@ -0,0 +1,3 @@
1
+ "use client";
2
+ import { ScrollShadow } from "@heroui/react";
3
+ export { ScrollShadow };
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn, Label, SearchField, } from "@heroui/react";
4
+ import { useEffect, useState } from "react";
5
+ import { useDebounce } from "react-haiku";
6
+ // prettier-ignore
7
+ export const SearchInputField = ({ label, delay, onDebounce, properties }) => {
8
+ const [text, setText] = useState("");
9
+ const debounced = useDebounce(text, delay || 300);
10
+ useEffect(() => {
11
+ onDebounce?.(debounced);
12
+ // eslint-disable-next-line react-hooks/exhaustive-deps
13
+ }, [debounced]);
14
+ return _jsxs(SearchField, { variant: "secondary", "aria-label": "search for keyword", ...properties?.field, value: text, onChange: setText, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(SearchField.Group, { ...properties?.group, children: [_jsx(SearchField.SearchIcon, { ...properties?.icon }), _jsx(SearchField.Input, { placeholder: "Search...", ...properties?.input, className: cn("w-70", properties?.input?.className) }), _jsx(SearchField.ClearButton, { ...properties?.clear })] })] });
15
+ };
@@ -0,0 +1,130 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import z from "zod";
5
+ import { DataTablePagination } from "./pagination";
6
+ import useLocalStorageState from "use-local-storage-state";
7
+ import { Checkbox, cn, Table, TableLayout, Virtualizer } from "@heroui/react";
8
+ import { createColumnHelper, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
9
+ import { ChevronUp } from "lucide-react";
10
+ import { useEffect, useState } from "react";
11
+ // prettier-ignore
12
+ export const DataTable = ({ name, onSelectRows, columns, items, properties, rowIdKey, renderCell, storageBaseName, ...pagination }) => {
13
+ const enableRowSelection = Boolean(onSelectRows);
14
+ const [columnWidths, setColumnWidths] = useLocalStorageState([storageBaseName || "DataTable", name].join("::"), {
15
+ defaultValue: Object.fromEntries(columns.map(({ key }) => [key, null]))
16
+ });
17
+ const [sorting, setSorting] = useState([]);
18
+ const [rowSelection, setRowSelection] = useState({});
19
+ const table = useReactTable({
20
+ getFilteredRowModel: getFilteredRowModel(),
21
+ getCoreRowModel: getCoreRowModel(),
22
+ getPaginationRowModel: getPaginationRowModel(),
23
+ getSortedRowModel: getSortedRowModel(),
24
+ columns: createColumns({ columns }),
25
+ enableRowSelection,
26
+ data: items,
27
+ initialState: {
28
+ pagination: { pageSize: pagination.count.value }
29
+ },
30
+ state: {
31
+ sorting,
32
+ rowSelection,
33
+ columnVisibility: Object.fromEntries(columns.map((col) => [col.key, !col.hide]))
34
+ },
35
+ columnResizeMode: "onEnd",
36
+ onSortingChange: setSorting,
37
+ onRowSelectionChange: setRowSelection,
38
+ });
39
+ const sortDescriptor = toSortDescriptor(sorting);
40
+ useEffect(() => {
41
+ if (!onSelectRows)
42
+ return;
43
+ const arr = z.coerce.number().array().safeParse(Object.keys(rowSelection));
44
+ if (arr.success) {
45
+ const keys = arr.data
46
+ .map((index) => _.get(items[index], rowIdKey) ?? null)
47
+ .filter((item) => item !== null);
48
+ // @ts-expect-error keys
49
+ onSelectRows(keys);
50
+ }
51
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52
+ }, [rowSelection, items, rowIdKey]);
53
+ return _jsx(Virtualizer, { layout: TableLayout, layoutOptions: {
54
+ headingHeight: 42,
55
+ rowHeight: 52,
56
+ ...properties?.virtualization
57
+ }, children: _jsxs(Table, { ...properties?.table, className: cn("min-h-[50dvh]", properties?.table?.className), children: [_jsx(Table.ScrollContainer, { ...properties?.scrollContainer, children: _jsx(Table.ResizableContainer, { onResize: (...map) => {
58
+ const next = Object.fromEntries(Array.from(map.entries())
59
+ .map(([key, value]) => [String(key),
60
+ Object.fromEntries(value)
61
+ ]));
62
+ // @ts-expect-error next[0]
63
+ setColumnWidths(next[0]);
64
+ }, ...properties?.tableReizeableContainer, children: _jsxs(Table.Content, { "aria-label": "tanstack usable data table", sortDescriptor: sortDescriptor, onSortChange: (s) => setSorting(toSortingState(s)), ...properties?.tableContent, className: cn("w-full overflow-x-auto", properties?.tableContent?.className), children: [_jsxs(Table.Header, { ...properties?.tableHeader, children: [!enableRowSelection ? null :
65
+ _jsx(Table.Column, { maxWidth: 20, children: _jsx(InditerminateCheckbox, { id: "all", properties: {
66
+ checkbox: {
67
+ "aria-label": "Select all",
68
+ variant: "primary",
69
+ className: "w-fit"
70
+ }
71
+ },
72
+ // onChange={table.getToggleAllRowsSelectedHandler()}
73
+ onChange: table.toggleAllRowsSelected, isSelected: table.getIsAllRowsSelected(), isIndeterminate: table.getIsSomeRowsSelected() }) }), table.getHeaderGroups().at(0)?.headers.map((header, index) => {
74
+ // @ts-expect-error width
75
+ return _jsx(Table.Column, { id: header.id, isRowHeader: index === 0, allowsSorting: header.column.getCanSort(), ...properties?.tableColumn, defaultWidth: columnWidths?.[header.id], className: cn("rounded-none p-0", properties?.tableColumn?.className), children: ({ sortDirection }) => _jsxs(SortableColumnHeader, { direction: sortDirection, children: [flexRender(header.column.columnDef.header, header.getContext()), _jsx(Table.ColumnResizer, { ...properties?.tableColumnResizer })] }) }, header.id);
76
+ })] }), _jsx(Table.Body, { ...properties?.tableBody, children: table.getRowModel().rows.map((row, rowIndex) => {
77
+ return _jsxs(Table.Row, { id: row.id, ...properties?.tableRow, children: [!enableRowSelection ? null :
78
+ _jsx(Table.Cell, { className: "pr-0", children: _jsx(InditerminateCheckbox, { id: row.id, label: String(_.get(row, rowIdKey)), onChange: row.getToggleSelectedHandler(), isSelected: row.getIsSelected(), isIndeterminate: row.getIsSomeSelected(), properties: {
79
+ checkbox: {
80
+ className: "w-fit"
81
+ }
82
+ } }) }, row.id), row.getVisibleCells().map((cell) => {
83
+ const original = row.original;
84
+ // @ts-expect-error cell
85
+ return _jsx(Table.Cell, { ...properties?.tableCell, className: cn("whitespace-nowrap flex items-center", properties?.tableCell?.className), children: renderCell?.({ row: original, rowIndex })?.[cell.column.id] ??
86
+ flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id);
87
+ })] }, row.id);
88
+ }) })] }) }) }), _jsx(Table.Footer, { ...properties?.tableFooter, className: cn("flex items-end", properties?.tableFooter?.className), children: _jsx(DataTablePagination, { ...pagination, properties: properties, prev: {
89
+ ...pagination.prev,
90
+ onPress: pagination.prev?.onPress ?? table.previousPage,
91
+ canPrev: pagination.prev?.canPrev ?? table.getCanPreviousPage(),
92
+ }, next: {
93
+ ...pagination.next,
94
+ onPress: pagination.next?.onPress ?? table.nextPage,
95
+ canNext: pagination.next?.canNext ?? table.getCanNextPage(),
96
+ } }) })] }) });
97
+ };
98
+ // prettier-ignore
99
+ const createColumns = ({ columns }) => {
100
+ const helper = createColumnHelper();
101
+ // @ts-expect-error columnKey
102
+ return columns.map((column) => helper.accessor(column.key, {
103
+ header: column.title
104
+ }));
105
+ };
106
+ // prettier-ignore
107
+ const toSortDescriptor = (sorting) => {
108
+ const first = _.head(sorting);
109
+ if (!first)
110
+ return undefined;
111
+ return {
112
+ column: first.id,
113
+ direction: first.desc ? "descending" : "ascending",
114
+ };
115
+ };
116
+ // prettier-ignore
117
+ const toSortingState = (descriptor) => {
118
+ return [{ desc: descriptor.direction === "descending", id: String(descriptor.column) }];
119
+ };
120
+ // prettier-ignore
121
+ const SortableColumnHeader = ({ children, direction }) => {
122
+ return _jsxs("div", { className: "flex items-center gap-x-2 p-4 header-cell truncate", children: [children, !direction ? null :
123
+ _jsx(ChevronUp, { className: cn("transform size-3 transition-transform duration-100 ease-out",
124
+ // @ts-expect-error overlap
125
+ direction === "descending" ? "rotate-180" : "") })] });
126
+ };
127
+ // prettier-ignore
128
+ const InditerminateCheckbox = ({ label, properties, ...rest }) => {
129
+ return _jsx(Checkbox, { "aria-label": `Select row ${label || ""}`.trim(), slot: "selection", variant: "secondary", isDisabled: false, ...properties?.checkbox, ...rest, children: _jsx(Checkbox.Control, { children: _jsx(Checkbox.Indicator, {}) }) });
130
+ };
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Surface } from "@heroui/react";
4
+ import { PackageOpenIcon } from "lucide-react";
5
+ // prettier-ignore
6
+ export const RenderEmptyDataTable = ({ isDropTarget, isEmpty }) => {
7
+ return _jsxs(Surface, { variant: "secondary", className: "h-full rounded-2xl flex items-center text-center justify-center flex-col", children: [_jsx(PackageOpenIcon, { className: "size-15 mb-3" }), _jsx("h5", { className: "text-lg", children: "No records found." }), _jsx("p", { className: "text-sm text-zinc-500", children: "Try adjusting your filters or add new entries." })] });
8
+ };
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import z from "zod";
5
+ import { cn } from "@heroui/react";
6
+ import { FilesIcon, InfoIcon, PencilIcon, ShieldAlertIcon, TrashIcon } from "lucide-react";
7
+ import { createElement } from "react";
8
+ import { RippledButton } from "../button";
9
+ import { toMoment } from "../../../libs/utils/date";
10
+ export { DataTable } from "./base";
11
+ export { RenderEmptyDataTable } from "./empty";
12
+ export { DataTablePagination } from "./pagination";
13
+ // prettier-ignore
14
+ export const RenderDateRangeDataTableValue = ({ dates: [from, to] }) => {
15
+ return _jsxs("div", { className: "flex gap-x-2 items-center", children: [_jsx("div", { className: "w-20.5", children: toMoment(from).format("ll") }), _jsx("span", { className: "mr-1", children: "-" }), _jsx("div", { children: toMoment(to).format("ll") })] });
16
+ };
17
+ // prettier-ignore
18
+ export const RenderDateTimeDataTableValue = ({ date }) => {
19
+ return _jsxs("div", { className: "flex gap-x-2 items-center", children: [_jsx("div", { className: "w-20.5", children: toMoment(date).format("ll") }), _jsx("span", { className: "mr-1", children: "-" }), _jsx("div", { children: toMoment(date).format("hh:mm A") })] });
20
+ };
21
+ // prettier-ignore
22
+ export const RenderCurrencyDataTableValue = ({ isNegativeDanger, value }) => {
23
+ if (_.isNil(value))
24
+ return null;
25
+ const schema = z.coerce.number().safeParse(value);
26
+ if (!schema.success)
27
+ return value;
28
+ return _jsx("div", { className: "flex gap-x-2 items-center", children: _jsx("div", { className: cn("w-20.5", isNegativeDanger && schema.data < 0 ? "text-danger" : ""), children: Intl.NumberFormat("en-PH", {
29
+ style: "currency",
30
+ currency: "PHP"
31
+ }).format(schema.data) }) });
32
+ };
33
+ // prettier-ignore
34
+ export const RenderActionDataTableValue = (props) => {
35
+ const options = {
36
+ view: {
37
+ icon: InfoIcon,
38
+ variant: "tertiary"
39
+ },
40
+ edit: {
41
+ icon: PencilIcon,
42
+ variant: "tertiary"
43
+ },
44
+ delete: {
45
+ icon: TrashIcon,
46
+ variant: "danger-soft"
47
+ },
48
+ audit: {
49
+ icon: ShieldAlertIcon,
50
+ variant: "tertiary"
51
+ },
52
+ files: {
53
+ icon: FilesIcon,
54
+ variant: "secondary"
55
+ }
56
+ };
57
+ const items = Object.entries(props).reduce((acc, [k, value]) => {
58
+ const key = k;
59
+ const { onPress, tooltip } = value;
60
+ acc[key] = _jsx(RippledButton, { properties: {
61
+ button: {
62
+ size: "sm",
63
+ isIconOnly: true,
64
+ variant: options[key].variant
65
+ }
66
+ }, tooltipContent: tooltip, onPress: onPress, type: "button", children: createElement(options[key].icon, { className: "size-4" }) }, key);
67
+ return acc;
68
+ }, {});
69
+ return _jsx("div", { className: "flex gap-2", children: Object.values(items) });
70
+ };
@@ -0,0 +1,51 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn, Pagination } from "@heroui/react";
4
+ import { useMemo } from "react";
5
+ import { NumericInput } from "../number";
6
+ import { Ripple } from "m3-ripple";
7
+ // prettier-ignore
8
+ export const DataTablePagination = ({ renderPaginationSummary, gotoPage, locale, count, page, totalPages, properties, next, prev, hidePageNumbers }) => {
9
+ const { displayPage, take } = useMemo(() => ({
10
+ take: page * count.value + 1,
11
+ displayPage: page,
12
+ }), [count.value, page]);
13
+ const getPageNumbers = () => {
14
+ const content = [];
15
+ if (totalPages <= 7) {
16
+ for (let index = 1; index <= totalPages; index++) {
17
+ content.push(index);
18
+ }
19
+ }
20
+ else {
21
+ content.push(1);
22
+ if (page > 3) {
23
+ content.push("...");
24
+ }
25
+ const start = Math.max(2, page - 1);
26
+ const end = Math.min(totalPages - 1, page + 1);
27
+ for (let index = start; index <= end; index++) {
28
+ content.push(index);
29
+ }
30
+ if (page < totalPages - 2) {
31
+ content.push("...");
32
+ }
33
+ content.push(totalPages);
34
+ }
35
+ return content;
36
+ };
37
+ return _jsxs(Pagination, { size: "sm", ...properties?.pagination, className: cn("items-center", properties?.pagination?.className), children: [_jsx(NumericInput, { onChange: count.onChange, value: count.value, properties: {
38
+ field: {
39
+ maxValue: count.max,
40
+ minValue: 1,
41
+ },
42
+ label: { className: "text-zinc-500 text-xs" }
43
+ }, label: "Row count" }), _jsx(Pagination.Summary, { ...properties?.paginationSummary, children: renderPaginationSummary?.(take) ||
44
+ _jsx("div", { className: "flex flex-col", children: _jsx("span", { children: `Page ${displayPage.toLocaleString(locale)} of ${totalPages.toLocaleString(locale)}` }) }) }), _jsxs(Pagination.Content, { ...properties?.paginationContent, children: [_jsx(Pagination.Item, { ...properties?.paginationItem, children: _jsxs(Pagination.Previous, { isDisabled: !prev?.canPrev, onPress: prev?.onPress, ...properties?.paginationPrevButton, children: [_jsx(Ripple, {}), _jsx(Pagination.PreviousIcon, { ...properties?.paginationPrevIcon }), _jsx("span", { children: prev?.text || "Prev" })] }) }), hidePageNumbers ? null :
45
+ getPageNumbers().map((current, index) => {
46
+ const isActive = current === page;
47
+ if (current === "...")
48
+ return _jsx(Pagination.Item, { ...properties?.paginationItem, children: _jsx(Pagination.Ellipsis, {}) }, ["e", index].join(":"));
49
+ return _jsx(Pagination.Item, { ...properties?.paginationItem, children: _jsx(Pagination.Link, { isActive: isActive, onPress: () => gotoPage?.(current), className: cn(isActive ? "bg-accent/5" : ""), children: _jsx("span", { className: isActive ? "text-accent font-bold" : "font-normal", children: current }) }) }, current);
50
+ }), _jsx(Pagination.Item, { ...properties?.paginationItem, children: _jsxs(Pagination.Next, { isDisabled: !next?.canNext, onPress: next?.onPress, ...properties?.paginationNextButton, children: [_jsx(Ripple, {}), _jsx("span", { children: next?.text || "Next" }), _jsx(Pagination.NextIcon, { ...properties?.paginationNextIcon })] }) })] })] });
51
+ };
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import { cn, Tabs as HeroUITabs } from "@heroui/react";
5
+ import { useMemo } from "react";
6
+ // prettier-ignore
7
+ export const Tabs = ({ pathname, renderTab, data, properties }) => {
8
+ const activeKey = useMemo(() => {
9
+ const paths = pathname.split("/");
10
+ const path = paths[paths.length - 1];
11
+ const activeKey = Object.keys(data).find((key) => {
12
+ const item = _.get(data, key);
13
+ if (item.href)
14
+ return item.href.startsWith(pathname);
15
+ return key.toLowerCase() == path.toLowerCase();
16
+ });
17
+ return activeKey;
18
+ }, [pathname, data]);
19
+ return _jsxs(HeroUITabs, { defaultSelectedKey: activeKey, ...properties?.tabs, children: [_jsx(HeroUITabs.ListContainer, { ...properties?.listContainer, children: _jsx(HeroUITabs.List, { "aria-label": "list options", ...properties?.list, children: Object.keys(data).map((k) => {
20
+ const key = k;
21
+ const { href } = data[key];
22
+ return _jsxs(HeroUITabs.Tab, { id: key, href: href, ...properties?.tab, className: cn("w-fit", properties?.tab?.className), children: [renderTab?.[key] ?? key, _jsx(HeroUITabs.Indicator, { ...properties?.indicator })] }, key);
23
+ }) }) }), Object.keys(data).map((key) => {
24
+ const { component } = data[key];
25
+ return _jsx(HeroUITabs.Panel, { id: key, ...properties?.panel, children: component }, key);
26
+ })] });
27
+ };
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import { Autocomplete, cn, EmptyState, Label, ListBox, SearchField, Tag, TagGroup, useFilter, } from "@heroui/react";
5
+ import { FormField } from "./field";
6
+ // prettier-ignore
7
+ export const AutoCompleteFormField = ({ emptyMessage, items, idKey, nameKey, properties, label, ...form }) => {
8
+ const { contains } = useFilter({ sensitivity: "base" });
9
+ const isSingle = properties?.base?.autoComplete?.selectionMode === "single";
10
+ return _jsx(FormField, { ...form, children: ({ field: { value, onChange, ...field }, fieldState }) => {
11
+ // @ts-expect-error keys
12
+ return _jsxs(Autocomplete, { isInvalid: fieldState.invalid, selectionMode: "multiple", variant: "secondary", value: isSingle ? value :
13
+ !value ? undefined : _.isArray(value) ? value : [value], ...properties?.base?.autoComplete, ...field, onChange: (keys) => {
14
+ if (isSingle)
15
+ return onChange(keys);
16
+ if (!_.isArray(keys))
17
+ return onChange([]);
18
+ return onChange(keys);
19
+ }, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(Autocomplete.Trigger, { ...properties?.base?.trigger, className: cn("py-0 items-center", properties?.base?.trigger?.className), children: [_jsx(Autocomplete.Value, { ...properties?.base?.value, children: ({ defaultChildren, isPlaceholder, state }) => {
20
+ if (isPlaceholder || !state.selectedItems.length)
21
+ return defaultChildren;
22
+ const selectedItemKeys = state.selectedItems.map((item) => item.key);
23
+ return _jsx(TagGroup, { size: "lg", "aria-label": "autocomplete tags", ...properties?.tag?.group, onRemove: (keys) => {
24
+ const keysToRemove = _.toArray(keys);
25
+ const keysCurrent = _.isArray(value) ? value : [value];
26
+ return onChange(keysCurrent.filter((key) => !keysToRemove.includes(key)));
27
+ }, children: _jsx(TagGroup.List, { ...properties?.tag?.list, children: selectedItemKeys.map((selectedItemKey) => {
28
+ const item = items.find((s) => _.get(s, idKey) == selectedItemKey);
29
+ if (!item)
30
+ return null;
31
+ const current = {
32
+ id: _.get(item, idKey),
33
+ name: _.get(item, nameKey)
34
+ };
35
+ return _jsx(Tag, { id: current.id, ...properties?.tag?.item, className: cn(isSingle ? "[&_.close-button]:hidden" : undefined, "bg-transparent!", properties?.tag?.item?.className), textValue: current.name, children: _jsx("span", { children: current.name }) }, current.id);
36
+ }) }) });
37
+ } }), _jsx(Autocomplete.Indicator, {})] }), _jsx(Autocomplete.Popover, { isNonModal: true, placement: "bottom left", ...properties?.popover?.popover, children: _jsxs(Autocomplete.Filter, { filter: contains, ...properties?.popover?.filter, children: [_jsx(SearchField, { autoFocus: true, fullWidth: true, "aria-label": "autocomplete search", name: "search", variant: "secondary", ...properties?.search?.field, children: _jsxs(SearchField.Group, { ...properties?.search?.group, children: [_jsx(SearchField.SearchIcon, { ...properties?.search?.icon }), _jsx(SearchField.Input, { placeholder: "Search...", ...properties?.search?.input }), _jsx(SearchField.ClearButton, { ...properties?.search?.clear })] }) }), _jsx(ListBox, { renderEmptyState: () => _jsx(EmptyState, { ...properties?.list?.empty, children: _jsx("span", { children: emptyMessage || "No results found" }) }), children: items.map((item) => {
38
+ const current = {
39
+ id: _.get(item, idKey),
40
+ name: _.get(item, nameKey)
41
+ };
42
+ return _jsxs(ListBox.Item, { id: current.id, textValue: current.name, "aria-label": current.name, ...properties?.list?.item, children: [_jsx("span", { children: current.name }), _jsx(ListBox.ItemIndicator, { ...properties?.list?.check })] }, current.id);
43
+ }) })] }) })] });
44
+ } });
45
+ };
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import _ from "lodash";
4
+ import { FormField } from "./field";
5
+ import { DateField, DateRangePicker, Label, RangeCalendar } from "@heroui/react";
6
+ import { parseAbsoluteToLocal } from "@internationalized/date";
7
+ import { FormFieldErrorMessage } from "./error";
8
+ import { toMoment } from "../../libs/utils/date";
9
+ // prettier-ignore
10
+ export const DateRangeFormField = ({ startName, endName, properties, label, ...form }) => {
11
+ return _jsx(FormField, { ...form, children: ({ field: { onChange, value, ...field }, fieldState }) => {
12
+ const start = _.get(value, startName.split(".").slice(1).join("."));
13
+ const end = _.get(value, startName.split(".").slice(1).join("."));
14
+ const parsed = {
15
+ start: _.isDate(start) ? parseAbsoluteToLocal(start.toISOString()) : undefined,
16
+ end: _.isDate(end) ? parseAbsoluteToLocal(end.toISOString()) : undefined,
17
+ };
18
+ return _jsxs(DateRangePicker, { hideTimeZone: true, isInvalid: fieldState.invalid, "aria-label": "date range picker", granularity: "day", defaultValue: parsed.start && parsed.end ? parsed : undefined, ...properties?.picker, ...field, startName: startName, endName: endName, onChange: (value) => {
19
+ if (!value)
20
+ return onChange(null);
21
+ const { start, end } = value;
22
+ const from = toMoment().set({
23
+ month: start.month - 1,
24
+ date: start.day,
25
+ year: start.year,
26
+ hour: start.hour,
27
+ minute: start.minute,
28
+ second: start.second,
29
+ millisecond: start.millisecond
30
+ });
31
+ const to = toMoment().set({
32
+ month: end.month - 1,
33
+ date: end.day,
34
+ year: end.year,
35
+ hour: end.hour,
36
+ minute: end.minute,
37
+ second: end.second,
38
+ millisecond: end.millisecond
39
+ });
40
+ return onChange({
41
+ from: from.toDate(),
42
+ to: to.toDate()
43
+ });
44
+ }, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(DateField.Group, { variant: "secondary", ...properties?.input?.group, children: [_jsx(DateField.Input, { ...properties?.input?.input, slot: "start", children: (segment) => _jsx(DateField.Segment, { segment: segment, ...properties?.input?.segment }) }), _jsx(DateRangePicker.RangeSeparator, { ...properties?.input?.separator }), _jsx(DateField.Input, { ...properties?.input?.input, slot: "end", children: (segment) => _jsx(DateField.Segment, { segment: segment, ...properties?.input?.segment }) }), _jsx(DateField.Suffix, { ...properties?.input?.trigger?.suffix, children: _jsx(DateRangePicker.Trigger, { ...properties?.input?.trigger?.trigger, children: _jsx(DateRangePicker.TriggerIndicator, { ...properties?.input?.trigger?.indicator }) }) })] }), _jsx(FormFieldErrorMessage, { fieldState: fieldState, properties: { error: properties?.error } }), _jsx(DateRangePicker.Popover, { isNonModal: true, placement: "bottom end", ...properties?.calendar?.popover, children: _jsxs(RangeCalendar, { "aria-label": "calendar period", ...properties?.calendar?.calendar, children: [_jsxs(RangeCalendar.Header, { ...properties?.calendar?.header, children: [_jsxs(RangeCalendar.YearPickerTrigger, { ...properties?.calendar?.yearPicker?.tigger, children: [_jsx(RangeCalendar.YearPickerTriggerHeading, { ...properties?.calendar?.yearPicker?.heading }), _jsx(RangeCalendar.YearPickerTriggerIndicator, { ...properties?.calendar?.yearPicker?.indicator })] }), _jsx(RangeCalendar.NavButton, { slot: "previous", ...properties?.calendar?.previous }), _jsx(RangeCalendar.NavButton, { slot: "next", ...properties?.calendar?.next })] }), _jsxs(RangeCalendar.Grid, { children: [_jsx(RangeCalendar.GridHeader, { children: (day) => _jsx(RangeCalendar.HeaderCell, { children: day }) }), _jsx(RangeCalendar.GridBody, { children: (date) => _jsx(RangeCalendar.Cell, { date: date }) })] }), _jsx(RangeCalendar.YearPickerGrid, { children: _jsx(RangeCalendar.YearPickerGridBody, { children: ({ year }) => _jsx(RangeCalendar.YearPickerCell, { year: year }) }) })] }) })] });
45
+ } });
46
+ };
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { FormField } from "./field";
4
+ import { DateField, DatePicker, Calendar, Label, TimeField, cn } from "@heroui/react";
5
+ import { parseAbsoluteToLocal } from "@internationalized/date";
6
+ import { FormFieldErrorMessage } from "./error";
7
+ import { toMoment } from "../../libs/utils/date";
8
+ // prettier-ignore
9
+ export const DateFormField = ({ label, properties, ...form }) => {
10
+ const showTimePicker = properties?.picker?.granularity && ["hour", "minute", "second"].includes(properties.picker.granularity);
11
+ return _jsx(FormField, { ...form, children: ({ field: { value, onChange, ...field }, fieldState }) => _jsxs(DatePicker, { hideTimeZone: true, isInvalid: fieldState.invalid, "aria-label": label || "date picker", value: !value ? undefined : parseAbsoluteToLocal(value.toISOString()), shouldCloseOnSelect: !showTimePicker, ...properties?.picker, ...field, onChange: (value) => {
12
+ if (!value)
13
+ return onChange(null);
14
+ const date = toMoment().set({
15
+ month: value.month - 1,
16
+ date: value.day,
17
+ year: value.year,
18
+ hour: value.hour,
19
+ minute: value.minute,
20
+ second: value.second,
21
+ millisecond: value.millisecond
22
+ });
23
+ return onChange(date.toDate());
24
+ }, children: [_jsx(Label, { ...properties?.label, children: label }), _jsxs(DateField.Group, { variant: "secondary", ...properties?.input?.group, children: [_jsx(DateField.Input, { ...properties?.input?.input, children: (segment) => _jsx(DateField.Segment, { segment: segment, ...properties?.input?.segment }) }), _jsx(DateField.Suffix, { ...properties?.input?.trigger?.suffix, children: _jsx(DatePicker.Trigger, { ...properties?.input?.trigger?.trigger, children: _jsx(DatePicker.TriggerIndicator, { ...properties?.input?.trigger?.indicator }) }) })] }), _jsx(FormFieldErrorMessage, { fieldState: fieldState, properties: { error: properties?.error } }), _jsxs(DatePicker.Popover, { isNonModal: true, placement: "bottom end", ...properties?.calendar?.popover, className: cn("min-w-64", properties?.calendar?.popover?.className), children: [_jsxs(Calendar, { "aria-label": "calendar period", ...properties?.calendar?.calendar, children: [_jsxs(Calendar.Header, { ...properties?.calendar?.header, children: [_jsxs(Calendar.YearPickerTrigger, { ...properties?.calendar?.yearPicker?.tigger, children: [_jsx(Calendar.YearPickerTriggerHeading, { ...properties?.calendar?.yearPicker?.heading }), _jsx(Calendar.YearPickerTriggerIndicator, { ...properties?.calendar?.yearPicker?.indicator })] }), _jsx(Calendar.NavButton, { slot: "previous", ...properties?.calendar?.previous }), _jsx(Calendar.NavButton, { slot: "next", ...properties?.calendar?.next })] }), _jsxs(Calendar.Grid, { children: [_jsx(Calendar.GridHeader, { children: (day) => _jsx(Calendar.HeaderCell, { children: day }) }), _jsx(Calendar.GridBody, { children: (date) => _jsx(Calendar.Cell, { date: date }) })] }), _jsx(Calendar.YearPickerGrid, { children: _jsx(Calendar.YearPickerGridBody, { children: ({ year }) => _jsx(Calendar.YearPickerCell, { year: year }) }) })] }), showTimePicker ?
25
+ _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, {}), _jsx(TimeField, { defaultValue: value, shouldForceLeadingZeros: properties?.picker?.shouldForceLeadingZeros, hideTimeZone: properties?.picker?.hideTimeZone, "aria-label": label?.concat(" time ") || "time picker", hourCycle: properties?.picker?.hourCycle, onChange: (timeValue) => {
26
+ if (!timeValue)
27
+ return;
28
+ const date = toMoment(value).set({
29
+ hour: timeValue.hour,
30
+ minute: timeValue.minute,
31
+ second: timeValue.second,
32
+ millisecond: timeValue.millisecond
33
+ });
34
+ return onChange(date.toDate());
35
+ }, children: _jsx(TimeField.Group, { variant: "secondary", children: _jsx(TimeField.Input, { children: (segment) => _jsx(TimeField.Segment, { segment: segment }) }) }) })] })
36
+ : null] })] }) });
37
+ };
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { FieldError } from "@heroui/react";
4
+ // prettier-ignore
5
+ export const FormFieldErrorMessage = ({ fieldState, properties }) => {
6
+ return _jsxs(FieldError, { ...properties?.error, children: [" ", fieldState.error?.message || fieldState.error?.root?.message] });
7
+ };