@usefragments/ui 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DatePicker/index.d.ts +1 -1
- package/dist/components/DatePicker/index.d.ts.map +1 -1
- package/dist/{components/DataTable/DataTable.virtual.cjs → data-table-virtual.cjs} +1 -1
- package/dist/{components/DataTable/DataTable.virtual.js → data-table-virtual.js} +1 -1
- package/dist/data-table.cjs +27 -9
- package/dist/data-table.js +19 -1
- package/dist/datepicker.cjs +68 -32
- package/dist/datepicker.js +41 -5
- package/dist/index.cjs +0 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- package/fragments.json +1 -1
- package/package.json +52 -2
- package/src/components/DataTable/index.tsx +44 -16
- package/src/components/DatePicker/index.tsx +64 -5
- package/src/index.ts +8 -9
- package/src/styles/styles.d.ts +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usefragments/ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Customizable UI components built on Base UI headless primitives",
|
|
6
6
|
"author": "Conan McNicholl",
|
|
@@ -99,6 +99,16 @@
|
|
|
99
99
|
"default": "./dist/data-table.cjs"
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
|
+
"./data-table-virtual": {
|
|
103
|
+
"import": {
|
|
104
|
+
"types": "./dist/components/DataTable/DataTable.virtual.d.ts",
|
|
105
|
+
"default": "./dist/data-table-virtual.js"
|
|
106
|
+
},
|
|
107
|
+
"require": {
|
|
108
|
+
"types": "./dist/components/DataTable/DataTable.virtual.d.ts",
|
|
109
|
+
"default": "./dist/data-table-virtual.cjs"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
102
112
|
"./editor": {
|
|
103
113
|
"import": {
|
|
104
114
|
"types": "./dist/components/Editor/index.d.ts",
|
|
@@ -110,10 +120,12 @@
|
|
|
110
120
|
}
|
|
111
121
|
},
|
|
112
122
|
"./styles": {
|
|
123
|
+
"types": "./src/styles/styles.d.ts",
|
|
113
124
|
"sass": "./src/styles/globals.scss",
|
|
114
125
|
"default": "./dist/assets/ui.css"
|
|
115
126
|
},
|
|
116
127
|
"./globals": {
|
|
128
|
+
"types": "./src/styles/styles.d.ts",
|
|
117
129
|
"sass": "./src/styles/globals.scss",
|
|
118
130
|
"default": "./dist/assets/ui.css"
|
|
119
131
|
},
|
|
@@ -155,6 +167,44 @@
|
|
|
155
167
|
"remark-gfm": ">=4.0.0",
|
|
156
168
|
"shiki": ">=1.0.0"
|
|
157
169
|
},
|
|
170
|
+
"peerDependenciesMeta": {
|
|
171
|
+
"@tanstack/react-table": {
|
|
172
|
+
"optional": true
|
|
173
|
+
},
|
|
174
|
+
"@tanstack/react-virtual": {
|
|
175
|
+
"optional": true
|
|
176
|
+
},
|
|
177
|
+
"@tiptap/extension-link": {
|
|
178
|
+
"optional": true
|
|
179
|
+
},
|
|
180
|
+
"@tiptap/react": {
|
|
181
|
+
"optional": true
|
|
182
|
+
},
|
|
183
|
+
"@tiptap/starter-kit": {
|
|
184
|
+
"optional": true
|
|
185
|
+
},
|
|
186
|
+
"date-fns": {
|
|
187
|
+
"optional": true
|
|
188
|
+
},
|
|
189
|
+
"react-colorful": {
|
|
190
|
+
"optional": true
|
|
191
|
+
},
|
|
192
|
+
"react-day-picker": {
|
|
193
|
+
"optional": true
|
|
194
|
+
},
|
|
195
|
+
"react-markdown": {
|
|
196
|
+
"optional": true
|
|
197
|
+
},
|
|
198
|
+
"recharts": {
|
|
199
|
+
"optional": true
|
|
200
|
+
},
|
|
201
|
+
"remark-gfm": {
|
|
202
|
+
"optional": true
|
|
203
|
+
},
|
|
204
|
+
"shiki": {
|
|
205
|
+
"optional": true
|
|
206
|
+
}
|
|
207
|
+
},
|
|
158
208
|
"dependencies": {
|
|
159
209
|
"@base-ui/react": "1.6.0",
|
|
160
210
|
"@phosphor-icons/react": "^2.1.10"
|
|
@@ -190,7 +240,7 @@
|
|
|
190
240
|
"vite": "^6.0.0",
|
|
191
241
|
"vitest": "^2.1.8",
|
|
192
242
|
"vitest-axe": "^0.1.0",
|
|
193
|
-
"@usefragments/core": "1.
|
|
243
|
+
"@usefragments/core": "1.4.0"
|
|
194
244
|
},
|
|
195
245
|
"files": [
|
|
196
246
|
"src",
|
|
@@ -5,13 +5,40 @@ import styles from "./DataTable.module.scss";
|
|
|
5
5
|
import { Checkbox } from "../Checkbox";
|
|
6
6
|
import { ExpandIcon, SortAscIcon, SortDescIcon, SortIcon } from "./DataTable.icons";
|
|
7
7
|
import { DataTableSkeletonRows, useArrowKeyRowNav } from "./DataTable.support";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
|
|
9
|
+
// ============================================
|
|
10
|
+
// Dependency (@tanstack/react-table) — lazy-required
|
|
11
|
+
// ============================================
|
|
12
|
+
// `@tanstack/react-table` is an optional peer dependency. It is pulled in via a
|
|
13
|
+
// synchronous `require()` (mirroring Chart/Editor) rather than a static ESM
|
|
14
|
+
// import so a bundler's dep-optimizer (e.g. Vite dev) does not create a static
|
|
15
|
+
// import edge for consumers who only use, say, `{ Button }`. `require` resolves
|
|
16
|
+
// synchronously, so `useReactTable` (a hook) is available before the first hook
|
|
17
|
+
// call and hook order stays stable across renders. When the peer is absent the
|
|
18
|
+
// component throws a friendly install message on first render.
|
|
19
|
+
|
|
20
|
+
type ReactTableModule = {
|
|
21
|
+
flexRender: (...args: any[]) => React.ReactNode;
|
|
22
|
+
getCoreRowModel: (...args: any[]) => any;
|
|
23
|
+
getExpandedRowModel: (...args: any[]) => any;
|
|
24
|
+
getSortedRowModel: (...args: any[]) => any;
|
|
25
|
+
useReactTable: (options: any) => any;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let _reactTable: ReactTableModule | null = null;
|
|
29
|
+
let _reactTableLoaded = false;
|
|
30
|
+
let _reactTableFailed = false;
|
|
31
|
+
|
|
32
|
+
function loadReactTable() {
|
|
33
|
+
if (_reactTableLoaded) return;
|
|
34
|
+
_reactTableLoaded = true;
|
|
35
|
+
try {
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
37
|
+
_reactTable = require("@tanstack/react-table") as ReactTableModule;
|
|
38
|
+
} catch {
|
|
39
|
+
_reactTableFailed = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
15
42
|
|
|
16
43
|
/** Horizontal alignment for a column's header + cells. */
|
|
17
44
|
export type ColumnAlign = "left" | "right" | "center";
|
|
@@ -50,15 +77,6 @@ export type DataTableRowClickEvent =
|
|
|
50
77
|
|
|
51
78
|
export type DataTableColumn<T> = ColumnDef<T, unknown>;
|
|
52
79
|
|
|
53
|
-
// ============================================
|
|
54
|
-
// Dependency (@tanstack/react-table)
|
|
55
|
-
// ============================================
|
|
56
|
-
// Statically imported (ESM) so DataTable works in every bundler, including
|
|
57
|
-
// browser SPAs (Vite) where `require` is unavailable. `useReactTable` is a
|
|
58
|
-
// hook and must resolve synchronously on first render. The package is an
|
|
59
|
-
// optional peer dep + `sideEffects: false`, so this import is tree-shaken
|
|
60
|
-
// out of bundles that never import DataTable.
|
|
61
|
-
|
|
62
80
|
export interface DataTableProps<T> extends Omit<React.HTMLAttributes<HTMLTableElement>, "onClick"> {
|
|
63
81
|
/** Column definitions */
|
|
64
82
|
columns: DataTableColumn<T>[];
|
|
@@ -186,6 +204,16 @@ function DataTableRoot<T>({
|
|
|
186
204
|
"aria-describedby": ariaDescribedBy,
|
|
187
205
|
...htmlProps
|
|
188
206
|
}: DataTableProps<T>) {
|
|
207
|
+
loadReactTable();
|
|
208
|
+
if (_reactTableFailed || !_reactTable) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
"[@usefragments/ui] DataTable: @tanstack/react-table is not installed. " +
|
|
211
|
+
"Install it with: npm install @tanstack/react-table"
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const { flexRender, getCoreRowModel, getExpandedRowModel, getSortedRowModel, useReactTable } =
|
|
215
|
+
_reactTable;
|
|
216
|
+
|
|
189
217
|
const tableRef = React.useRef<HTMLTableElement>(null);
|
|
190
218
|
useArrowKeyRowNav(tableRef, !!onRowClick);
|
|
191
219
|
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
5
|
-
import { DayFlag, DayPicker, SelectionState, UI } from "react-day-picker";
|
|
6
|
-
import { format as formatDateWithPattern } from "date-fns";
|
|
7
5
|
import { useFormFieldIds, type FormFieldProps } from "../../utils/aria";
|
|
8
6
|
import { useResolvedControlSize } from "../ComponentDefaults";
|
|
9
7
|
import styles from "./DatePicker.module.scss";
|
|
@@ -186,15 +184,30 @@ function useDatePickerContext() {
|
|
|
186
184
|
// ============================================
|
|
187
185
|
// Default formatters
|
|
188
186
|
// ============================================
|
|
187
|
+
//
|
|
188
|
+
// Zero-dependency `Intl.DateTimeFormat` so the default trigger label needs no
|
|
189
|
+
// optional peer. `date-fns` remains an optional peer only for consumers who pass
|
|
190
|
+
// their own `formatDate`/`formatRange`; the default path never imports it, so a
|
|
191
|
+
// bundler that pulls DatePicker into the graph does not fail on a missing peer.
|
|
192
|
+
const longDateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
193
|
+
month: "long",
|
|
194
|
+
day: "numeric",
|
|
195
|
+
year: "numeric",
|
|
196
|
+
});
|
|
197
|
+
const mediumDateFormatter = new Intl.DateTimeFormat("en-US", {
|
|
198
|
+
month: "short",
|
|
199
|
+
day: "2-digit",
|
|
200
|
+
year: "numeric",
|
|
201
|
+
});
|
|
189
202
|
|
|
190
203
|
function defaultFormatDate(date: Date): string {
|
|
191
|
-
return
|
|
204
|
+
return longDateFormatter.format(date);
|
|
192
205
|
}
|
|
193
206
|
|
|
194
207
|
function defaultFormatRange(range: DateRange): string {
|
|
195
208
|
if (!range.from) return "";
|
|
196
|
-
if (!range.to) return
|
|
197
|
-
return `${
|
|
209
|
+
if (!range.to) return mediumDateFormatter.format(range.from);
|
|
210
|
+
return `${mediumDateFormatter.format(range.from)} - ${mediumDateFormatter.format(range.to)}`;
|
|
198
211
|
}
|
|
199
212
|
|
|
200
213
|
function formatDateForHiddenInput(date?: Date): string {
|
|
@@ -205,11 +218,48 @@ function formatDateForHiddenInput(date?: Date): string {
|
|
|
205
218
|
return `${year}-${month}-${day}`;
|
|
206
219
|
}
|
|
207
220
|
|
|
221
|
+
// ============================================
|
|
222
|
+
// Lazy-loaded dependency (react-day-picker)
|
|
223
|
+
// ============================================
|
|
224
|
+
//
|
|
225
|
+
// Loaded on demand via require() so the barrel never statically references the
|
|
226
|
+
// optional `react-day-picker` peer. Importing anything else from
|
|
227
|
+
// @usefragments/ui must not drag the calendar (or its transitive `date-fns`
|
|
228
|
+
// dependency) into a consumer's build graph. Mirrors the Chart/recharts pattern.
|
|
229
|
+
|
|
230
|
+
type DayPickerComponent = React.ComponentType<Record<string, unknown>>;
|
|
231
|
+
type RdpEnum = Record<string, string>;
|
|
232
|
+
|
|
233
|
+
let _DayPicker: DayPickerComponent | null = null;
|
|
234
|
+
let _UI: RdpEnum | null = null;
|
|
235
|
+
let _SelectionState: RdpEnum | null = null;
|
|
236
|
+
let _DayFlag: RdpEnum | null = null;
|
|
237
|
+
let _rdpLoaded = false;
|
|
238
|
+
let _rdpFailed = false;
|
|
239
|
+
|
|
240
|
+
function loadDayPickerDeps(): void {
|
|
241
|
+
if (_rdpLoaded) return;
|
|
242
|
+
_rdpLoaded = true;
|
|
243
|
+
try {
|
|
244
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
245
|
+
const rdp = require("react-day-picker");
|
|
246
|
+
_DayPicker = rdp.DayPicker as DayPickerComponent;
|
|
247
|
+
_UI = rdp.UI as RdpEnum;
|
|
248
|
+
_SelectionState = rdp.SelectionState as RdpEnum;
|
|
249
|
+
_DayFlag = rdp.DayFlag as RdpEnum;
|
|
250
|
+
} catch {
|
|
251
|
+
_rdpFailed = true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
208
255
|
// ============================================
|
|
209
256
|
// ClassNames mapping (built lazily)
|
|
210
257
|
// ============================================
|
|
211
258
|
|
|
212
259
|
function getCalendarClassNames() {
|
|
260
|
+
const UI = _UI!;
|
|
261
|
+
const SelectionState = _SelectionState!;
|
|
262
|
+
const DayFlag = _DayFlag!;
|
|
213
263
|
return {
|
|
214
264
|
[UI.Root]: styles.calendar,
|
|
215
265
|
[UI.Months]: styles.months,
|
|
@@ -517,6 +567,15 @@ function DatePickerCalendar({
|
|
|
517
567
|
[]
|
|
518
568
|
);
|
|
519
569
|
|
|
570
|
+
loadDayPickerDeps();
|
|
571
|
+
if (_rdpFailed || !_DayPicker || !_UI) {
|
|
572
|
+
// react-day-picker is an optional peer: render nothing rather than crash
|
|
573
|
+
// when a consumer mounts <DatePicker> without installing the calendar dep.
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
const DayPicker = _DayPicker;
|
|
577
|
+
const UI = _UI;
|
|
578
|
+
|
|
520
579
|
const calendarClassNames = getCalendarClassNames();
|
|
521
580
|
|
|
522
581
|
const calendarClasses = className
|
package/src/index.ts
CHANGED
|
@@ -257,15 +257,14 @@ export {
|
|
|
257
257
|
type ExpandedState,
|
|
258
258
|
} from "./components/DataTable";
|
|
259
259
|
|
|
260
|
-
// DataTable row virtualization (opt-in; requires @tanstack/react-virtual)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
} from "./components/DataTable/DataTable.virtual";
|
|
260
|
+
// DataTable row virtualization (opt-in; requires @tanstack/react-virtual).
|
|
261
|
+
// Intentionally NOT re-exported from the main barrel: `useTableVirtualizer`
|
|
262
|
+
// wraps a hook that must resolve synchronously, so — unlike DataTable/Chart/
|
|
263
|
+
// Editor — it cannot be lazy-required. Re-exporting it here (or routing it
|
|
264
|
+
// through the `./data-table` subpath, which the main barrel imports) would
|
|
265
|
+
// statically pull @tanstack/react-virtual into every consumer's Button-only
|
|
266
|
+
// build. It lives behind its own dedicated subpath the barrel never imports:
|
|
267
|
+
// import { DataTableVirtual, useTableVirtualizer } from "@usefragments/ui/data-table-virtual";
|
|
269
268
|
|
|
270
269
|
// EmptyState
|
|
271
270
|
export {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Ambient type surface for the side-effect style entrypoints
|
|
2
|
+
// (`@usefragments/ui/styles` and `@usefragments/ui/globals`). These specifiers
|
|
3
|
+
// resolve to compiled CSS (or the raw SCSS under the `sass` condition) and carry
|
|
4
|
+
// no runtime exports, so a bare `import "@usefragments/ui/styles";` needs a
|
|
5
|
+
// resolvable `types` target to keep TypeScript from erroring. This file ships in
|
|
6
|
+
// the published tarball via the package `files: ["src"]` entry and is referenced
|
|
7
|
+
// by the `types` condition of both exports in `publishConfig`.
|
|
8
|
+
export {};
|