nexus-shared 3.0.0 → 3.1.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/CHANGELOG.md +446 -262
- package/LICENSE +21 -21
- package/README.md +1084 -1000
- package/dist/Client.Index.d.ts +3 -0
- package/dist/Client.Index.js +3 -0
- package/dist/Components/Chats/ChatParts.d.ts +2 -2
- package/dist/Components/Chats/ChatParts.js +3 -7
- package/dist/Components/Chats/ChatThread.js +3 -3
- package/dist/Components/Documents/Button.d.ts +6 -1
- package/dist/Components/Documents/Button.js +2 -2
- package/dist/Components/Documents/Menu.js +21 -9
- package/dist/Components/Documents/SplitButton.d.ts +3 -1
- package/dist/Components/Documents/SplitButton.js +7 -5
- package/dist/Components/Documents/TabButtons.d.ts +5 -2
- package/dist/Components/Documents/TabButtons.js +2 -2
- package/dist/Components/Forms/ApiForm.d.ts +1 -1
- package/dist/Components/Forms/ApiForm.js +1 -1
- package/dist/Components/Forms/Crud.js +177 -58
- package/dist/Components/Forms/CrudParts.d.ts +5 -1
- package/dist/Components/Forms/CrudParts.js +37 -5
- package/dist/Components/Forms/ExcelImport.d.ts +23 -7
- package/dist/Components/Forms/ExcelImport.js +189 -60
- package/dist/Components/Forms/Form.js +5 -13
- package/dist/Components/Forms/SubmitForm.d.ts +11 -2
- package/dist/Components/Forms/SubmitForm.js +23 -12
- package/dist/Components/Inputs/DropdownParts.d.ts +1 -1
- package/dist/Components/Inputs/DropdownParts.js +4 -6
- package/dist/Components/Inputs/NumberBox.js +24 -2
- package/dist/Components/Inputs/RowsInput.js +2 -2
- package/dist/Components/Inputs/Slider.js +4 -1
- package/dist/Components/Inputs/TabularForm.js +42 -10
- package/dist/Components/Inputs/TimePanel.js +4 -3
- package/dist/Components/Layouts/Popup.js +1 -4
- package/dist/Components/Layouts/ThemePicker.d.ts +20 -3
- package/dist/Components/Layouts/ThemePicker.js +77 -6
- package/dist/Components/Layouts/ThemeScript.d.ts +4 -2
- package/dist/Components/Layouts/ThemeScript.js +4 -2
- package/dist/Components/Layouts/ThemeSwitcher.d.ts +6 -3
- package/dist/Components/Layouts/ThemeSwitcher.js +9 -8
- package/dist/Components/Viewers/Avatar.d.ts +21 -0
- package/dist/Components/Viewers/Avatar.js +21 -0
- package/dist/Components/Viewers/DataTable.js +192 -44
- package/dist/Components/Viewers/DataTableColumns.d.ts +7 -3
- package/dist/Components/Viewers/DataTableColumns.js +25 -68
- package/dist/Components/Viewers/DataTableFilters.d.ts +21 -0
- package/dist/Components/Viewers/DataTableFilters.js +68 -0
- package/dist/Components/Viewers/DataTableParts.d.ts +2 -2
- package/dist/Components/Viewers/DataTableParts.js +3 -3
- package/dist/Helpers/AnimationHelpers.d.ts +11 -0
- package/dist/Helpers/AnimationHelpers.js +20 -2
- package/dist/Helpers/CrudBackend.d.ts +7 -4
- package/dist/Helpers/CrudBackend.js +4 -2
- package/dist/Helpers/ExcelBackend.d.ts +3 -3
- package/dist/Helpers/ExcelBackend.js +8 -2
- package/dist/Helpers/ExcelHelpers.d.ts +36 -8
- package/dist/Helpers/ExcelHelpers.js +55 -13
- package/dist/Helpers/FormStore.d.ts +9 -5
- package/dist/Helpers/FormStore.js +25 -5
- package/dist/Helpers/MessageBuilder.js +1 -0
- package/dist/Helpers/NumberHelpers.d.ts +7 -1
- package/dist/Helpers/NumberHelpers.js +41 -3
- package/dist/Helpers/PopoverHelpers.d.ts +17 -5
- package/dist/Helpers/PopoverHelpers.js +52 -17
- package/dist/Helpers/PopoverHooks.d.ts +24 -0
- package/dist/Helpers/PopoverHooks.js +62 -0
- package/dist/Helpers/RowsStore.d.ts +7 -2
- package/dist/Helpers/RowsStore.js +15 -3
- package/dist/Helpers/TableExport.js +12 -12
- package/dist/Helpers/TableFilters.d.ts +25 -0
- package/dist/Helpers/TableFilters.js +162 -0
- package/dist/Helpers/TableHelpers.d.ts +6 -3
- package/dist/Helpers/TableHelpers.js +8 -4
- package/dist/Helpers/TableStore.d.ts +11 -3
- package/dist/Helpers/TableStore.js +16 -5
- package/dist/Helpers/ThemeHelpers.d.ts +21 -4
- package/dist/Helpers/ThemeHelpers.js +46 -9
- package/dist/Helpers/UserPreferences.d.ts +14 -0
- package/dist/Helpers/UserPreferences.js +99 -0
- package/dist/Interfaces/CrudInterfaces.d.ts +20 -1
- package/dist/Interfaces/ExcelInterfaces.d.ts +12 -0
- package/dist/Interfaces/FormInterfaces.d.ts +33 -5
- package/dist/Interfaces/PreferenceInterfaces.d.ts +43 -0
- package/dist/Interfaces/PreferenceInterfaces.js +28 -0
- package/dist/Interfaces/TableInterfaces.d.ts +59 -12
- package/dist/Interfaces/ThemeInterfaces.d.ts +25 -0
- package/dist/Interfaces/ThemeInterfaces.js +15 -0
- package/dist/Services/ExcelApi.d.ts +3 -1
- package/dist/Services/ExcelApi.js +1 -1
- package/dist/Services/ThemeService.d.ts +18 -2
- package/dist/Services/ThemeService.js +80 -16
- package/dist/Shared.Index.d.ts +2 -0
- package/dist/Shared.Index.js +2 -0
- package/package.json +85 -85
- package/src/Styles/Nexus.Avatar.css +79 -0
- package/src/Styles/Nexus.Base.css +117 -70
- package/src/Styles/Nexus.Button.css +180 -153
- package/src/Styles/Nexus.Calendar.css +273 -275
- package/src/Styles/Nexus.Chat.css +1443 -1489
- package/src/Styles/Nexus.Choice.css +343 -345
- package/src/Styles/Nexus.Crud.css +168 -161
- package/src/Styles/Nexus.DateTime.css +81 -81
- package/src/Styles/Nexus.Dropdown.css +725 -774
- package/src/Styles/Nexus.Editor.css +295 -297
- package/src/Styles/Nexus.Excel.css +389 -370
- package/src/Styles/Nexus.Form.css +279 -321
- package/src/Styles/Nexus.Index.css +37 -36
- package/src/Styles/Nexus.Input.css +602 -637
- package/src/Styles/Nexus.Markdown.css +237 -265
- package/src/Styles/Nexus.Menu.css +237 -259
- package/src/Styles/Nexus.Popup.css +724 -731
- package/src/Styles/Nexus.RichText.css +2 -32
- package/src/Styles/Nexus.Rows.css +637 -596
- package/src/Styles/Nexus.Slider.css +276 -278
- package/src/Styles/Nexus.Tab.Buttons.css +432 -419
- package/src/Styles/Nexus.Table.css +1386 -1296
- package/src/Styles/Nexus.Theme.Picker.css +286 -232
- package/src/Styles/Nexus.Themes.css +194 -194
- package/src/Styles/Nexus.Time.css +144 -147
- package/src/Styles/Nexus.Toast.css +263 -265
- package/src/Styles/Nexus.Tokens.css +89 -72
- package/src/Styles/Nexus.Tree.css +431 -435
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode, Ref } from "react";
|
|
2
2
|
import type { TableStore } from "../Helpers/TableStore.ts";
|
|
3
3
|
import type { ExcelEndpoints } from "./ExcelInterfaces.ts";
|
|
4
|
+
import type { InputParams } from "./FormInterfaces.ts";
|
|
4
5
|
import type { Size, Tone } from "./TypeInterfaces.ts";
|
|
5
6
|
/** A row's id: its `rowKey` field, such as `id`. */
|
|
6
7
|
export type TableKey = string | number;
|
|
@@ -81,7 +82,13 @@ export interface TableSort {
|
|
|
81
82
|
key: string;
|
|
82
83
|
direction: TableSortDirection;
|
|
83
84
|
}
|
|
84
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* The advanced filter's values, by input name: only the inputs that hold a value, in the order of the inputs, so the
|
|
87
|
+
* same filters always serialize the same way (a cache key, a request). A date range is its pair ["2026-10-01", null],
|
|
88
|
+
* a range slider [2, 7], a multiple choice its list, a ticked checkbox `true`.
|
|
89
|
+
*/
|
|
90
|
+
export type TableFilters = Readonly<Record<string, unknown>>;
|
|
91
|
+
/** What the table shows: the search, the filters, the sort, and the page. */
|
|
85
92
|
export interface TableQuery {
|
|
86
93
|
/** The search text, trimmed. */
|
|
87
94
|
search: string;
|
|
@@ -89,13 +96,18 @@ export interface TableQuery {
|
|
|
89
96
|
/** The page, from 1. */
|
|
90
97
|
page: number;
|
|
91
98
|
pageSize: number;
|
|
99
|
+
/**
|
|
100
|
+
* The advanced filter while any input holds a value; absent otherwise. A client table matches its rows; a server
|
|
101
|
+
* table's loader receives the raw values (`filterRequest` gives them in a server's names).
|
|
102
|
+
*/
|
|
103
|
+
filters?: TableFilters;
|
|
92
104
|
}
|
|
93
105
|
/** One page of rows, as a server sends it. */
|
|
94
106
|
export interface TablePage<TRow extends TableRow = TableRow> {
|
|
95
107
|
rows: readonly TRow[];
|
|
96
108
|
/** Every row there is. Default: the rows given. */
|
|
97
109
|
total?: number;
|
|
98
|
-
/** The rows that match the search. Default: `total`. */
|
|
110
|
+
/** The rows that match the search and the filters. Default: `total`. */
|
|
99
111
|
matches?: number;
|
|
100
112
|
}
|
|
101
113
|
/**
|
|
@@ -120,7 +132,7 @@ export interface TableState<TRow extends TableRow = TableRow> {
|
|
|
120
132
|
offset: number;
|
|
121
133
|
/** Every row there is. */
|
|
122
134
|
total: number;
|
|
123
|
-
/** The rows that match the search. */
|
|
135
|
+
/** The rows that match the search and the filters. */
|
|
124
136
|
matches: number;
|
|
125
137
|
query: TableQuery;
|
|
126
138
|
/** The selected rows by key (keys as text), in the order they were picked. */
|
|
@@ -175,10 +187,15 @@ export interface TableExcel {
|
|
|
175
187
|
subject?: string;
|
|
176
188
|
/** Values the endpoints' own params need, such as a parent's id. */
|
|
177
189
|
params?: Record<string, string | number>;
|
|
178
|
-
/**
|
|
190
|
+
/** Filters the page holds outside the table, sent beside the table's own (`filterInputs`); the page's win a clash. */
|
|
179
191
|
filters?: () => Record<string, unknown>;
|
|
180
|
-
/** After an import wrote something
|
|
192
|
+
/** After an import wrote something, before the table reads its rows again: drop here whatever the page keeps of them. */
|
|
181
193
|
onImported?: () => void;
|
|
194
|
+
/**
|
|
195
|
+
* No **Bulk insert** entry. A sheet with a required list cannot be typed in - its key is picked in the spreadsheet -
|
|
196
|
+
* and its panel says so; this leaves the entry out instead.
|
|
197
|
+
*/
|
|
198
|
+
bulk?: false;
|
|
182
199
|
}
|
|
183
200
|
/** An item of the table's options menu (⋮): Import, Print, a report of the page's own. */
|
|
184
201
|
export interface TableMenuAction {
|
|
@@ -195,6 +212,12 @@ export interface TableMenuAction {
|
|
|
195
212
|
separator?: boolean;
|
|
196
213
|
onSelect: () => void;
|
|
197
214
|
}
|
|
215
|
+
/** A way to select rows by what they are, such as "Pinned" or "Not flagged". */
|
|
216
|
+
export interface TableSelectBy<TRow extends TableRow = TableRow> {
|
|
217
|
+
label: string;
|
|
218
|
+
icon?: ReactNode;
|
|
219
|
+
test: (row: TRow) => boolean;
|
|
220
|
+
}
|
|
198
221
|
/** An action on one row, in its row: an icon button (`inline`) or an item of the row's menu. */
|
|
199
222
|
export interface TableRowAction<TRow extends TableRow = TableRow> {
|
|
200
223
|
/** Tells actions apart; a test or a style can find it by `data-action`. */
|
|
@@ -247,22 +270,33 @@ export interface DataTableProps<TRow extends TableRow = TableRow> {
|
|
|
247
270
|
searchable?: boolean;
|
|
248
271
|
/** Default "Search…". */
|
|
249
272
|
searchPlaceholder?: string;
|
|
250
|
-
/**
|
|
273
|
+
/** On the left of the bar, after the Add section: tabs, filters. On a narrow table the line under the search. */
|
|
251
274
|
toolbar?: ReactNode;
|
|
252
|
-
/**
|
|
275
|
+
/** The page's own buttons, in the Add section after the table's Add: first in the bar, last on a phone. */
|
|
253
276
|
actions?: ReactNode;
|
|
277
|
+
/**
|
|
278
|
+
* The table's Add, first in the bar. With `excel`, its arrow holds the template, the import and the export, which
|
|
279
|
+
* then leave the options menu.
|
|
280
|
+
*/
|
|
281
|
+
add?: {
|
|
282
|
+
label: ReactNode;
|
|
283
|
+
onClick: () => void;
|
|
284
|
+
};
|
|
254
285
|
/** The Columns panel, where columns are shown, hidden, and dragged into another order. Default true. */
|
|
255
286
|
columnsMenu?: boolean;
|
|
256
287
|
/**
|
|
257
288
|
* The spreadsheet side of this table, against the backend's Excel controller. The options menu (⋮) then offers
|
|
258
289
|
* **Download template**, **Import from a spreadsheet** (the file is verified, the person goes over the rows, and the
|
|
259
|
-
* table reloads once they are written)
|
|
260
|
-
*
|
|
290
|
+
* table reloads once they are written), **Bulk insert** (the same import with no file: the rows are typed into the
|
|
291
|
+
* same editor; offered only with `add`, as it is an Add of many rows) and, where the endpoints have one, **Export to
|
|
292
|
+
* Excel** - which asks the server with the search, the filters and the sort on screen instead of writing a file of
|
|
293
|
+
* the rows this browser happens to hold.
|
|
261
294
|
*
|
|
262
|
-
* It replaces `onImport`, which is the hook for a page that imports its own way.
|
|
295
|
+
* It replaces `onImport`, which is the hook for a page that imports its own way. With `add`, they are under the
|
|
296
|
+
* Add's arrow instead of the options menu.
|
|
263
297
|
*/
|
|
264
298
|
excel?: TableExcel;
|
|
265
|
-
/** A Reload button. Default true when rows are loaded. */
|
|
299
|
+
/** A Reload button (in the options menu on a table under 375px wide). Default true when rows are loaded. */
|
|
266
300
|
reloadable?: boolean;
|
|
267
301
|
/** When the user presses Reload, before the rows load again: drop a cache of your own. */
|
|
268
302
|
onReload?: () => void;
|
|
@@ -288,6 +322,11 @@ export interface DataTableProps<TRow extends TableRow = TableRow> {
|
|
|
288
322
|
maxSelection?: number;
|
|
289
323
|
/** After the selection changes. */
|
|
290
324
|
onSelectionChange?: (rows: TRow[]) => void;
|
|
325
|
+
/**
|
|
326
|
+
* While rows are selected, their count opens a menu that selects again by what the rows are: every row on the page,
|
|
327
|
+
* then these, each picking exactly the rows on the page that pass its test.
|
|
328
|
+
*/
|
|
329
|
+
selectBy?: readonly TableSelectBy<TRow>[];
|
|
291
330
|
/** Actions on the selected rows. A function gets the selected rows. */
|
|
292
331
|
massActions?: readonly TableMassAction<TRow>[] | ((rows: TRow[]) => readonly TableMassAction<TRow>[]);
|
|
293
332
|
/** Actions of each row. */
|
|
@@ -327,9 +366,17 @@ export interface DataTableProps<TRow extends TableRow = TableRow> {
|
|
|
327
366
|
stateKey?: string;
|
|
328
367
|
/** Milliseconds after the last key before a search goes to a server. Default 300; a table with every row searches at once. */
|
|
329
368
|
searchDelay?: number;
|
|
369
|
+
/**
|
|
370
|
+
* The advanced filter: the inputs the rows can be filtered by, as a form takes them. Keep the array stable.
|
|
371
|
+
* With any, the options menu (⋮) offers **Filters**: a panel of these inputs under its button, applied as they change.
|
|
372
|
+
* Name an input after the column `key` it filters (else a path into the row); that name is also what a server gets.
|
|
373
|
+
* A `number` input named `{key}From` / `{key}To` is a lower / upper bound of column `{key}`.
|
|
374
|
+
* `required`, `defaultValue` and `defaultChecked` are ignored, so the Add form's params can be reused.
|
|
375
|
+
*/
|
|
376
|
+
filterInputs?: readonly InputParams[];
|
|
330
377
|
/** Shown when there are no rows at all. Default "No records yet." */
|
|
331
378
|
emptyMessage?: ReactNode;
|
|
332
|
-
/** Beside the empty message
|
|
379
|
+
/** Beside the empty message. Default: the table's Add (`add`); `null` for none. */
|
|
333
380
|
emptyAction?: ReactNode;
|
|
334
381
|
/** The tallest the table grows before its rows scroll under a header that stays: pixels or a CSS length. */
|
|
335
382
|
maxHeight?: number | string;
|
|
@@ -9,9 +9,34 @@ export interface ThemeOption {
|
|
|
9
9
|
/** The themes in `nexus-shared/styles.css`. Each has a light and a dark palette. */
|
|
10
10
|
export declare const NEXUS_THEMES: readonly ThemeOption[];
|
|
11
11
|
export declare const DEFAULT_THEME = "nexus";
|
|
12
|
+
/** `compact` (default): today's sizes. `cozy`: every control and row a step taller, for touch screens and large monitors. */
|
|
13
|
+
export type Density = "compact" | "cozy";
|
|
14
|
+
/**
|
|
15
|
+
* Whether things move: `on` even when the operating system asks for less motion, `off` never, `system` as the
|
|
16
|
+
* operating system says (`prefers-reduced-motion`). Some people turn animations off for the whole desktop and still
|
|
17
|
+
* want them here, which is why this is a choice of its own.
|
|
18
|
+
*/
|
|
19
|
+
export type AnimationMode = "on" | "off" | "system";
|
|
20
|
+
/** The scale grid, a development tool: off, a 4px sheet with a solid line every 48px, or millimetres and centimetres. */
|
|
21
|
+
export type ScaleGrid = "off" | "px" | "cm";
|
|
12
22
|
/** Browser storage keys for the saved choice. */
|
|
13
23
|
export declare const THEME_STORAGE_KEY = "nx-theme";
|
|
14
24
|
export declare const THEME_MODE_STORAGE_KEY = "nx-mode";
|
|
25
|
+
export declare const DENSITY_STORAGE_KEY = "nx-density";
|
|
26
|
+
export declare const ANIMATIONS_STORAGE_KEY = "nx-animations";
|
|
27
|
+
export declare const GRID_STORAGE_KEY = "nx-grid";
|
|
15
28
|
/** Attributes on `<html>` that select the theme and the mode. Without `data-nx-mode`, the system setting applies. */
|
|
16
29
|
export declare const THEME_ATTRIBUTE = "data-nx-theme";
|
|
17
30
|
export declare const THEME_MODE_ATTRIBUTE = "data-nx-mode";
|
|
31
|
+
/** `compact` or `cozy`; the size tokens follow it. */
|
|
32
|
+
export declare const DENSITY_ATTRIBUTE = "data-nx-density";
|
|
33
|
+
/** The visitor's animations choice, `on` or `off`. Without it, the system setting applies. */
|
|
34
|
+
export declare const ANIMATIONS_ATTRIBUTE = "data-nx-animations";
|
|
35
|
+
/**
|
|
36
|
+
* What the stylesheets read: `reduce` while nothing may move, `full` otherwise. `ThemeScript` works it out from the
|
|
37
|
+
* choice and the system setting before the first paint, and again when the system setting changes, so no component
|
|
38
|
+
* asks `prefers-reduced-motion` itself.
|
|
39
|
+
*/
|
|
40
|
+
export declare const MOTION_ATTRIBUTE = "data-nx-motion";
|
|
41
|
+
/** `px` or `cm` while the scale grid shows; development builds only. */
|
|
42
|
+
export declare const GRID_ATTRIBUTE = "data-nx-grid";
|
|
@@ -12,6 +12,21 @@ export const DEFAULT_THEME = "nexus";
|
|
|
12
12
|
/** Browser storage keys for the saved choice. */
|
|
13
13
|
export const THEME_STORAGE_KEY = "nx-theme";
|
|
14
14
|
export const THEME_MODE_STORAGE_KEY = "nx-mode";
|
|
15
|
+
export const DENSITY_STORAGE_KEY = "nx-density";
|
|
16
|
+
export const ANIMATIONS_STORAGE_KEY = "nx-animations";
|
|
17
|
+
export const GRID_STORAGE_KEY = "nx-grid";
|
|
15
18
|
/** Attributes on `<html>` that select the theme and the mode. Without `data-nx-mode`, the system setting applies. */
|
|
16
19
|
export const THEME_ATTRIBUTE = "data-nx-theme";
|
|
17
20
|
export const THEME_MODE_ATTRIBUTE = "data-nx-mode";
|
|
21
|
+
/** `compact` or `cozy`; the size tokens follow it. */
|
|
22
|
+
export const DENSITY_ATTRIBUTE = "data-nx-density";
|
|
23
|
+
/** The visitor's animations choice, `on` or `off`. Without it, the system setting applies. */
|
|
24
|
+
export const ANIMATIONS_ATTRIBUTE = "data-nx-animations";
|
|
25
|
+
/**
|
|
26
|
+
* What the stylesheets read: `reduce` while nothing may move, `full` otherwise. `ThemeScript` works it out from the
|
|
27
|
+
* choice and the system setting before the first paint, and again when the system setting changes, so no component
|
|
28
|
+
* asks `prefers-reduced-motion` itself.
|
|
29
|
+
*/
|
|
30
|
+
export const MOTION_ATTRIBUTE = "data-nx-motion";
|
|
31
|
+
/** `px` or `cm` while the scale grid shows; development builds only. */
|
|
32
|
+
export const GRID_ATTRIBUTE = "data-nx-grid";
|
|
@@ -43,4 +43,6 @@ export declare function verifyExcelFile(endpoints: ExcelEndpoints, file: File, o
|
|
|
43
43
|
* they made on screen would be lost. Every check runs again on the way in: what the browser sends is a row, not a
|
|
44
44
|
* decision.
|
|
45
45
|
*/
|
|
46
|
-
export declare function importExcelRows(endpoints: ExcelEndpoints, rows: readonly ExcelSheetRow[], options?: ExcelCallOptions
|
|
46
|
+
export declare function importExcelRows(endpoints: ExcelEndpoints, rows: readonly ExcelSheetRow[], options?: ExcelCallOptions & {
|
|
47
|
+
recordStatus?: number;
|
|
48
|
+
}): Promise<ApiResult<ExcelImportAnswer>>;
|
|
@@ -104,7 +104,7 @@ export async function verifyExcelFile(endpoints, file, options = {}) {
|
|
|
104
104
|
*/
|
|
105
105
|
export async function importExcelRows(endpoints, rows, options = {}) {
|
|
106
106
|
const backend = getExcelBackend();
|
|
107
|
-
const answer = await api.post(endpoints.import, backend.importRequest(rows), { ...call(options), count: rows.length, toast: options.toast === false ? false : { success: false } });
|
|
107
|
+
const answer = await api.post(endpoints.import, backend.importRequest(rows, options.recordStatus), { ...call(options), count: rows.length, toast: options.toast === false ? false : { success: false } });
|
|
108
108
|
// An import that wrote nothing at all is the one failure; it still answers with what it refused, where it says so.
|
|
109
109
|
return { ...answer, result: answer.result === undefined ? undefined : backend.readImport(answer.result) };
|
|
110
110
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ThemeMode } from "../Interfaces/ThemeInterfaces.ts";
|
|
1
|
+
import { type AnimationMode, type Density, type ScaleGrid, type ThemeMode } from "../Interfaces/ThemeInterfaces.ts";
|
|
2
2
|
export interface ThemeState {
|
|
3
3
|
/** The active theme id. */
|
|
4
4
|
theme: string;
|
|
@@ -6,12 +6,28 @@ export interface ThemeState {
|
|
|
6
6
|
mode: ThemeMode;
|
|
7
7
|
/** The mode actually shown. */
|
|
8
8
|
resolvedMode: "light" | "dark";
|
|
9
|
+
density: Density;
|
|
10
|
+
/** The chosen animations, which may be `system`. */
|
|
11
|
+
animations: AnimationMode;
|
|
12
|
+
/** Whether things move now: the choice, or the system setting under `system`. */
|
|
13
|
+
motion: boolean;
|
|
14
|
+
/** The scale grid; always `off` outside a development build. */
|
|
15
|
+
grid: ScaleGrid;
|
|
9
16
|
setTheme: (theme: string) => void;
|
|
10
17
|
setMode: (mode: ThemeMode) => void;
|
|
18
|
+
setDensity: (density: Density) => void;
|
|
19
|
+
setAnimations: (animations: AnimationMode) => void;
|
|
20
|
+
setGrid: (grid: ScaleGrid) => void;
|
|
11
21
|
}
|
|
12
22
|
/** Switches the theme on this page and saves it for the next visit. */
|
|
13
23
|
export declare function setTheme(theme: string): void;
|
|
14
24
|
/** Switches light, dark, or system on this page and saves it for the next visit. */
|
|
15
25
|
export declare function setThemeMode(mode: ThemeMode): void;
|
|
16
|
-
/**
|
|
26
|
+
/** Switches compact or cozy on this page and saves it: every control and row follows at once. */
|
|
27
|
+
export declare function setDensity(density: Density): void;
|
|
28
|
+
/** Turns animations on, off, or back to the system setting on this page, and saves it. */
|
|
29
|
+
export declare function setAnimations(animations: AnimationMode): void;
|
|
30
|
+
/** Shows the scale grid (`px`, `cm`) or hides it (`off`), and saves it. Outside a development build it never shows. */
|
|
31
|
+
export declare function setScaleGrid(grid: ScaleGrid): void;
|
|
32
|
+
/** The current theme, mode, density, animations and scale grid, and functions to change them. */
|
|
17
33
|
export declare function useTheme(): ThemeState;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useSyncExternalStore } from "react";
|
|
3
|
-
import { THEME_ID_PATTERN } from "../Helpers/ThemeHelpers.js";
|
|
4
|
-
import { DEFAULT_THEME, THEME_ATTRIBUTE, THEME_MODE_ATTRIBUTE, THEME_MODE_STORAGE_KEY, THEME_STORAGE_KEY, } from "../Interfaces/ThemeInterfaces.js";
|
|
3
|
+
import { isDevelopmentBuild, motionFor, REDUCED_MOTION_QUERY, THEME_ID_PATTERN } from "../Helpers/ThemeHelpers.js";
|
|
4
|
+
import { ANIMATIONS_ATTRIBUTE, ANIMATIONS_STORAGE_KEY, DEFAULT_THEME, DENSITY_ATTRIBUTE, DENSITY_STORAGE_KEY, GRID_ATTRIBUTE, GRID_STORAGE_KEY, MOTION_ATTRIBUTE, THEME_ATTRIBUTE, THEME_MODE_ATTRIBUTE, THEME_MODE_STORAGE_KEY, THEME_STORAGE_KEY, } from "../Interfaces/ThemeInterfaces.js";
|
|
5
5
|
const DARK_QUERY = "(prefers-color-scheme: dark)";
|
|
6
6
|
// Before hydration there is no document; the real values follow right after.
|
|
7
|
-
const SERVER_SNAPSHOT = `${DEFAULT_THEME} system light`;
|
|
8
|
-
// Colors switch at once, instead of every button and border running its own transition.
|
|
7
|
+
const SERVER_SNAPSHOT = `${DEFAULT_THEME} system light compact system full off`;
|
|
8
|
+
// Colors and sizes switch at once, instead of every button and border running its own transition.
|
|
9
9
|
function withoutTransitions(change) {
|
|
10
10
|
const style = document.createElement("style");
|
|
11
11
|
style.textContent = "*,*::before,*::after{transition:none!important}";
|
|
@@ -22,12 +22,33 @@ function save(key, value) {
|
|
|
22
22
|
// Storage blocked (private mode, for example): the choice lasts until the page reloads.
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
/** Sets an attribute on `<html>`, or takes it away for the choice that means "nothing chosen". */
|
|
26
|
+
function mark(attribute, value, none) {
|
|
27
|
+
const root = document.documentElement;
|
|
28
|
+
if (value === none)
|
|
29
|
+
root.removeAttribute(attribute);
|
|
30
|
+
else
|
|
31
|
+
root.setAttribute(attribute, value);
|
|
32
|
+
}
|
|
33
|
+
const isMode = (value) => value === "light" || value === "dark" || value === "system";
|
|
34
|
+
const isDensity = (value) => value === "compact" || value === "cozy";
|
|
35
|
+
const isAnimations = (value) => value === "on" || value === "off" || value === "system";
|
|
36
|
+
const isGrid = (value) => value === "off" || value === "px" || value === "cm";
|
|
25
37
|
function applyTheme(theme) {
|
|
26
38
|
withoutTransitions(() => document.documentElement.setAttribute(THEME_ATTRIBUTE, theme));
|
|
27
39
|
}
|
|
28
40
|
function applyMode(mode) {
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
withoutTransitions(() => mark(THEME_MODE_ATTRIBUTE, mode, "system"));
|
|
42
|
+
}
|
|
43
|
+
function applyDensity(density) {
|
|
44
|
+
withoutTransitions(() => document.documentElement.setAttribute(DENSITY_ATTRIBUTE, density));
|
|
45
|
+
}
|
|
46
|
+
function applyAnimations(animations) {
|
|
47
|
+
mark(ANIMATIONS_ATTRIBUTE, animations, "system");
|
|
48
|
+
document.documentElement.setAttribute(MOTION_ATTRIBUTE, motionFor(animations, window.matchMedia(REDUCED_MOTION_QUERY).matches));
|
|
49
|
+
}
|
|
50
|
+
function applyGrid(grid) {
|
|
51
|
+
mark(GRID_ATTRIBUTE, isDevelopmentBuild() ? grid : "off", "off");
|
|
31
52
|
}
|
|
32
53
|
/** Switches the theme on this page and saves it for the next visit. */
|
|
33
54
|
export function setTheme(theme) {
|
|
@@ -41,27 +62,63 @@ export function setThemeMode(mode) {
|
|
|
41
62
|
applyMode(mode);
|
|
42
63
|
save(THEME_MODE_STORAGE_KEY, mode);
|
|
43
64
|
}
|
|
65
|
+
/** Switches compact or cozy on this page and saves it: every control and row follows at once. */
|
|
66
|
+
export function setDensity(density) {
|
|
67
|
+
if (!isDensity(density))
|
|
68
|
+
return;
|
|
69
|
+
applyDensity(density);
|
|
70
|
+
save(DENSITY_STORAGE_KEY, density);
|
|
71
|
+
}
|
|
72
|
+
/** Turns animations on, off, or back to the system setting on this page, and saves it. */
|
|
73
|
+
export function setAnimations(animations) {
|
|
74
|
+
if (!isAnimations(animations))
|
|
75
|
+
return;
|
|
76
|
+
applyAnimations(animations);
|
|
77
|
+
save(ANIMATIONS_STORAGE_KEY, animations);
|
|
78
|
+
}
|
|
79
|
+
/** Shows the scale grid (`px`, `cm`) or hides it (`off`), and saves it. Outside a development build it never shows. */
|
|
80
|
+
export function setScaleGrid(grid) {
|
|
81
|
+
if (!isGrid(grid))
|
|
82
|
+
return;
|
|
83
|
+
applyGrid(grid);
|
|
84
|
+
save(GRID_STORAGE_KEY, grid);
|
|
85
|
+
}
|
|
44
86
|
function readSnapshot() {
|
|
45
87
|
const root = document.documentElement;
|
|
46
88
|
const theme = root.getAttribute(THEME_ATTRIBUTE) || DEFAULT_THEME;
|
|
47
89
|
const attribute = root.getAttribute(THEME_MODE_ATTRIBUTE);
|
|
48
90
|
const mode = attribute === "light" || attribute === "dark" ? attribute : "system";
|
|
49
91
|
const resolved = mode === "system" ? (window.matchMedia(DARK_QUERY).matches ? "dark" : "light") : mode;
|
|
50
|
-
|
|
92
|
+
const density = root.getAttribute(DENSITY_ATTRIBUTE) === "cozy" ? "cozy" : "compact";
|
|
93
|
+
const chosen = root.getAttribute(ANIMATIONS_ATTRIBUTE);
|
|
94
|
+
const animations = chosen === "on" || chosen === "off" ? chosen : "system";
|
|
95
|
+
// Read as the stylesheets read it; a page without ThemeScript has no attribute, and its animations run.
|
|
96
|
+
const motion = root.getAttribute(MOTION_ATTRIBUTE) === "reduce" ? "reduce" : "full";
|
|
97
|
+
const grid = root.getAttribute(GRID_ATTRIBUTE);
|
|
98
|
+
return `${theme} ${mode} ${resolved} ${density} ${animations} ${motion} ${grid === "px" || grid === "cm" ? grid : "off"}`;
|
|
51
99
|
}
|
|
52
100
|
// The attributes on <html> are the source of truth, so every picker on the page stays in step,
|
|
53
101
|
// including changes made by the system setting or in another tab.
|
|
54
102
|
function subscribe(onChange) {
|
|
55
103
|
const observer = new MutationObserver(onChange);
|
|
56
|
-
observer.observe(document.documentElement, {
|
|
104
|
+
observer.observe(document.documentElement, {
|
|
105
|
+
attributes: true,
|
|
106
|
+
attributeFilter: [THEME_ATTRIBUTE, THEME_MODE_ATTRIBUTE, DENSITY_ATTRIBUTE, ANIMATIONS_ATTRIBUTE, MOTION_ATTRIBUTE, GRID_ATTRIBUTE],
|
|
107
|
+
});
|
|
57
108
|
const media = window.matchMedia(DARK_QUERY);
|
|
58
109
|
media.addEventListener("change", onChange);
|
|
59
110
|
const onStorage = (event) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
111
|
+
const value = event.newValue;
|
|
112
|
+
if (event.key === THEME_STORAGE_KEY && value && THEME_ID_PATTERN.test(value))
|
|
113
|
+
applyTheme(value);
|
|
114
|
+
else if (event.key === THEME_MODE_STORAGE_KEY && isMode(value))
|
|
115
|
+
applyMode(value);
|
|
116
|
+
else if (event.key === DENSITY_STORAGE_KEY && isDensity(value))
|
|
117
|
+
applyDensity(value);
|
|
118
|
+
else if (event.key === ANIMATIONS_STORAGE_KEY && isAnimations(value))
|
|
119
|
+
applyAnimations(value);
|
|
120
|
+
else if (event.key === GRID_STORAGE_KEY && isGrid(value))
|
|
121
|
+
applyGrid(value);
|
|
65
122
|
};
|
|
66
123
|
window.addEventListener("storage", onStorage);
|
|
67
124
|
return () => {
|
|
@@ -70,14 +127,21 @@ function subscribe(onChange) {
|
|
|
70
127
|
window.removeEventListener("storage", onStorage);
|
|
71
128
|
};
|
|
72
129
|
}
|
|
73
|
-
/** The current theme and
|
|
130
|
+
/** The current theme, mode, density, animations and scale grid, and functions to change them. */
|
|
74
131
|
export function useTheme() {
|
|
75
|
-
const [theme, mode, resolvedMode] = useSyncExternalStore(subscribe, readSnapshot, () => SERVER_SNAPSHOT).split(" ");
|
|
132
|
+
const [theme, mode, resolvedMode, density, animations, motion, grid] = useSyncExternalStore(subscribe, readSnapshot, () => SERVER_SNAPSHOT).split(" ");
|
|
76
133
|
return {
|
|
77
134
|
theme: theme ?? DEFAULT_THEME,
|
|
78
|
-
mode: (mode
|
|
135
|
+
mode: isMode(mode) ? mode : "system",
|
|
79
136
|
resolvedMode: resolvedMode === "dark" ? "dark" : "light",
|
|
137
|
+
density: density === "cozy" ? "cozy" : "compact",
|
|
138
|
+
animations: isAnimations(animations) ? animations : "system",
|
|
139
|
+
motion: motion !== "reduce",
|
|
140
|
+
grid: isGrid(grid) ? grid : "off",
|
|
80
141
|
setTheme,
|
|
81
142
|
setMode: setThemeMode,
|
|
143
|
+
setDensity,
|
|
144
|
+
setAnimations,
|
|
145
|
+
setGrid: setScaleGrid,
|
|
82
146
|
};
|
|
83
147
|
}
|
package/dist/Shared.Index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export * from "./Helpers/NumberHelpers.ts";
|
|
|
32
32
|
export * from "./Helpers/Permissions.ts";
|
|
33
33
|
export * from "./Helpers/RichTextHelpers.ts";
|
|
34
34
|
export * from "./Helpers/RowsStore.ts";
|
|
35
|
+
export * from "./Helpers/TableFilters.ts";
|
|
35
36
|
export * from "./Helpers/TableHelpers.ts";
|
|
36
37
|
export * from "./Helpers/TableStore.ts";
|
|
37
38
|
export * from "./Helpers/ThemeHelpers.ts";
|
|
@@ -46,6 +47,7 @@ export * from "./Interfaces/ExcelInterfaces.ts";
|
|
|
46
47
|
export * from "./Interfaces/FormInterfaces.ts";
|
|
47
48
|
export * from "./Interfaces/InputInterfaces.ts";
|
|
48
49
|
export * from "./Interfaces/MessageInterfaces.ts";
|
|
50
|
+
export * from "./Interfaces/PreferenceInterfaces.ts";
|
|
49
51
|
export * from "./Interfaces/TableInterfaces.ts";
|
|
50
52
|
export * from "./Interfaces/ThemeInterfaces.ts";
|
|
51
53
|
export * from "./Interfaces/TypeInterfaces.ts";
|
package/dist/Shared.Index.js
CHANGED
|
@@ -35,6 +35,7 @@ export * from "./Helpers/NumberHelpers.js";
|
|
|
35
35
|
export * from "./Helpers/Permissions.js";
|
|
36
36
|
export * from "./Helpers/RichTextHelpers.js";
|
|
37
37
|
export * from "./Helpers/RowsStore.js";
|
|
38
|
+
export * from "./Helpers/TableFilters.js";
|
|
38
39
|
export * from "./Helpers/TableHelpers.js";
|
|
39
40
|
export * from "./Helpers/TableStore.js";
|
|
40
41
|
export * from "./Helpers/ThemeHelpers.js";
|
|
@@ -50,6 +51,7 @@ export * from "./Interfaces/ExcelInterfaces.js";
|
|
|
50
51
|
export * from "./Interfaces/FormInterfaces.js";
|
|
51
52
|
export * from "./Interfaces/InputInterfaces.js";
|
|
52
53
|
export * from "./Interfaces/MessageInterfaces.js";
|
|
54
|
+
export * from "./Interfaces/PreferenceInterfaces.js";
|
|
53
55
|
export * from "./Interfaces/TableInterfaces.js";
|
|
54
56
|
export * from "./Interfaces/ThemeInterfaces.js";
|
|
55
57
|
export * from "./Interfaces/TypeInterfaces.js";
|
package/package.json
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "nexus-shared",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "The Nexus component library for React and Next.js: params-driven inputs and forms, a data table with a CRUD on top, popups and toasts, an API layer with permissions, Markdown and rich text editors, and 7 themes in light and dark.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"react",
|
|
7
|
-
"nextjs",
|
|
8
|
-
"components",
|
|
9
|
-
"ui",
|
|
10
|
-
"forms",
|
|
11
|
-
"datatable",
|
|
12
|
-
"crud",
|
|
13
|
-
"inputs",
|
|
14
|
-
"design-system",
|
|
15
|
-
"typescript",
|
|
16
|
-
"nepali-calendar",
|
|
17
|
-
"nexus"
|
|
18
|
-
],
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"author": "Bijay Adhikari",
|
|
21
|
-
"type": "module",
|
|
22
|
-
"sideEffects": [
|
|
23
|
-
"*.css"
|
|
24
|
-
],
|
|
25
|
-
"exports": {
|
|
26
|
-
".": {
|
|
27
|
-
"types": "./dist/Shared.Index.d.ts",
|
|
28
|
-
"default": "./dist/Shared.Index.js"
|
|
29
|
-
},
|
|
30
|
-
"./client": {
|
|
31
|
-
"types": "./dist/Client.Index.d.ts",
|
|
32
|
-
"default": "./dist/Client.Index.js"
|
|
33
|
-
},
|
|
34
|
-
"./server": {
|
|
35
|
-
"types": "./dist/Server.Index.d.ts",
|
|
36
|
-
"default": "./dist/Server.Index.js"
|
|
37
|
-
},
|
|
38
|
-
"./styles.css": "./src/Styles/Nexus.Index.css",
|
|
39
|
-
"./package.json": "./package.json"
|
|
40
|
-
},
|
|
41
|
-
"files": [
|
|
42
|
-
"dist",
|
|
43
|
-
"src/Styles",
|
|
44
|
-
"CHANGELOG.md"
|
|
45
|
-
],
|
|
46
|
-
"scripts": {
|
|
47
|
-
"build": "tsc -p tsconfig.build.json",
|
|
48
|
-
"typecheck": "tsc -p tsconfig.json",
|
|
49
|
-
"test": "node scripts/test-all.mjs",
|
|
50
|
-
"check:themes": "node scripts/check-themes.mjs",
|
|
51
|
-
"test:api": "node scripts/test-api.mts",
|
|
52
|
-
"test:chat": "node scripts/test-chat.mts",
|
|
53
|
-
"test:dates": "node scripts/test-date-helpers.mts",
|
|
54
|
-
"test:datetimes": "node scripts/test-datetime-helpers.mts",
|
|
55
|
-
"test:drag": "node scripts/test-drag-helpers.mts",
|
|
56
|
-
"test:excel": "node scripts/test-excel.mts",
|
|
57
|
-
"test:dropdown": "node scripts/test-dropdown-helpers.mts",
|
|
58
|
-
"test:forms": "node scripts/test-form-store.mts",
|
|
59
|
-
"test:markdown": "node scripts/test-markdown.mts",
|
|
60
|
-
"test:numbers": "node scripts/test-number-helpers.mts",
|
|
61
|
-
"test:popups": "node scripts/test-popup-rules.mts",
|
|
62
|
-
"test:richtext": "node scripts/test-richtext.mts",
|
|
63
|
-
"test:rows": "node scripts/test-rows-store.mts",
|
|
64
|
-
"test:table": "node scripts/test-table.mts",
|
|
65
|
-
"test:times": "node scripts/test-time-helpers.mts",
|
|
66
|
-
"test:tree": "node scripts/test-tree-store.mts",
|
|
67
|
-
"test:types": "tsc -p scripts/type-checks/tsconfig.json"
|
|
68
|
-
},
|
|
69
|
-
"dependencies": {
|
|
70
|
-
"nexus-icons": "^1.1.0"
|
|
71
|
-
},
|
|
72
|
-
"peerDependencies": {
|
|
73
|
-
"react": ">=19",
|
|
74
|
-
"react-dom": ">=19"
|
|
75
|
-
},
|
|
76
|
-
"devDependencies": {
|
|
77
|
-
"@types/react": "19.3.0"
|
|
78
|
-
},
|
|
79
|
-
"engines": {
|
|
80
|
-
"node": ">=20.9"
|
|
81
|
-
},
|
|
82
|
-
"publishConfig": {
|
|
83
|
-
"access": "public"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "nexus-shared",
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"description": "The Nexus component library for React and Next.js: params-driven inputs and forms, a data table with a CRUD on top, popups and toasts, an API layer with permissions, Markdown and rich text editors, and 7 themes in light and dark.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"nextjs",
|
|
8
|
+
"components",
|
|
9
|
+
"ui",
|
|
10
|
+
"forms",
|
|
11
|
+
"datatable",
|
|
12
|
+
"crud",
|
|
13
|
+
"inputs",
|
|
14
|
+
"design-system",
|
|
15
|
+
"typescript",
|
|
16
|
+
"nepali-calendar",
|
|
17
|
+
"nexus"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Bijay Adhikari",
|
|
21
|
+
"type": "module",
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"*.css"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/Shared.Index.d.ts",
|
|
28
|
+
"default": "./dist/Shared.Index.js"
|
|
29
|
+
},
|
|
30
|
+
"./client": {
|
|
31
|
+
"types": "./dist/Client.Index.d.ts",
|
|
32
|
+
"default": "./dist/Client.Index.js"
|
|
33
|
+
},
|
|
34
|
+
"./server": {
|
|
35
|
+
"types": "./dist/Server.Index.d.ts",
|
|
36
|
+
"default": "./dist/Server.Index.js"
|
|
37
|
+
},
|
|
38
|
+
"./styles.css": "./src/Styles/Nexus.Index.css",
|
|
39
|
+
"./package.json": "./package.json"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"src/Styles",
|
|
44
|
+
"CHANGELOG.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.build.json",
|
|
48
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
49
|
+
"test": "node scripts/test-all.mjs",
|
|
50
|
+
"check:themes": "node scripts/check-themes.mjs",
|
|
51
|
+
"test:api": "node scripts/test-api.mts",
|
|
52
|
+
"test:chat": "node scripts/test-chat.mts",
|
|
53
|
+
"test:dates": "node scripts/test-date-helpers.mts",
|
|
54
|
+
"test:datetimes": "node scripts/test-datetime-helpers.mts",
|
|
55
|
+
"test:drag": "node scripts/test-drag-helpers.mts",
|
|
56
|
+
"test:excel": "node scripts/test-excel.mts",
|
|
57
|
+
"test:dropdown": "node scripts/test-dropdown-helpers.mts",
|
|
58
|
+
"test:forms": "node scripts/test-form-store.mts",
|
|
59
|
+
"test:markdown": "node scripts/test-markdown.mts",
|
|
60
|
+
"test:numbers": "node scripts/test-number-helpers.mts",
|
|
61
|
+
"test:popups": "node scripts/test-popup-rules.mts",
|
|
62
|
+
"test:richtext": "node scripts/test-richtext.mts",
|
|
63
|
+
"test:rows": "node scripts/test-rows-store.mts",
|
|
64
|
+
"test:table": "node scripts/test-table.mts",
|
|
65
|
+
"test:times": "node scripts/test-time-helpers.mts",
|
|
66
|
+
"test:tree": "node scripts/test-tree-store.mts",
|
|
67
|
+
"test:types": "tsc -p scripts/type-checks/tsconfig.json"
|
|
68
|
+
},
|
|
69
|
+
"dependencies": {
|
|
70
|
+
"nexus-icons": "^1.1.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"react": ">=19",
|
|
74
|
+
"react-dom": ">=19"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@types/react": "19.3.0"
|
|
78
|
+
},
|
|
79
|
+
"engines": {
|
|
80
|
+
"node": ">=20.9"
|
|
81
|
+
},
|
|
82
|
+
"publishConfig": {
|
|
83
|
+
"access": "public"
|
|
84
|
+
}
|
|
85
|
+
}
|