@timmbr/ui 1.13.2 → 1.15.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.
Files changed (64) hide show
  1. package/dist/components/AttributeValueField/AttributeValueField.d.ts +20 -0
  2. package/dist/components/AttributeValueField/AttributeValueField.d.ts.map +1 -0
  3. package/dist/components/AttributeValueField/AttributeValueField.js +130 -0
  4. package/dist/components/AttributeValueField/index.d.ts +2 -0
  5. package/dist/components/AttributeValueField/index.d.ts.map +1 -0
  6. package/dist/components/DataTable/DataTable.d.ts +10 -0
  7. package/dist/components/DataTable/DataTable.d.ts.map +1 -0
  8. package/dist/components/DataTable/DataTable.js +177 -0
  9. package/dist/components/DataTable/DataTable.types.d.ts +42 -0
  10. package/dist/components/DataTable/DataTable.types.d.ts.map +1 -0
  11. package/dist/components/DataTable/index.d.ts +3 -0
  12. package/dist/components/DataTable/index.d.ts.map +1 -0
  13. package/dist/components/RichTextEditor/RichTextContent.d.ts +8 -0
  14. package/dist/components/RichTextEditor/RichTextContent.d.ts.map +1 -0
  15. package/dist/components/RichTextEditor/RichTextContent.js +18 -0
  16. package/dist/components/RichTextEditor/RichTextEditor.context.d.ts +6 -0
  17. package/dist/components/RichTextEditor/RichTextEditor.context.d.ts.map +1 -0
  18. package/dist/components/RichTextEditor/RichTextEditor.context.js +14 -0
  19. package/dist/components/RichTextEditor/RichTextEditor.d.ts +4 -0
  20. package/dist/components/RichTextEditor/RichTextEditor.d.ts.map +1 -0
  21. package/dist/components/RichTextEditor/RichTextEditor.helpers.d.ts +28 -0
  22. package/dist/components/RichTextEditor/RichTextEditor.helpers.d.ts.map +1 -0
  23. package/dist/components/RichTextEditor/RichTextEditor.helpers.js +52 -0
  24. package/dist/components/RichTextEditor/RichTextEditor.js +156 -0
  25. package/dist/components/RichTextEditor/RichTextEditor.styles.d.ts +10 -0
  26. package/dist/components/RichTextEditor/RichTextEditor.styles.d.ts.map +1 -0
  27. package/dist/components/RichTextEditor/RichTextEditor.styles.js +95 -0
  28. package/dist/components/RichTextEditor/RichTextEditor.types.d.ts +73 -0
  29. package/dist/components/RichTextEditor/RichTextEditor.types.d.ts.map +1 -0
  30. package/dist/components/RichTextEditor/RichTextJsonContent.d.ts +9 -0
  31. package/dist/components/RichTextEditor/RichTextJsonContent.d.ts.map +1 -0
  32. package/dist/components/RichTextEditor/RichTextJsonContent.js +27 -0
  33. package/dist/components/RichTextEditor/index.d.ts +14 -0
  34. package/dist/components/RichTextEditor/index.d.ts.map +1 -0
  35. package/dist/components/RichTextEditor/subcomponents/RteCharCount.d.ts +4 -0
  36. package/dist/components/RichTextEditor/subcomponents/RteCharCount.d.ts.map +1 -0
  37. package/dist/components/RichTextEditor/subcomponents/RteCharCount.js +37 -0
  38. package/dist/components/RichTextEditor/subcomponents/RteEmojiPicker.d.ts +3 -0
  39. package/dist/components/RichTextEditor/subcomponents/RteEmojiPicker.d.ts.map +1 -0
  40. package/dist/components/RichTextEditor/subcomponents/RteEmojiPicker.js +274 -0
  41. package/dist/components/RichTextEditor/subcomponents/RteLinkPopover.d.ts +3 -0
  42. package/dist/components/RichTextEditor/subcomponents/RteLinkPopover.d.ts.map +1 -0
  43. package/dist/components/RichTextEditor/subcomponents/RteLinkPopover.js +93 -0
  44. package/dist/components/RichTextEditor/subcomponents/RteToolbar.d.ts +7 -0
  45. package/dist/components/RichTextEditor/subcomponents/RteToolbar.d.ts.map +1 -0
  46. package/dist/components/RichTextEditor/subcomponents/RteToolbar.js +234 -0
  47. package/dist/components/RichTextEditor/subcomponents/RteToolbarButton.d.ts +4 -0
  48. package/dist/components/RichTextEditor/subcomponents/RteToolbarButton.d.ts.map +1 -0
  49. package/dist/components/RichTextEditor/subcomponents/RteToolbarButton.js +37 -0
  50. package/dist/components/RichTextEditor/subcomponents/RteToolbarGroup.d.ts +4 -0
  51. package/dist/components/RichTextEditor/subcomponents/RteToolbarGroup.d.ts.map +1 -0
  52. package/dist/components/RichTextEditor/subcomponents/RteToolbarGroup.js +13 -0
  53. package/dist/components/Table/Table.d.ts.map +1 -1
  54. package/dist/components/Table/Table.js +14 -7
  55. package/dist/components/Table/Table.styles.js +2 -2
  56. package/dist/components/Table/Table.types.d.ts +1 -0
  57. package/dist/components/Table/Table.types.d.ts.map +1 -1
  58. package/dist/components/Table/TablePagination.js +3 -3
  59. package/dist/index.d.ts +3 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +15 -0
  62. package/dist/node_modules/.pnpm/@tanstack_react-table@8.21._59ea1c5c486c125464e3b5e1938c78d1/node_modules/@tanstack/react-table/build/lib/index.js +74 -0
  63. package/dist/node_modules/.pnpm/@tanstack_table-core@8.21.3/node_modules/@tanstack/table-core/build/lib/index.js +3027 -0
  64. package/package.json +15 -5
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ export type AttributeValueFieldType = "STRING" | "INTEGER" | "DECIMAL" | "LIST" | "BOOLEAN";
3
+ export interface AttributeValueFieldOption {
4
+ label: string;
5
+ slug: string;
6
+ swatchHex?: string | null;
7
+ }
8
+ export interface AttributeValueFieldProps {
9
+ type: AttributeValueFieldType;
10
+ value: unknown;
11
+ onChange: (value: unknown) => void;
12
+ options?: AttributeValueFieldOption[];
13
+ unit?: string | null;
14
+ disabled?: boolean;
15
+ size?: "sm" | "md";
16
+ className?: string;
17
+ id?: string;
18
+ }
19
+ export declare const AttributeValueField: React.FC<AttributeValueFieldProps>;
20
+ //# sourceMappingURL=AttributeValueField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AttributeValueField.d.ts","sourceRoot":"","sources":["../../../src/components/AttributeValueField/AttributeValueField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,SAAS,GACT,SAAS,GACT,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAiIlE,CAAC"}
@@ -0,0 +1,130 @@
1
+ "use client";
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { cn } from '@timmbr/utils';
4
+ import { Switch } from '../Switch/Switch.js';
5
+ import { Inline } from '../Inline/Inline.js';
6
+ import { Input } from '../Input/Input.js';
7
+ import { Text } from '../Text/Text.js';
8
+ import { Stack } from '../Stack/Stack.js';
9
+ import { Checkbox } from '../Checkbox/Checkbox.js';
10
+ import { Select } from '../Select/Select.js';
11
+
12
+ const AttributeValueField = ({
13
+ type,
14
+ value,
15
+ onChange,
16
+ options = [],
17
+ unit,
18
+ disabled,
19
+ size = "sm",
20
+ className,
21
+ id
22
+ }) => {
23
+ const inputSize = size === "sm" ? "sm" : "md";
24
+ if (type === "BOOLEAN") {
25
+ const checked = value === true || value === "true";
26
+ return /* @__PURE__ */ jsx(
27
+ Switch,
28
+ {
29
+ id,
30
+ checked,
31
+ onCheckedChange: (next) => onChange(next),
32
+ disabled,
33
+ className
34
+ }
35
+ );
36
+ }
37
+ if (type === "INTEGER" || type === "DECIMAL") {
38
+ return /* @__PURE__ */ jsxs(Inline, { gap: 2, align: "center", className: cn("w-full", className), children: [
39
+ /* @__PURE__ */ jsx(
40
+ Input,
41
+ {
42
+ id,
43
+ type: "number",
44
+ size: inputSize,
45
+ step: type === "INTEGER" ? 1 : "any",
46
+ value: value === void 0 || value === null ? "" : String(value),
47
+ onChange: (e) => {
48
+ const raw = e.target.value;
49
+ if (raw === "") {
50
+ onChange("");
51
+ return;
52
+ }
53
+ onChange(type === "INTEGER" ? parseInt(raw, 10) : parseFloat(raw));
54
+ },
55
+ disabled,
56
+ className: "flex-1"
57
+ }
58
+ ),
59
+ unit ? /* @__PURE__ */ jsx(Text, { variant: "caption", foreground: "muted", className: "shrink-0", children: unit }) : null
60
+ ] });
61
+ }
62
+ if (type === "LIST" && options.length > 0) {
63
+ const selected = Array.isArray(value) ? value : value ? [String(value)] : [];
64
+ return /* @__PURE__ */ jsx(Stack, { gap: 2, className, children: options.map((opt) => {
65
+ const optValue = opt.slug || opt.label;
66
+ const isChecked = selected.includes(optValue);
67
+ return /* @__PURE__ */ jsxs(Inline, { gap: 2, align: "center", children: [
68
+ /* @__PURE__ */ jsx(
69
+ Checkbox,
70
+ {
71
+ id: id ? `${id}-${opt.slug}` : void 0,
72
+ checked: isChecked,
73
+ disabled,
74
+ onCheckedChange: (checked) => {
75
+ if (checked) {
76
+ onChange([...selected, optValue]);
77
+ } else {
78
+ onChange(selected.filter((v) => v !== optValue));
79
+ }
80
+ }
81
+ }
82
+ ),
83
+ opt.swatchHex ? /* @__PURE__ */ jsx(
84
+ "span",
85
+ {
86
+ className: "size-4 rounded-sm border border-border shrink-0",
87
+ style: { backgroundColor: opt.swatchHex }
88
+ }
89
+ ) : null,
90
+ /* @__PURE__ */ jsx(Text, { variant: "body-2", children: opt.label })
91
+ ] }, opt.slug);
92
+ }) });
93
+ }
94
+ if (type === "LIST" || type === "STRING") {
95
+ if (options.length > 0) {
96
+ const selectValue = value === void 0 || value === null ? "" : String(value);
97
+ return /* @__PURE__ */ jsx(
98
+ Select,
99
+ {
100
+ id,
101
+ size: inputSize,
102
+ value: selectValue,
103
+ onValueChange: (v) => onChange(v),
104
+ disabled,
105
+ className,
106
+ options: [
107
+ { value: "", label: "Select…" },
108
+ ...options.map((o) => ({
109
+ value: o.slug || o.label,
110
+ label: o.label
111
+ }))
112
+ ]
113
+ }
114
+ );
115
+ }
116
+ }
117
+ return /* @__PURE__ */ jsx(
118
+ Input,
119
+ {
120
+ id,
121
+ size: inputSize,
122
+ value: value === void 0 || value === null ? "" : String(value),
123
+ onChange: (e) => onChange(e.target.value),
124
+ disabled,
125
+ className
126
+ }
127
+ );
128
+ };
129
+
130
+ export { AttributeValueField };
@@ -0,0 +1,2 @@
1
+ export { AttributeValueField, type AttributeValueFieldProps, type AttributeValueFieldType, type AttributeValueFieldOption, } from "./AttributeValueField";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AttributeValueField/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,GAC/B,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ import { flexRender, type ColumnDef } from '@tanstack/react-table';
3
+ import type { DataTableProps } from './DataTable.types';
4
+ export declare function DataTable<TData, TValue = unknown>({ data, columns, sorting, onSortingChange, rowSelection, onRowSelectionChange, className, containerClassName, bordered, variant, size, emptyMessage, isLoading, getRowId, onRowClick, stickyHeader, showScrollIndicator, motion: motionProp, }: DataTableProps<TData, TValue>): React.JSX.Element;
5
+ export declare namespace DataTable {
6
+ var displayName: string;
7
+ }
8
+ export { flexRender };
9
+ export type { ColumnDef };
10
+ //# sourceMappingURL=DataTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DataTable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAIL,UAAU,EAGV,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAc/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACjD,IAAI,EACJ,OAAO,EACP,OAAO,EACP,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,SAAS,EACT,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,YAAkC,EAClC,SAAiB,EACjB,QAAQ,EACR,UAAU,EACV,YAAmB,EACnB,mBAA0B,EAC1B,MAAM,EAAE,UAAU,GACnB,EAAE,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,qBA+L/B;yBAlNe,SAAS;;;AAsNzB,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -0,0 +1,177 @@
1
+ "use client";
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import { useReactTable, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
5
+ export { flexRender } from '@tanstack/react-table';
6
+ import { ChevronUp, ChevronDown, ChevronsUpDown } from '@timmbr/icons';
7
+ import { cn } from '@timmbr/utils';
8
+ import { motion } from '@timmbr/motion';
9
+ import { resolveMotion } from '../../types/motion.js';
10
+ import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../Table/Table.js';
11
+ import { useGlobalAnimation } from '../../providers/AnimationProvider.js';
12
+
13
+ function DataTable({
14
+ data,
15
+ columns,
16
+ sorting,
17
+ onSortingChange,
18
+ rowSelection,
19
+ onRowSelectionChange,
20
+ className,
21
+ containerClassName,
22
+ bordered,
23
+ variant,
24
+ size,
25
+ emptyMessage = "No results found.",
26
+ isLoading = false,
27
+ getRowId,
28
+ onRowClick,
29
+ stickyHeader = true,
30
+ showScrollIndicator = true,
31
+ motion: motionProp
32
+ }) {
33
+ const [internalSorting, setInternalSorting] = React.useState([]);
34
+ const [internalRowSelection, setInternalRowSelection] = React.useState({});
35
+ const scrollContainerRef = React.useRef(null);
36
+ const globalMotion = useGlobalAnimation();
37
+ const { shouldAnimate } = resolveMotion(motionProp, globalMotion);
38
+ const [scrollProgress, setScrollProgress] = React.useState(0);
39
+ React.useEffect(() => {
40
+ const el = scrollContainerRef.current;
41
+ if (!el) return;
42
+ const updateProgress = () => {
43
+ const maxScroll = el.scrollHeight - el.clientHeight;
44
+ setScrollProgress(maxScroll > 0 ? el.scrollTop / maxScroll : 0);
45
+ };
46
+ updateProgress();
47
+ el.addEventListener("scroll", updateProgress, { passive: true });
48
+ const resizeObserver = new ResizeObserver(updateProgress);
49
+ resizeObserver.observe(el);
50
+ return () => {
51
+ el.removeEventListener("scroll", updateProgress);
52
+ resizeObserver.disconnect();
53
+ };
54
+ }, [data]);
55
+ React.useEffect(() => {
56
+ if (typeof scrollContainerRef.current?.scrollTo === "function") {
57
+ scrollContainerRef.current.scrollTo({ top: 0, behavior: "smooth" });
58
+ }
59
+ }, [data]);
60
+ const table = useReactTable({
61
+ data,
62
+ columns,
63
+ state: {
64
+ sorting: sorting !== void 0 ? sorting : internalSorting,
65
+ rowSelection: rowSelection !== void 0 ? rowSelection : internalRowSelection
66
+ },
67
+ onSortingChange: onSortingChange ?? setInternalSorting,
68
+ onRowSelectionChange: onRowSelectionChange ?? setInternalRowSelection,
69
+ getCoreRowModel: getCoreRowModel(),
70
+ getSortedRowModel: getSortedRowModel(),
71
+ enableRowSelection: true,
72
+ getRowId
73
+ });
74
+ const resolvedContainerClassName = cn(
75
+ stickyHeader && "min-h-0 h-full",
76
+ containerClassName
77
+ );
78
+ return /* @__PURE__ */ jsxs(
79
+ Table,
80
+ {
81
+ className: cn(stickyHeader && "border-separate border-spacing-0", className),
82
+ containerClassName: resolvedContainerClassName,
83
+ containerRef: scrollContainerRef,
84
+ bordered,
85
+ variant,
86
+ size,
87
+ children: [
88
+ showScrollIndicator && shouldAnimate && /* @__PURE__ */ jsx("caption", { className: "p-0 caption-top", children: /* @__PURE__ */ jsx(
89
+ motion.div,
90
+ {
91
+ style: { scaleX: scrollProgress },
92
+ className: "sticky top-0 z-30 h-0.5 w-full bg-primary origin-left pointer-events-none transition-transform duration-150 ease-out"
93
+ }
94
+ ) }),
95
+ /* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { className: "border-b border-border hover:bg-transparent", children: headerGroup.headers.map((header) => {
96
+ const canSort = header.column.getCanSort();
97
+ const isSorted = header.column.getIsSorted();
98
+ return /* @__PURE__ */ jsx(
99
+ TableHead,
100
+ {
101
+ colSpan: header.colSpan,
102
+ className: cn(
103
+ stickyHeader ? "sticky top-0 z-20 bg-card border-b border-border" : "static shadow-none",
104
+ canSort && "cursor-pointer select-none"
105
+ ),
106
+ onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
107
+ children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
108
+ /* @__PURE__ */ jsx("span", { children: flexRender(
109
+ header.column.columnDef.header,
110
+ header.getContext()
111
+ ) }),
112
+ canSort && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center text-muted-foreground", children: isSorted === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "size-3.5 text-foreground" }) : isSorted === "desc" ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 text-foreground" }) : /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5 opacity-40 hover:opacity-100 transition-opacity" }) })
113
+ ] })
114
+ },
115
+ header.id
116
+ );
117
+ }) }, headerGroup.id)) }),
118
+ /* @__PURE__ */ jsx(TableBody, { children: isLoading ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
119
+ TableCell,
120
+ {
121
+ colSpan: columns.length,
122
+ className: "h-28 text-center text-muted-foreground",
123
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2", children: [
124
+ /* @__PURE__ */ jsx("span", { className: "inline-block size-4 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
125
+ /* @__PURE__ */ jsx("span", { children: "Loading..." })
126
+ ] })
127
+ }
128
+ ) }) : table.getRowModel().rows.length > 0 ? table.getRowModel().rows.map((row, index) => {
129
+ const isSelected = row.getIsSelected();
130
+ const cells = row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
131
+ if (shouldAnimate) {
132
+ return /* @__PURE__ */ jsx(
133
+ motion.tr,
134
+ {
135
+ "data-state": isSelected ? "selected" : void 0,
136
+ initial: { opacity: 0, y: 4 },
137
+ animate: { opacity: 1, y: 0 },
138
+ transition: {
139
+ duration: 0.2,
140
+ ease: [0.16, 1, 0.3, 1],
141
+ delay: Math.min(index * 0.015, 0.15)
142
+ },
143
+ className: cn(
144
+ "border-b border-grey-200 dark:border-grey-800 transition-colors data-[state=selected]:bg-primary/5 hover:bg-grey-50/80 dark:hover:bg-grey-900/60",
145
+ onRowClick && "cursor-pointer"
146
+ ),
147
+ onClick: () => onRowClick?.(row),
148
+ children: cells
149
+ },
150
+ row.id
151
+ );
152
+ }
153
+ return /* @__PURE__ */ jsx(
154
+ TableRow,
155
+ {
156
+ "data-state": isSelected ? "selected" : void 0,
157
+ className: cn(onRowClick && "cursor-pointer"),
158
+ onClick: () => onRowClick?.(row),
159
+ children: cells
160
+ },
161
+ row.id
162
+ );
163
+ }) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
164
+ TableCell,
165
+ {
166
+ colSpan: columns.length,
167
+ className: "h-28 text-center text-muted-foreground",
168
+ children: emptyMessage
169
+ }
170
+ ) }) })
171
+ ]
172
+ }
173
+ );
174
+ }
175
+ DataTable.displayName = "DataTable";
176
+
177
+ export { DataTable };
@@ -0,0 +1,42 @@
1
+ import type * as React from 'react';
2
+ import type { ColumnDef, HeaderContext, CellContext, SortingState, RowSelectionState, OnChangeFn, Row, Table as ReactTableInstance } from '@tanstack/react-table';
3
+ import type { TableProps } from '../Table/Table.types';
4
+ import type { MotionProps } from '../../types/motion';
5
+ export type { ColumnDef, HeaderContext, CellContext, SortingState, RowSelectionState, OnChangeFn, Row, ReactTableInstance, };
6
+ export interface DataTableProps<TData, TValue = unknown> extends MotionProps {
7
+ /** The data to display in the table. */
8
+ data: TData[];
9
+ /** Column definitions conforming to TanStack Table's ColumnDef specification. */
10
+ columns: ColumnDef<TData, TValue>[];
11
+ /** Controlled sorting state. */
12
+ sorting?: SortingState;
13
+ /** Callback fired when sorting changes. */
14
+ onSortingChange?: OnChangeFn<SortingState>;
15
+ /** Controlled row selection state (mapping rowId to boolean). */
16
+ rowSelection?: RowSelectionState;
17
+ /** Callback fired when row selection changes. */
18
+ onRowSelectionChange?: OnChangeFn<RowSelectionState>;
19
+ /** Additional CSS class names for the table element. */
20
+ className?: string;
21
+ /** Additional CSS class names for the table container. */
22
+ containerClassName?: string;
23
+ /** Whether the table should render with borders. */
24
+ bordered?: boolean;
25
+ /** Table visual variant: 'default' | 'striped' | 'bordered'. */
26
+ variant?: TableProps['variant'];
27
+ /** Table row density: 'sm' | 'default'. */
28
+ size?: TableProps['size'];
29
+ /** Custom content to display when there are no records. */
30
+ emptyMessage?: React.ReactNode;
31
+ /** Whether data is loading (renders skeleton or loading indicator). */
32
+ isLoading?: boolean;
33
+ /** Optional function to determine unique ID for each row. */
34
+ getRowId?: (originalRow: TData, index: number, parent?: Row<TData>) => string;
35
+ /** Optional click handler for table rows. */
36
+ onRowClick?: (row: Row<TData>) => void;
37
+ /** Whether the table header remains sticky while scrolling rows. @default true */
38
+ stickyHeader?: boolean;
39
+ /** Whether to render a smooth motion spring scroll progress indicator. @default true */
40
+ showScrollIndicator?: boolean;
41
+ }
42
+ //# sourceMappingURL=DataTable.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataTable.types.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DataTable.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EACb,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,GAAG,EACH,KAAK,IAAI,kBAAkB,EAC5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,YAAY,EACV,SAAS,EACT,aAAa,EACb,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,GAAG,EACH,kBAAkB,GACnB,CAAC;AAEF,MAAM,WAAW,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAE,SAAQ,WAAW;IAC1E,wCAAwC;IACxC,IAAI,EAAE,KAAK,EAAE,CAAC;IACd,iFAAiF;IACjF,OAAO,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;IACpC,gCAAgC;IAChC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,2CAA2C;IAC3C,eAAe,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IAC3C,iEAAiE;IACjE,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACrD,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gEAAgE;IAChE,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IAChC,2CAA2C;IAC3C,IAAI,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAC1B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC;IAC9E,6CAA6C;IAC7C,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IACvC,kFAAkF;IAClF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wFAAwF;IACxF,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B"}
@@ -0,0 +1,3 @@
1
+ export * from './DataTable';
2
+ export * from './DataTable.types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import type { RichTextContentProps } from './RichTextEditor.types';
3
+ /**
4
+ * SSR-safe viewer for HTML content produced by RichTextEditor.
5
+ * Applies the same DS prose typography as the editor without loading TipTap.
6
+ */
7
+ export declare function RichTextContent({ content, className, style }: RichTextContentProps): React.JSX.Element | null;
8
+ //# sourceMappingURL=RichTextContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextContent.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,oBAAoB,4BAYlF"}
@@ -0,0 +1,18 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { cn } from '@timmbr/utils';
3
+ import { proseViewerStyles } from './RichTextEditor.styles.js';
4
+
5
+ function RichTextContent({ content, className, style }) {
6
+ if (!content) return null;
7
+ return /* @__PURE__ */ jsx(
8
+ "div",
9
+ {
10
+ "data-slot": "rte-content",
11
+ className: cn(proseViewerStyles, className),
12
+ style,
13
+ dangerouslySetInnerHTML: { __html: content }
14
+ }
15
+ );
16
+ }
17
+
18
+ export { RichTextContent };
@@ -0,0 +1,6 @@
1
+ import * as React from 'react';
2
+ import type { RteContextValue } from './RichTextEditor.types';
3
+ declare const RteContext: React.Context<RteContextValue>;
4
+ export { RteContext };
5
+ export declare function useRteContext(): RteContextValue;
6
+ //# sourceMappingURL=RichTextEditor.context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextEditor.context.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,QAAA,MAAM,UAAU,gCAKd,CAAC;AAEH,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,wBAAgB,aAAa,IAAI,eAAe,CAE/C"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import * as React from 'react';
3
+
4
+ const RteContext = React.createContext({
5
+ editor: null,
6
+ shouldAnimate: true,
7
+ disabled: false,
8
+ readOnly: false
9
+ });
10
+ function useRteContext() {
11
+ return React.useContext(RteContext);
12
+ }
13
+
14
+ export { RteContext, useRteContext };
@@ -0,0 +1,4 @@
1
+ import * as React from 'react';
2
+ import type { RichTextEditorProps } from './RichTextEditor.types';
3
+ export declare function RichTextEditor({ value, defaultValue, onChange, onChangeJson, onFocus, onBlur, placeholder, maxCharacters, showCharacterCount, showWordCount, toolbar, toolbarClassName, disabled, readOnly, className, editorClassName, style, id, motion: motionProp, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, }: RichTextEditorProps): React.JSX.Element;
4
+ //# sourceMappingURL=RichTextEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextEditor.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,MAAM,EACN,WAAW,EACX,aAAa,EACb,kBAA0B,EAC1B,aAAqB,EACrB,OAAc,EACd,gBAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,SAAS,EACT,eAAe,EACf,KAAK,EACL,EAAE,EACF,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,kBAAkB,EAAE,eAAe,GACpC,EAAE,mBAAmB,qBAoIrB"}
@@ -0,0 +1,28 @@
1
+ import type { Extensions } from '@tiptap/core';
2
+ interface EditorExtensionConfig {
3
+ placeholder?: string;
4
+ maxCharacters?: number;
5
+ /** When true, loads CharacterCount extension even without a hard limit */
6
+ showCount?: boolean;
7
+ }
8
+ /**
9
+ * Full extension set for the interactive editor.
10
+ * TextAlign must come after StarterKit to correctly extend paragraph/heading nodes.
11
+ */
12
+ export declare function getEditorExtensions(config?: EditorExtensionConfig): Extensions;
13
+ /**
14
+ * Minimal extension set for SSR/viewer use with generateHTML.
15
+ * Excludes extensions that require browser APIs (Placeholder, CharacterCount).
16
+ */
17
+ export declare function getViewerExtensions(): Extensions;
18
+ /**
19
+ * TipTap can emit several representations of an empty document.
20
+ * Strip all <br> variants and whitespace, then check for a single empty paragraph.
21
+ */
22
+ export declare function normalizeHtml(html: string): string;
23
+ /**
24
+ * Normalise a user-typed URL: add https:// if no scheme and not a relative path.
25
+ */
26
+ export declare function normalizeUrl(url: string): string;
27
+ export {};
28
+ //# sourceMappingURL=RichTextEditor.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextEditor.helpers.d.ts","sourceRoot":"","sources":["../../../src/components/RichTextEditor/RichTextEditor.helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQ/C,UAAU,qBAAqB;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,GAAE,qBAA0B,GAAG,UAAU,CAqBlF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CAUhD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhD"}
@@ -0,0 +1,52 @@
1
+ import StarterKit from '@tiptap/starter-kit';
2
+ import Underline from '@tiptap/extension-underline';
3
+ import Link from '@tiptap/extension-link';
4
+ import TextAlign from '@tiptap/extension-text-align';
5
+ import Placeholder from '@tiptap/extension-placeholder';
6
+ import CharacterCount from '@tiptap/extension-character-count';
7
+
8
+ function getEditorExtensions(config = {}) {
9
+ return [
10
+ StarterKit.configure({
11
+ codeBlock: false,
12
+ heading: { levels: [2, 3] }
13
+ }),
14
+ Underline,
15
+ Link.configure({
16
+ openOnClick: false,
17
+ autolink: true,
18
+ HTMLAttributes: { rel: "noopener noreferrer", target: "_blank" }
19
+ }),
20
+ TextAlign.configure({ types: ["heading", "paragraph"] }),
21
+ Placeholder.configure({
22
+ placeholder: config.placeholder ?? "Start writing…",
23
+ showOnlyWhenEditable: true
24
+ }),
25
+ ...config.showCount || config.maxCharacters !== void 0 ? [CharacterCount.configure({ limit: config.maxCharacters })] : []
26
+ ];
27
+ }
28
+ function getViewerExtensions() {
29
+ return [
30
+ StarterKit.configure({
31
+ codeBlock: false,
32
+ heading: { levels: [2, 3] }
33
+ }),
34
+ Underline,
35
+ Link.configure({ openOnClick: false }),
36
+ TextAlign.configure({ types: ["heading", "paragraph"] })
37
+ ];
38
+ }
39
+ function normalizeHtml(html) {
40
+ const stripped = html.replace(/<br\s*\/?>/gi, "").replace(/\s/g, "");
41
+ if (stripped === "<p></p>" || stripped === "") return "";
42
+ return html;
43
+ }
44
+ function normalizeUrl(url) {
45
+ const trimmed = url.trim();
46
+ if (!trimmed) return "";
47
+ if (trimmed.startsWith("/") || trimmed.startsWith("#")) return trimmed;
48
+ if (/^https?:\/\//i.test(trimmed)) return trimmed;
49
+ return `https://${trimmed}`;
50
+ }
51
+
52
+ export { getEditorExtensions, getViewerExtensions, normalizeHtml, normalizeUrl };