nexus-shared 3.1.0 → 4.0.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 +2268 -446
- package/LICENSE +21 -21
- package/README.md +1705 -1084
- package/dist/Client.Index.d.ts +17 -0
- package/dist/Client.Index.js +17 -0
- package/dist/Components/Documents/DocumentFrame.d.ts +50 -0
- package/dist/Components/Documents/DocumentFrame.js +83 -0
- package/dist/Components/Documents/Menu.d.ts +4 -0
- package/dist/Components/Documents/Menu.js +40 -24
- package/dist/Components/Documents/PrintDocument.d.ts +95 -0
- package/dist/Components/Documents/PrintDocument.js +62 -0
- package/dist/Components/Documents/Tabs.d.ts +59 -0
- package/dist/Components/Documents/Tabs.js +70 -0
- package/dist/Components/Forms/ApiForm.js +19 -2
- package/dist/Components/Forms/Crud.d.ts +2 -2
- package/dist/Components/Forms/Crud.js +871 -377
- package/dist/Components/Forms/CrudActions.d.ts +136 -0
- package/dist/Components/Forms/CrudActions.js +184 -0
- package/dist/Components/Forms/CrudHistory.d.ts +66 -0
- package/dist/Components/Forms/CrudHistory.js +140 -0
- package/dist/Components/Forms/CrudNarrowPicker.d.ts +31 -0
- package/dist/Components/Forms/CrudNarrowPicker.js +180 -0
- package/dist/Components/Forms/CrudParts.d.ts +30 -2
- package/dist/Components/Forms/CrudParts.js +56 -5
- package/dist/Components/Forms/CrudRowForms.d.ts +26 -0
- package/dist/Components/Forms/CrudRowForms.js +114 -0
- package/dist/Components/Forms/CrudScopes.d.ts +28 -0
- package/dist/Components/Forms/CrudScopes.js +76 -0
- package/dist/Components/Forms/CrudTree.d.ts +90 -0
- package/dist/Components/Forms/CrudTree.js +363 -0
- package/dist/Components/Forms/CrudWorkspace.d.ts +63 -0
- package/dist/Components/Forms/CrudWorkspace.js +169 -0
- package/dist/Components/Forms/ExcelImport.js +3 -3
- package/dist/Components/Forms/Form.d.ts +4 -4
- package/dist/Components/Forms/Form.js +125 -16
- package/dist/Components/Forms/FormLeaveGuard.d.ts +44 -0
- package/dist/Components/Forms/FormLeaveGuard.js +65 -0
- package/dist/Components/Forms/RecordFlows.d.ts +50 -0
- package/dist/Components/Forms/RecordFlows.js +282 -0
- package/dist/Components/Forms/SubmitForm.d.ts +37 -2
- package/dist/Components/Forms/SubmitForm.js +195 -10
- package/dist/Components/Inputs/CheckBox.js +1 -1
- package/dist/Components/Inputs/ChoiceField.d.ts +21 -1
- package/dist/Components/Inputs/ChoiceField.js +28 -2
- package/dist/Components/Inputs/CodeBox.d.ts +69 -0
- package/dist/Components/Inputs/CodeBox.js +316 -0
- package/dist/Components/Inputs/DatePicker.js +4 -1
- package/dist/Components/Inputs/DateRangePicker.js +4 -1
- package/dist/Components/Inputs/DateTimePicker.js +4 -1
- package/dist/Components/Inputs/Dropdown.d.ts +13 -0
- package/dist/Components/Inputs/Dropdown.js +8 -5
- package/dist/Components/Inputs/DropdownParts.d.ts +3 -1
- package/dist/Components/Inputs/DropdownParts.js +16 -4
- package/dist/Components/Inputs/Field.d.ts +7 -1
- package/dist/Components/Inputs/Field.js +2 -2
- package/dist/Components/Inputs/GroupForm.d.ts +6 -6
- package/dist/Components/Inputs/GroupForm.js +10 -11
- package/dist/Components/Inputs/InputRenderer.d.ts +9 -6
- package/dist/Components/Inputs/InputRenderer.js +39 -31
- package/dist/Components/Inputs/NumberBox.js +4 -2
- package/dist/Components/Inputs/PictureInput.d.ts +41 -0
- package/dist/Components/Inputs/PictureInput.js +70 -0
- package/dist/Components/Inputs/RadioGroup.d.ts +16 -3
- package/dist/Components/Inputs/RadioGroup.js +8 -3
- package/dist/Components/Inputs/RowsInput.d.ts +1 -1
- package/dist/Components/Inputs/RowsInput.js +18 -3
- package/dist/Components/Inputs/TabularForm.d.ts +5 -5
- package/dist/Components/Inputs/TabularForm.js +29 -29
- package/dist/Components/Inputs/TextArea.d.ts +6 -0
- package/dist/Components/Inputs/TextArea.js +14 -2
- package/dist/Components/Inputs/TextBox.js +4 -1
- package/dist/Components/Inputs/TextBoxTypes.d.ts +6 -0
- package/dist/Components/Inputs/TextBoxTypes.js +17 -0
- package/dist/Components/Inputs/TimePicker.js +4 -1
- package/dist/Components/Inputs/TreeView.d.ts +107 -6
- package/dist/Components/Inputs/TreeView.js +513 -30
- package/dist/Components/Layouts/MessageBox.d.ts +15 -2
- package/dist/Components/Layouts/MessageBox.js +56 -7
- package/dist/Components/Layouts/Popup.d.ts +13 -6
- package/dist/Components/Layouts/Popup.js +37 -9
- package/dist/Components/Layouts/PopupDock.d.ts +3 -1
- package/dist/Components/Layouts/PopupDock.js +2 -1
- package/dist/Components/Layouts/PopupHost.js +5 -4
- package/dist/Components/Layouts/ThemePicker.d.ts +3 -2
- package/dist/Components/Layouts/ThemePicker.js +16 -4
- package/dist/Components/Viewers/DataTable.js +205 -61
- package/dist/Components/Viewers/DataTableFilters.d.ts +1 -1
- package/dist/Components/Viewers/DataTableFilters.js +17 -2
- package/dist/Components/Viewers/DataTableParts.d.ts +46 -12
- package/dist/Components/Viewers/DataTableParts.js +62 -21
- package/dist/Components/Viewers/OwnerFiles.d.ts +175 -0
- package/dist/Components/Viewers/OwnerFiles.js +589 -0
- package/dist/Components/Viewers/QrCodeImage.d.ts +22 -0
- package/dist/Components/Viewers/QrCodeImage.js +15 -0
- package/dist/Components/Viewers/RecordCards.d.ts +16 -0
- package/dist/Components/Viewers/RecordCards.js +509 -0
- package/dist/Helpers/ApiModules.d.ts +3 -34
- package/dist/Helpers/ApiModules.js +3 -3
- package/dist/Helpers/ApiRoutes.d.ts +68 -26
- package/dist/Helpers/ApiRoutes.js +31 -27
- package/dist/Helpers/ArrayHelpers.d.ts +0 -0
- package/dist/Helpers/ArrayHelpers.js +2 -0
- package/dist/Helpers/BusyHooks.d.ts +6 -0
- package/dist/Helpers/BusyHooks.js +39 -0
- package/dist/Helpers/CodeHelpers.d.ts +97 -0
- package/dist/Helpers/CodeHelpers.js +332 -0
- package/dist/Helpers/CrudBackend.d.ts +114 -6
- package/dist/Helpers/CrudBackend.js +214 -11
- package/dist/Helpers/CrudColumns.d.ts +98 -0
- package/dist/Helpers/CrudColumns.js +160 -0
- package/dist/Helpers/CrudDetailsTabs.d.ts +58 -0
- package/dist/Helpers/CrudDetailsTabs.js +126 -0
- package/dist/Helpers/CrudHelpers.d.ts +130 -6
- package/dist/Helpers/CrudHelpers.js +304 -12
- package/dist/Helpers/CrudNarrowPick.d.ts +83 -0
- package/dist/Helpers/CrudNarrowPick.js +157 -0
- package/dist/Helpers/CrudRowForms.d.ts +15 -0
- package/dist/Helpers/CrudRowForms.js +43 -0
- package/dist/Helpers/CrudScopes.d.ts +32 -0
- package/dist/Helpers/CrudScopes.js +79 -0
- package/dist/Helpers/DropdownHelpers.d.ts +3 -1
- package/dist/Helpers/DropdownHelpers.js +6 -2
- package/dist/Helpers/ExcelHelpers.d.ts +1 -1
- package/dist/Helpers/ExcelHelpers.js +12 -11
- package/dist/Helpers/FileAdapter.d.ts +78 -0
- package/dist/Helpers/FileAdapter.js +102 -0
- package/dist/Helpers/FilePrimaries.d.ts +48 -0
- package/dist/Helpers/FilePrimaries.js +138 -0
- package/dist/Helpers/FormConfirm.d.ts +32 -0
- package/dist/Helpers/FormConfirm.js +40 -0
- package/dist/Helpers/FormStore.d.ts +90 -5
- package/dist/Helpers/FormStore.js +318 -22
- package/dist/Helpers/InputConditions.d.ts +50 -0
- package/dist/Helpers/InputConditions.js +168 -0
- package/dist/Helpers/InputMemory.d.ts +106 -0
- package/dist/Helpers/InputMemory.js +385 -0
- package/dist/Helpers/InputNarrowing.d.ts +18 -0
- package/dist/Helpers/InputNarrowing.js +67 -0
- package/dist/Helpers/InputParamsHelpers.d.ts +44 -1
- package/dist/Helpers/InputParamsHelpers.js +162 -71
- package/dist/Helpers/MessageBuilder.js +2 -0
- package/dist/Helpers/NexusDriveAdapter.d.ts +55 -0
- package/dist/Helpers/NexusDriveAdapter.js +207 -0
- package/dist/Helpers/NexusHelpers.d.ts +0 -0
- package/dist/Helpers/NexusHelpers.js +1 -0
- package/dist/Helpers/NumberHelpers.d.ts +95 -0
- package/dist/Helpers/NumberHelpers.js +126 -0
- package/dist/Helpers/Permissions.js +2 -1
- package/dist/Helpers/QrCode.d.ts +26 -0
- package/dist/Helpers/QrCode.js +463 -0
- package/dist/Helpers/RecordCards.d.ts +205 -0
- package/dist/Helpers/RecordCards.js +378 -0
- package/dist/Helpers/RequestCache.d.ts +47 -0
- package/dist/Helpers/RequestCache.js +132 -0
- package/dist/Helpers/RowsStore.d.ts +37 -2
- package/dist/Helpers/RowsStore.js +128 -10
- package/dist/Helpers/ServerPreview.d.ts +69 -0
- package/dist/Helpers/ServerPreview.js +99 -0
- package/dist/Helpers/TableColumns.js +4 -3
- package/dist/Helpers/TableExport.d.ts +7 -1
- package/dist/Helpers/TableExport.js +21 -15
- package/dist/Helpers/TableFilters.d.ts +1 -1
- package/dist/Helpers/TableFilters.js +24 -23
- package/dist/Helpers/TableHelpers.d.ts +24 -3
- package/dist/Helpers/TableHelpers.js +58 -12
- package/dist/Helpers/TableJoins.d.ts +83 -0
- package/dist/Helpers/TableJoins.js +284 -0
- package/dist/Helpers/TableStore.d.ts +26 -1
- package/dist/Helpers/TableStore.js +73 -7
- package/dist/Helpers/TreeStore.d.ts +306 -11
- package/dist/Helpers/TreeStore.js +1048 -90
- package/dist/Helpers/UserPreferences.d.ts +8 -0
- package/dist/Helpers/UserPreferences.js +17 -0
- package/dist/Interfaces/CrudInterfaces.d.ts +512 -14
- package/dist/Interfaces/FileInterfaces.d.ts +162 -0
- package/dist/Interfaces/FileInterfaces.js +4 -0
- package/dist/Interfaces/FormInterfaces.d.ts +393 -29
- package/dist/Interfaces/FormInterfaces.js +79 -1
- package/dist/Interfaces/InputInterfaces.d.ts +39 -3
- package/dist/Interfaces/MessageInterfaces.d.ts +1 -1
- package/dist/Interfaces/PreferenceInterfaces.d.ts +8 -0
- package/dist/Interfaces/PreferenceInterfaces.js +2 -5
- package/dist/Interfaces/RecordInterfaces.d.ts +367 -0
- package/dist/Interfaces/RecordInterfaces.js +1 -0
- package/dist/Interfaces/TableInterfaces.d.ts +160 -5
- package/dist/Services/ApiProxy.d.ts +36 -1
- package/dist/Services/ApiProxy.js +182 -52
- package/dist/Services/ApiProxyRules.d.ts +203 -0
- package/dist/Services/ApiProxyRules.js +426 -0
- package/dist/Services/ExcelApi.js +5 -0
- package/dist/Services/FileApi.d.ts +13 -0
- package/dist/Services/FileApi.js +29 -0
- package/dist/Services/ImageEditorLoader.d.ts +14 -0
- package/dist/Services/ImageEditorLoader.js +51 -0
- package/dist/Services/JoinSources.d.ts +80 -0
- package/dist/Services/JoinSources.js +150 -0
- package/dist/Services/ModuleImport.d.ts +7 -0
- package/dist/Services/ModuleImport.js +22 -0
- package/dist/Services/ServerApi.d.ts +13 -2
- package/dist/Services/ServerApi.js +8 -3
- package/dist/Shared.Index.d.ts +20 -0
- package/dist/Shared.Index.js +20 -0
- package/package.json +92 -85
- package/src/Styles/Nexus.Avatar.css +80 -79
- package/src/Styles/Nexus.Base.css +117 -117
- package/src/Styles/Nexus.Button.css +186 -180
- package/src/Styles/Nexus.Calendar.css +273 -273
- package/src/Styles/Nexus.Chat.css +1443 -1443
- package/src/Styles/Nexus.Choice.css +359 -343
- package/src/Styles/Nexus.Crud.css +542 -168
- package/src/Styles/Nexus.DateTime.css +81 -81
- package/src/Styles/Nexus.Dropdown.css +733 -725
- package/src/Styles/Nexus.Editor.css +295 -295
- package/src/Styles/Nexus.Excel.css +389 -389
- package/src/Styles/Nexus.Files.css +410 -0
- package/src/Styles/Nexus.Form.css +282 -279
- package/src/Styles/Nexus.Index.css +41 -37
- package/src/Styles/Nexus.Input.css +238 -4
- package/src/Styles/Nexus.Markdown.css +237 -237
- package/src/Styles/Nexus.Menu.css +246 -237
- package/src/Styles/Nexus.Popup.css +800 -724
- package/src/Styles/Nexus.Print.css +288 -0
- package/src/Styles/Nexus.QrCode.css +12 -0
- package/src/Styles/Nexus.Record.css +430 -0
- package/src/Styles/Nexus.Rows.css +637 -637
- package/src/Styles/Nexus.Slider.css +276 -276
- package/src/Styles/Nexus.Tab.Buttons.css +497 -432
- package/src/Styles/Nexus.Table.css +98 -35
- package/src/Styles/Nexus.Theme.Picker.css +59 -3
- package/src/Styles/Nexus.Themes.css +200 -194
- package/src/Styles/Nexus.Time.css +144 -144
- package/src/Styles/Nexus.Toast.css +263 -263
- package/src/Styles/Nexus.Tokens.css +94 -89
- package/src/Styles/Nexus.Tree.css +530 -431
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { type IconNode } from "nexus-icons";
|
|
2
2
|
import { type CSSProperties, type MouseEvent, type ReactNode } from "react";
|
|
3
3
|
import { type CellTextOptions } from "../../Helpers/TableHelpers.ts";
|
|
4
|
-
import type { TableColumn, TableRow, TableRowAction, TableState, TableViewColumn } from "../../Interfaces/TableInterfaces.ts";
|
|
4
|
+
import type { TableColumn, TableRow, TableRowAction, TableRowMark, TableState, TableViewColumn } from "../../Interfaces/TableInterfaces.ts";
|
|
5
5
|
/** A number as the table writes counts: 1,234. */
|
|
6
6
|
export declare const formatCount: (count: number) => string;
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* A value in its column's format: text, a tag for an option with a tone, a check for `true`. Empty values show a dash.
|
|
9
|
+
* A `join` column shows a placeholder until the record it looks up is in, and "Not found" for a key with no record; a
|
|
10
|
+
* column with a `tag` shows it after the value: "Asia" then "Trashed".
|
|
11
|
+
*/
|
|
8
12
|
export declare function TableCellValue<TRow extends TableRow>({ column, row, options }: {
|
|
9
13
|
column: TableColumn<TRow>;
|
|
10
14
|
row: TRow;
|
|
@@ -37,8 +41,11 @@ export declare function TableColumnGroup<TRow extends TableRow>({ columns, width
|
|
|
37
41
|
frame: TableFrameColumns;
|
|
38
42
|
colRefs: Map<string, HTMLTableColElement>;
|
|
39
43
|
}): import("react").JSX.Element;
|
|
40
|
-
/**
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* The number of a row, its checkbox, or both: the number until the pointer is over the row or something is selected. A
|
|
46
|
+
* row of a table whose rows are picked (`onPick`) also holds its radio button here, out of sight.
|
|
47
|
+
*/
|
|
48
|
+
export declare function TableIndexCell({ heading, rowSpan, own, number, numbered, selectable, checkbox, pick, }: {
|
|
42
49
|
heading?: boolean;
|
|
43
50
|
/** 2 in the heading while the header has a band of group headings above the columns' own. */
|
|
44
51
|
rowSpan?: number;
|
|
@@ -51,6 +58,8 @@ export declare function TableIndexCell({ heading, rowSpan, own, number, numbered
|
|
|
51
58
|
numbered: boolean;
|
|
52
59
|
selectable: boolean;
|
|
53
60
|
checkbox?: ReactNode;
|
|
61
|
+
/** The row's radio button, when rows are picked. */
|
|
62
|
+
pick?: ReactNode;
|
|
54
63
|
}): import("react").JSX.Element;
|
|
55
64
|
export interface TableRowViewProps<TRow extends TableRow> {
|
|
56
65
|
row: TRow;
|
|
@@ -66,8 +75,8 @@ export interface TableRowViewProps<TRow extends TableRow> {
|
|
|
66
75
|
busy: boolean;
|
|
67
76
|
flashed: boolean;
|
|
68
77
|
numbered: boolean;
|
|
69
|
-
/**
|
|
70
|
-
|
|
78
|
+
/** The row's marks (pinned, a favourite), worn one under the other where a row without any shows its number. */
|
|
79
|
+
marks?: readonly TableRowMark[];
|
|
71
80
|
/** Where the table's own columns sit; `null` for the ones it does not have. */
|
|
72
81
|
frame: TableFrameColumns;
|
|
73
82
|
/** The user gave a column a width, so the table lays its columns out from the `<colgroup>`. */
|
|
@@ -78,15 +87,35 @@ export interface TableRowViewProps<TRow extends TableRow> {
|
|
|
78
87
|
onOpen?: (row: TRow) => void;
|
|
79
88
|
/** A single click opens the row, as a double-click does. */
|
|
80
89
|
openOnClick?: boolean;
|
|
90
|
+
/** Rows are picked: a click picks this one (a double-click still opens it), whatever `openOnClick` says. */
|
|
91
|
+
onPick?: (row: TRow) => void;
|
|
92
|
+
/** This row is the picked one. */
|
|
93
|
+
picked?: boolean;
|
|
94
|
+
/** The name of the table's radio group, for the row's own radio button; none in a section above the page. */
|
|
95
|
+
pickName?: string;
|
|
81
96
|
}
|
|
82
97
|
/** One row. It renders again only when its row, its state, or the columns change. */
|
|
83
|
-
declare function TableRowViewInner<TRow extends TableRow>({ row, rowKey, number, label, columns, cellOptions, selectable, selected, selectionFull, busy, flashed, numbered,
|
|
98
|
+
declare function TableRowViewInner<TRow extends TableRow>({ row, rowKey, number, label, columns, cellOptions, selectable, selected, selectionFull, busy, flashed, numbered, marks, frame, sized, actions, onToggle, onAction, onOpen, openOnClick, onPick, picked, pickName, }: TableRowViewProps<TRow>): import("react").JSX.Element;
|
|
84
99
|
export declare const TableRowView: typeof TableRowViewInner;
|
|
85
100
|
/**
|
|
86
|
-
* The head of the
|
|
87
|
-
* how many there are, and the most
|
|
101
|
+
* The head of a section above the page: one row across the table with a button that folds the section's records open
|
|
102
|
+
* and shut, how many there are, and the most it can hold.
|
|
103
|
+
*/
|
|
104
|
+
export declare function TableSectionHead({ span, label, icon, count, max, loading, open, onToggle }: {
|
|
105
|
+
span: number;
|
|
106
|
+
label: string;
|
|
107
|
+
icon: IconNode;
|
|
108
|
+
count: number;
|
|
109
|
+
max?: number;
|
|
110
|
+
loading: boolean;
|
|
111
|
+
open: boolean;
|
|
112
|
+
onToggle: () => void;
|
|
113
|
+
}): import("react").JSX.Element;
|
|
114
|
+
/**
|
|
115
|
+
* The pinned section's head, by its 3.1.0 name: a `TableSectionHead` with the pin icon.
|
|
116
|
+
* @deprecated since 3.2.0, when favourites became a second section: use `TableSectionHead`, which takes the icon.
|
|
88
117
|
*/
|
|
89
|
-
export declare function TablePinnedHead(
|
|
118
|
+
export declare function TablePinnedHead(props: {
|
|
90
119
|
span: number;
|
|
91
120
|
label: string;
|
|
92
121
|
count: number;
|
|
@@ -128,11 +157,16 @@ export declare function TablePageSize({ pageSize, pageSizes, compact, onChange }
|
|
|
128
157
|
}): import("react").JSX.Element | null;
|
|
129
158
|
/**
|
|
130
159
|
* Under the table: which rows show and how many the search and the filters left ("Showing 41–50 of 234 · filtered
|
|
131
|
-
* from 1,000"), the page of how many, and the pager.
|
|
160
|
+
* from 1,000"), the page of how many, the rows per page when the table keeps them here (`pageSize`), and the pager.
|
|
161
|
+
*
|
|
162
|
+
* A table read whole (`whole`, every row on one page) has nothing to page: its footer shows only while a search or the
|
|
163
|
+
* filters leave rows out, and is otherwise kept for screen readers alone, so the count is still heard as it changes.
|
|
132
164
|
*/
|
|
133
|
-
export declare function TableFooter<TRow extends TableRow>({ state, disabled, onPage }: {
|
|
165
|
+
export declare function TableFooter<TRow extends TableRow>({ state, disabled, whole, pageSize, onPage }: {
|
|
134
166
|
state: TableState<TRow>;
|
|
135
167
|
disabled: boolean;
|
|
168
|
+
whole?: boolean;
|
|
169
|
+
pageSize?: ReactNode;
|
|
136
170
|
onPage: (page: number) => void;
|
|
137
171
|
}): import("react").JSX.Element;
|
|
138
172
|
export {};
|
|
@@ -1,21 +1,43 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { iconCheck, iconChevronDown, iconChevronLeft, iconChevronRight, iconDotsVertical, iconLoader2, iconPin, InlineIcon } from "nexus-icons";
|
|
4
4
|
import { memo } from "react";
|
|
5
5
|
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
6
6
|
import { columnAlign, columnOption, columnValue, cssLength, formatCellText, pageButtons, pageCount, TABLE_ACTIONS_COLUMN, TABLE_INDEX_COLUMN, } from "../../Helpers/TableHelpers.js";
|
|
7
|
+
import { joinedState } from "../../Helpers/TableJoins.js";
|
|
7
8
|
import { Button } from "../Documents/Button.js";
|
|
8
9
|
import { Menu } from "../Documents/Menu.js";
|
|
9
10
|
/*
|
|
10
11
|
* The parts of a data table: a cell in its column's format, a row with its number and checkbox in one column and its
|
|
11
|
-
* actions, the widths of the columns the user set, the head of the
|
|
12
|
+
* actions, the widths of the columns the user set, the head of a section above the page, the pager, and the footer. The
|
|
12
13
|
* details view of the CRUD draws values with the same `TableCellValue`.
|
|
13
14
|
*/
|
|
14
15
|
const countFormat = new Intl.NumberFormat("en-US");
|
|
15
16
|
/** A number as the table writes counts: 1,234. */
|
|
16
17
|
export const formatCount = (count) => countFormat.format(count);
|
|
17
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* A value in its column's format: text, a tag for an option with a tone, a check for `true`. Empty values show a dash.
|
|
20
|
+
* A `join` column shows a placeholder until the record it looks up is in, and "Not found" for a key with no record; a
|
|
21
|
+
* column with a `tag` shows it after the value: "Asia" then "Trashed".
|
|
22
|
+
*/
|
|
18
23
|
export function TableCellValue({ column, row, options }) {
|
|
24
|
+
const joined = column.join ? joinedState(column.join, row) : null;
|
|
25
|
+
if (joined?.status === "loading")
|
|
26
|
+
return _jsx("span", { className: "nx-table__bone", "aria-label": "Loading" });
|
|
27
|
+
if (joined?.status === "missing" || joined?.status === "failed") {
|
|
28
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { className: "nx-table__dash", children: "\u2014" }), joined.status === "missing" && _jsx(TableTagView, { tag: { label: "Not found", tone: "danger" } })] }));
|
|
29
|
+
}
|
|
30
|
+
const tag = column.tag?.(row, joined?.status === "ready" ? joined.record : undefined);
|
|
31
|
+
const value = _jsx(TableCellContent, { column: column, row: row, options: options });
|
|
32
|
+
if (!tag)
|
|
33
|
+
return value;
|
|
34
|
+
return (_jsxs(_Fragment, { children: [value, _jsx(TableTagView, { tag: tag })] }));
|
|
35
|
+
}
|
|
36
|
+
/** A short tag after a cell's value, in the look of a column option's tag. */
|
|
37
|
+
function TableTagView({ tag }) {
|
|
38
|
+
return (_jsx("span", { className: "nx-table__tag nx-table__tag--after", "data-tone": tag.tone, children: tag.label }));
|
|
39
|
+
}
|
|
40
|
+
function TableCellContent({ column, row, options }) {
|
|
19
41
|
const value = columnValue(column, row);
|
|
20
42
|
if (column.render)
|
|
21
43
|
return _jsx(_Fragment, { children: column.render(row, value) });
|
|
@@ -30,7 +52,7 @@ export function TableCellValue({ column, row, options }) {
|
|
|
30
52
|
// A moment needs the browser's zone, unknown while the page hydrates: nothing shows until then, not another zone's time.
|
|
31
53
|
if (column.format === "date-time" && !options.timeZone && value)
|
|
32
54
|
return _jsx("span", { className: "nx-table__pending" });
|
|
33
|
-
const text = formatCellText(column, value, options);
|
|
55
|
+
const text = formatCellText(column, value, options, row);
|
|
34
56
|
if (!text)
|
|
35
57
|
return _jsx("span", { className: "nx-table__dash", children: "\u2014" });
|
|
36
58
|
return _jsx(_Fragment, { children: text });
|
|
@@ -74,8 +96,11 @@ export function TableColumnGroup({ columns, widths, frame, colRefs, }) {
|
|
|
74
96
|
const own = (key, on) => on && _jsx("col", { ref: hold(key), style: { width: widths[key] } }, key);
|
|
75
97
|
return (_jsxs("colgroup", { children: [own(TABLE_INDEX_COLUMN, Boolean(frame.index)), columns.map(view => (_jsx("col", { ref: hold(view.column.key), style: { width: widths[view.column.key] ?? cssLength(view.column.width) ?? FALLBACK_COLUMN_WIDTH } }, view.column.key))), _jsx("col", { className: "nx-table__col-filler" }), own(TABLE_ACTIONS_COLUMN, Boolean(frame.actions))] }));
|
|
76
98
|
}
|
|
77
|
-
/**
|
|
78
|
-
|
|
99
|
+
/**
|
|
100
|
+
* The number of a row, its checkbox, or both: the number until the pointer is over the row or something is selected. A
|
|
101
|
+
* row of a table whose rows are picked (`onPick`) also holds its radio button here, out of sight.
|
|
102
|
+
*/
|
|
103
|
+
export function TableIndexCell({ heading, rowSpan, own, number, numbered, selectable, checkbox, pick, }) {
|
|
79
104
|
const shared = {
|
|
80
105
|
className: cx(heading ? "nx-table__heading" : "nx-table__cell", "nx-table__cell--index"),
|
|
81
106
|
"data-col": TABLE_INDEX_COLUMN,
|
|
@@ -85,7 +110,7 @@ export function TableIndexCell({ heading, rowSpan, own, number, numbered, select
|
|
|
85
110
|
"data-swap": (numbered && selectable) || undefined,
|
|
86
111
|
style: ownStyle(own, "left"),
|
|
87
112
|
};
|
|
88
|
-
const content = (_jsxs(_Fragment, { children: [numbered && (_jsx("span", { className: "nx-table__number", "aria-hidden": selectable || undefined, children: number })), checkbox] }));
|
|
113
|
+
const content = (_jsxs(_Fragment, { children: [numbered && (_jsx("span", { className: "nx-table__number", "aria-hidden": selectable || undefined, children: number })), checkbox, pick] }));
|
|
89
114
|
return heading ? (_jsx("th", { scope: "col", rowSpan: rowSpan, ...shared, children: content })) : (_jsx("td", { ...shared, children: content }));
|
|
90
115
|
}
|
|
91
116
|
/** What in a row is a control of its own: a click there does what the control does, and never opens the row. */
|
|
@@ -104,21 +129,31 @@ function opensRow(event, single) {
|
|
|
104
129
|
return !(selection && !selection.isCollapsed && event.currentTarget.contains(selection.anchorNode));
|
|
105
130
|
}
|
|
106
131
|
/** One row. It renders again only when its row, its state, or the columns change. */
|
|
107
|
-
function TableRowViewInner({ row, rowKey, number, label, columns, cellOptions, selectable, selected, selectionFull, busy, flashed, numbered,
|
|
132
|
+
function TableRowViewInner({ row, rowKey, number, label, columns, cellOptions, selectable, selected, selectionFull, busy, flashed, numbered, marks, frame, sized, actions, onToggle, onAction, onOpen, openOnClick, onPick, picked = false, pickName, }) {
|
|
108
133
|
const inline = actions?.filter(action => action.inline && action.icon) ?? [];
|
|
109
134
|
const inMenu = actions?.filter(action => !(action.inline && action.icon)) ?? [];
|
|
110
135
|
const items = inMenu.map(action => ({ value: action.id, label: action.label, icon: action.icon, description: action.description, tone: action.tone, disabled: action.disabled }));
|
|
111
|
-
|
|
136
|
+
// A click picks a row where rows are picked; opening it is then the double-click's.
|
|
137
|
+
const clickOpens = Boolean(onOpen && openOnClick && !onPick);
|
|
138
|
+
return (_jsxs("tr", { className: "nx-table__row", "data-key": rowKey, "data-selected": selected || undefined, "data-picked": picked || undefined, "data-busy": busy || undefined, "data-flash": flashed || undefined, "aria-busy": busy || undefined, "data-open": clickOpens || undefined, "data-pick": onPick ? "" : undefined,
|
|
112
139
|
// One way in: with a single click the row is already open by the time a double-click would arrive.
|
|
113
|
-
onClick:
|
|
140
|
+
onClick: onPick ? event => opensRow(event, true) && onPick(row) : clickOpens ? event => opensRow(event, true) && onOpen?.(row) : undefined, onDoubleClick: onOpen && !clickOpens ? event => opensRow(event, false) && onOpen(row) : undefined, children: [frame.index && (_jsx(TableIndexCell, { own: frame.index, number: marks?.length ? (_jsx("span", { className: "nx-table__marks", children: marks.map(mark => (_jsx(InlineIcon, { icon: mark.icon, className: "nx-table__mark", label: mark.label }, mark.label))) })) : (formatCount(number)), numbered: numbered || Boolean(marks?.length), selectable: selectable, checkbox: selectable && (_jsx("label", { className: "nx-choice nx-choice--sm nx-table__check", title: selectionFull ? "No more rows can be selected." : undefined, children: _jsx("input", { type: "checkbox", className: "nx-choice__control nx-choice__control--checkbox", checked: selected, disabled: selectionFull && !selected, "aria-label": `Select ${label}`, onClick: event => onToggle(row, event.currentTarget.checked, event), onChange: () => undefined }) })), pick: onPick &&
|
|
141
|
+
pickName && (_jsx("input", { type: "radio", className: "nx-visually-hidden nx-table__pick", name: pickName, checked: picked, "aria-label": label, onChange: () => onPick(row) })) })), columns.map(view => (_jsx("td", { className: cx("nx-table__cell", `nx-table__cell--${columnAlign(view.column)}`, view.column.wrap && "nx-table__cell--wrap"), "data-col": view.column.key, "data-pin": view.pin ?? undefined, "data-pin-edge": (view.pin && view.edge) || undefined, style: columnStyle(view, sized), children: _jsx("span", { className: "nx-table__value", children: _jsx(TableCellValue, { column: view.column, row: row, options: cellOptions }) }) }, view.column.key))), sized && _jsx("td", { className: "nx-table__cell nx-table__cell--filler" }), frame.actions && (_jsx("td", { className: "nx-table__cell nx-table__cell--actions", "data-col": TABLE_ACTIONS_COLUMN, "data-pin": "right", "data-pin-edge": frame.actions.edge || undefined, style: ownStyle(frame.actions, "right"), children: _jsxs("div", { className: "nx-table__actions", children: [inline.map(action => (_jsx(Button, { variant: "ghost", size: "sm", icon: action.icon, hoverTone: action.tone === "danger" ? "danger" : undefined, "aria-label": `${action.label}: ${label}`, title: action.label, "data-action": action.id, disabled: busy || action.disabled, onClick: () => onAction(row, action) }, action.id))), items.length > 0 && (_jsx(Menu, { items: items, align: "end", "aria-label": `Actions: ${label}`, onSelect: value => onAction(row, inMenu.find(action => action.id === value)), children: _jsx(Button, { variant: "ghost", size: "sm", icon: _jsx(InlineIcon, { icon: iconDotsVertical }), loading: busy, "aria-label": `More actions: ${label}`, title: "More actions" }) })), items.length === 0 && busy && _jsx(Button, { variant: "ghost", size: "sm", loading: true, "aria-label": `Working: ${label}` })] }) }))] }));
|
|
114
142
|
}
|
|
115
143
|
export const TableRowView = memo(TableRowViewInner);
|
|
116
144
|
/**
|
|
117
|
-
* The head of the
|
|
118
|
-
* how many there are, and the most
|
|
145
|
+
* The head of a section above the page: one row across the table with a button that folds the section's records open
|
|
146
|
+
* and shut, how many there are, and the most it can hold.
|
|
119
147
|
*/
|
|
120
|
-
export function
|
|
121
|
-
return (_jsx("tr", { className: "nx-table__row nx-
|
|
148
|
+
export function TableSectionHead({ span, label, icon, count, max, loading, open, onToggle }) {
|
|
149
|
+
return (_jsx("tr", { className: "nx-table__row nx-table__section-row", children: _jsx("td", { colSpan: span, className: "nx-table__section-cell", children: _jsxs("button", { type: "button", className: "nx-table__section-toggle", "aria-expanded": open, onClick: onToggle, children: [_jsx(InlineIcon, { icon: iconChevronRight, className: "nx-table__section-caret" }), _jsx(InlineIcon, { icon: icon, className: "nx-table__section-icon" }), _jsx("span", { className: "nx-table__section-title", children: label }), (count > 0 || !loading) && (_jsx("span", { className: "nx-table__section-count", children: max ? `${formatCount(count)} of ${formatCount(max)}` : formatCount(count) })), loading && _jsx(InlineIcon, { icon: iconLoader2, className: "nx-spin nx-table__section-loading" })] }) }) }));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* The pinned section's head, by its 3.1.0 name: a `TableSectionHead` with the pin icon.
|
|
153
|
+
* @deprecated since 3.2.0, when favourites became a second section: use `TableSectionHead`, which takes the icon.
|
|
154
|
+
*/
|
|
155
|
+
export function TablePinnedHead(props) {
|
|
156
|
+
return _jsx(TableSectionHead, { ...props, icon: iconPin });
|
|
122
157
|
}
|
|
123
158
|
/** Placeholder rows while the first rows load, in the shape of the columns. */
|
|
124
159
|
export function TableSkeletonRows({ count, cells, frame, sized }) {
|
|
@@ -144,14 +179,20 @@ export function TablePageSize({ pageSize, pageSizes, compact = false, onChange }
|
|
|
144
179
|
}
|
|
145
180
|
/**
|
|
146
181
|
* Under the table: which rows show and how many the search and the filters left ("Showing 41–50 of 234 · filtered
|
|
147
|
-
* from 1,000"), the page of how many, and the pager.
|
|
182
|
+
* from 1,000"), the page of how many, the rows per page when the table keeps them here (`pageSize`), and the pager.
|
|
183
|
+
*
|
|
184
|
+
* A table read whole (`whole`, every row on one page) has nothing to page: its footer shows only while a search or the
|
|
185
|
+
* filters leave rows out, and is otherwise kept for screen readers alone, so the count is still heard as it changes.
|
|
148
186
|
*/
|
|
149
|
-
export function TableFooter({ state, disabled, onPage }) {
|
|
187
|
+
export function TableFooter({ state, disabled, whole = false, pageSize, onPage }) {
|
|
150
188
|
const { status, rows, offset, matches, total, query } = state;
|
|
151
|
-
|
|
189
|
+
const ready = status === "ready" && total > 0;
|
|
190
|
+
const narrowed = Boolean(query.search || query.filters);
|
|
191
|
+
const range = ready && (_jsxs(_Fragment, { children: [rows.length ? (_jsxs(_Fragment, { children: ["Showing ", _jsx("b", { children: `${formatCount(rows.length ? offset + 1 : 0)}–${formatCount(offset + rows.length)}` }), " of ", _jsx("b", { children: formatCount(matches) })] })) : (_jsx(_Fragment, { children: "No rows on this page" })), narrowed && matches !== total && _jsxs("span", { className: "nx-table__range-all", children: [" \u00B7 filtered from ", formatCount(total)] })] }));
|
|
192
|
+
if (whole) {
|
|
193
|
+
return (_jsx("div", { className: ready && narrowed ? "nx-table__footer" : "nx-visually-hidden", children: _jsx("p", { className: "nx-table__range", "aria-live": "polite", children: range }) }));
|
|
194
|
+
}
|
|
195
|
+
if (!ready)
|
|
152
196
|
return _jsx("div", { className: "nx-table__footer" });
|
|
153
|
-
|
|
154
|
-
const last = offset + rows.length;
|
|
155
|
-
const pages = pageCount(matches, query.pageSize);
|
|
156
|
-
return (_jsxs("div", { className: "nx-table__footer", children: [_jsxs("p", { className: "nx-table__range", "aria-live": "polite", children: [rows.length ? (_jsxs(_Fragment, { children: ["Showing ", _jsx("b", { children: `${formatCount(first)}–${formatCount(last)}` }), " of ", _jsx("b", { children: formatCount(matches) })] })) : (_jsx(_Fragment, { children: "No rows on this page" })), (query.search || query.filters) && matches !== total && _jsxs("span", { className: "nx-table__range-all", children: [" \u00B7 filtered from ", formatCount(total)] })] }), _jsxs("div", { className: "nx-table__paging", children: [_jsxs("span", { className: "nx-table__page-info", children: ["Page ", formatCount(query.page), " of ", formatCount(pages)] }), _jsx(TablePager, { page: query.page, matches: matches, pageSize: query.pageSize, disabled: disabled, onPage: onPage })] })] }));
|
|
197
|
+
return (_jsxs("div", { className: "nx-table__footer", children: [_jsx("p", { className: "nx-table__range", "aria-live": "polite", children: range }), _jsxs("div", { className: "nx-table__paging", children: [pageSize, _jsxs("span", { className: "nx-table__page-info", children: ["Page ", formatCount(query.page), " of ", formatCount(pageCount(matches, query.pageSize))] }), _jsx(TablePager, { page: query.page, matches: matches, pageSize: query.pageSize, disabled: disabled, onPage: onPage })] })] }));
|
|
157
198
|
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { type ReactNode, type RefObject } from "react";
|
|
2
|
+
import type { ApiModuleValue, ApiResult, AppModule } from "../../Interfaces/ApiInterfaces.ts";
|
|
3
|
+
import { type FileOwner, type OwnerFiles, type PictureType, type StoredFile } from "../../Interfaces/FileInterfaces.ts";
|
|
4
|
+
import type { TableColumn, TableRow } from "../../Interfaces/TableInterfaces.ts";
|
|
5
|
+
import { type PopupHandle } from "../Layouts/PopupHost.tsx";
|
|
6
|
+
/** What a page declares for an owner's pictures: whose they are, and how a picture is made. */
|
|
7
|
+
export interface OwnerFilesParams<TModule extends ApiModuleValue = AppModule> extends FileOwner<TModule> {
|
|
8
|
+
/** The shape every picture is cropped to: `1` for a logo or a person, `4 / 3`, or `free` (default). */
|
|
9
|
+
aspect?: number | "free";
|
|
10
|
+
/** `circle` shows a person's picture round, and the editor's guide with it. Default `rect`. */
|
|
11
|
+
shape?: "rect" | "circle";
|
|
12
|
+
/** The largest picture kept, in pixels. Default the category's `pictureMaxSide` (1920), which it never passes. */
|
|
13
|
+
maxWidth?: number;
|
|
14
|
+
maxHeight?: number;
|
|
15
|
+
/**
|
|
16
|
+
* The kind a picture is saved as, fixed. Default: the kind it came in, and a PNG over the size limit becomes a JPEG
|
|
17
|
+
* (nothing see-through) or a WebP (keeping its see-through parts where the browser writes WebP).
|
|
18
|
+
*/
|
|
19
|
+
type?: PictureType;
|
|
20
|
+
/** 0-1, for JPEG and WebP, where the editor starts. Never above the category's `pictureQuality`. */
|
|
21
|
+
quality?: number;
|
|
22
|
+
/** Whose they are, in the window's title and the pictures' names: "Kathmandu branch". */
|
|
23
|
+
title?: string;
|
|
24
|
+
/** Shows the files with no way to change them, whatever the backend allows. */
|
|
25
|
+
readOnly?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Why the files may not be changed here, said under them: a record that is closed, a year that is locked. Set, the
|
|
28
|
+
* files are read only, as with `readOnly`. Without it, a person the backend lets only look is told the backend's own
|
|
29
|
+
* reason (`OwnerFiles.readOnlyReason`), or that they may look but not change.
|
|
30
|
+
*
|
|
31
|
+
* @example lockReason: row?.isClosed ? "The branch is closed: open it again to change its picture." : null
|
|
32
|
+
*/
|
|
33
|
+
lockReason?: string | null;
|
|
34
|
+
/** After a change on this page: the owner's picture now (null for none). */
|
|
35
|
+
onChange?: (primary: StoredFile | null) => void;
|
|
36
|
+
}
|
|
37
|
+
/** What a person the backend lets only look at an owner's files is told, when it gave no words of its own. */
|
|
38
|
+
export declare const READ_ONLY_REASON = "You can see these files, but you may not change them.";
|
|
39
|
+
/** The longest side of a stored picture when neither the params nor the backend say: Drive's default (`PICTURE_LIMITS`). */
|
|
40
|
+
export declare const MAX_PICTURE_SIDE: 1920;
|
|
41
|
+
type Status = {
|
|
42
|
+
kind: "idle";
|
|
43
|
+
} | {
|
|
44
|
+
kind: "loading";
|
|
45
|
+
} | {
|
|
46
|
+
kind: "ready";
|
|
47
|
+
data: OwnerFiles;
|
|
48
|
+
} | {
|
|
49
|
+
kind: "failed";
|
|
50
|
+
message: string;
|
|
51
|
+
};
|
|
52
|
+
/** Tells what a refused or failed call said, once, in the server's own words. */
|
|
53
|
+
export declare function toastFileFailure(title: string, answer: Pick<ApiResult, "message" | "aborted">): void;
|
|
54
|
+
/** One owner's files, and every change a person can make to them. `ownerId` null: nothing is read (a record not saved yet). */
|
|
55
|
+
export declare function useOwnerFiles(params: Omit<OwnerFilesParams<ApiModuleValue>, "ownerId"> & {
|
|
56
|
+
ownerId?: string | null;
|
|
57
|
+
}): {
|
|
58
|
+
status: Status;
|
|
59
|
+
data: OwnerFiles | null;
|
|
60
|
+
busy: string | null;
|
|
61
|
+
canWrite: boolean;
|
|
62
|
+
readOnlyReason: string | null;
|
|
63
|
+
pictures: boolean;
|
|
64
|
+
editorProblem: string | null;
|
|
65
|
+
actions: {
|
|
66
|
+
reload: () => Promise<void | StoredFile | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Chooses a picture, edits it, and makes it the owner's picture (the picture input's Upload). In a category that
|
|
69
|
+
* keeps one file, the new picture takes the place of the one kept (Replace).
|
|
70
|
+
*/
|
|
71
|
+
replace: () => Promise<void>;
|
|
72
|
+
/** Chooses several files and stores them: each picture through the editor, one at a time (the gallery's Upload). */
|
|
73
|
+
upload: () => Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Edits a stored picture; what is saved is a new picture, the owner's picture when the edited one was. In a category
|
|
76
|
+
* that keeps one file, the edited picture takes its place.
|
|
77
|
+
*/
|
|
78
|
+
edit: (file: StoredFile) => Promise<void>;
|
|
79
|
+
makePrimary: (file: StoredFile | null) => Promise<void> | null;
|
|
80
|
+
rename: (file: StoredFile) => Promise<void>;
|
|
81
|
+
remove: (file: StoredFile) => Promise<void>;
|
|
82
|
+
/** Shows the pictures in the editor module's viewer, from `file`. */
|
|
83
|
+
view: (file: StoredFile) => Promise<void>;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Keeps the keyboard focus in an owner's files through a change (`busy`). Its buttons stay focusable while it runs
|
|
88
|
+
* (`aria-disabled`, never `disabled`: a focused control switched off sends the focus to the page in every browser), and
|
|
89
|
+
* when it ends with the focused button gone - a deleted file's, Edit after Remove, a star once its picture is the main
|
|
90
|
+
* one - the focus goes to the first control left in the same tile, row or `role="group"` (the picture input's buttons),
|
|
91
|
+
* else the first in `root`. Only when the focus
|
|
92
|
+
* was in `root` as the change began (or on the page, after a confirmation, while `root` had it last), and only when it
|
|
93
|
+
* has dropped to the page since: a person who moved on keeps their place.
|
|
94
|
+
*/
|
|
95
|
+
export declare function useFocusThroughChange(root: RefObject<HTMLElement | null>, busy: string | null): void;
|
|
96
|
+
/** A control's props while a change runs: still focusable and announced as unavailable, its press ignored. */
|
|
97
|
+
export declare function busyProps(busy: string | null, run: () => void): {
|
|
98
|
+
readonly "aria-disabled": true | undefined;
|
|
99
|
+
readonly onClick: () => void;
|
|
100
|
+
};
|
|
101
|
+
/** The owner's picture as the page keeps it, read with the other rows' in one call. */
|
|
102
|
+
export declare function usePrimaryPicture(owner: FileOwner<ApiModuleValue> | null): StoredFile | null | undefined;
|
|
103
|
+
export interface OwnerPictureProps {
|
|
104
|
+
owner: FileOwner<ApiModuleValue> | null;
|
|
105
|
+
/** The picture's height: pixels, or any CSS length (`var(--a-size)`). Default 28, a table row's. */
|
|
106
|
+
size?: number | string;
|
|
107
|
+
aspect?: number | "free";
|
|
108
|
+
shape?: "rect" | "circle";
|
|
109
|
+
/** What it shows, for a screen reader and the tooltip: "Kathmandu branch's picture". */
|
|
110
|
+
label?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Whose picture it is, by name: without a picture, their initials stand in, on the tone the shared `Avatar` gives that
|
|
113
|
+
* name ("Ram Thapa" -> "RT"), rather than the picture icon. A person's or a company's row passes it.
|
|
114
|
+
*/
|
|
115
|
+
name?: string | null;
|
|
116
|
+
/** Makes it a button: a table cell opens the gallery with it. */
|
|
117
|
+
onClick?: () => void;
|
|
118
|
+
className?: string;
|
|
119
|
+
}
|
|
120
|
+
/** An owner's picture, small: its thumbnail, or, when it has none, the initials of its `name` or a picture icon. */
|
|
121
|
+
export declare function OwnerPicture({ owner, size, aspect, shape, label, name, onClick, className }: OwnerPictureProps): import("react").JSX.Element;
|
|
122
|
+
export interface PictureGalleryProps extends OwnerFilesParams<ApiModuleValue> {
|
|
123
|
+
/** `pictures` (two panes) or `documents` (a list). Default: documents when the category takes anything but pictures. */
|
|
124
|
+
view?: "pictures" | "documents";
|
|
125
|
+
/** Once the files are read: the view shown, `documents` or `pictures` (a window's title follows it). */
|
|
126
|
+
onViewKnown?: (view: "pictures" | "documents") => void;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* An owner's pictures, or documents for a category that takes PDF: upload several up to the category's limit, make
|
|
130
|
+
* one the main picture, view them in the editor module's viewer, edit one (saved as a new picture), delete.
|
|
131
|
+
*
|
|
132
|
+
* Pictures come in two panes, as the 2026-06-20 gallery did: the main picture large, with Upload and Remove (no main
|
|
133
|
+
* picture; the pictures stay) under it and the count and kinds; beside it the pictures as a grid, each with its own
|
|
134
|
+
* buttons inside it - View, Make main, Edit, Delete (Make main and Delete not on the main one) - shown on hover, on a
|
|
135
|
+
* keyboard's focus in the picture, and always where nothing can hover (a touch screen). Under 560px of its own width
|
|
136
|
+
* the main picture sits small beside its buttons, over the grid.
|
|
137
|
+
*/
|
|
138
|
+
export declare function PictureGallery(props: PictureGalleryProps): import("react").JSX.Element;
|
|
139
|
+
/** An owner's documents as a list: `PictureGallery` with `view="documents"`. */
|
|
140
|
+
export declare function DocumentList(props: OwnerFilesParams<ApiModuleValue>): import("react").JSX.Element;
|
|
141
|
+
export interface OpenPictureGalleryOptions extends PictureGalleryProps {
|
|
142
|
+
/** The window's title. Default: "Pictures" or "Documents", and whose. */
|
|
143
|
+
popupTitle?: ReactNode;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Opens an owner's pictures (or documents) in a window; one window per owner and category. Pictures fill a wide
|
|
147
|
+
* window edge to edge in their two panes, the grid scrolling; documents are a list in a narrower one. Without `view`,
|
|
148
|
+
* the title, icon and size follow what the category takes once its files are read: a category that takes PDF says
|
|
149
|
+
* "Documents".
|
|
150
|
+
*/
|
|
151
|
+
export declare function openPictureGallery({ popupTitle, ...props }: OpenPictureGalleryOptions): PopupHandle;
|
|
152
|
+
export interface PictureColumnParams<TRow extends TableRow> extends Omit<OwnerFilesParams<ApiModuleValue>, "ownerId" | "title" | "onChange" | "lockReason">, Partial<Omit<TableColumn<TRow>, "render" | "value">> {
|
|
153
|
+
/** The row's field that holds the owner's id. Default `id`. */
|
|
154
|
+
ownerKey?: string;
|
|
155
|
+
/** Whose the row's pictures are, for the window's title: `row => row.branchName`. */
|
|
156
|
+
rowTitle?: (row: TRow) => string;
|
|
157
|
+
/**
|
|
158
|
+
* The row's field with a name whose initials stand in for a row with no picture (`"fullname"`), as the shared `Avatar`
|
|
159
|
+
* draws a person. Without it, such a row shows the picture icon.
|
|
160
|
+
*/
|
|
161
|
+
nameKey?: string;
|
|
162
|
+
/** Why a row's pictures may not be changed (its window shows them read only, with this sentence), or nothing. */
|
|
163
|
+
lockReason?: string | null | ((row: TRow) => string | null | undefined);
|
|
164
|
+
/** After a change in the window a row opened. */
|
|
165
|
+
onChange?: (row: TRow, primary: StoredFile | null) => void;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A column with each row's picture: every visible row's read in one call per page, and a click opens the row's
|
|
169
|
+
* gallery. A change there redraws the row's picture without a reload.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* columns: [pictureColumn({ module: NexusModule.Enterprise, category: "branch-picture", rowTitle: row => row.branchName }), ...]
|
|
173
|
+
*/
|
|
174
|
+
export declare function pictureColumn<TRow extends TableRow>({ module, category, ownerKey, rowTitle, nameKey, lockReason, onChange, aspect, shape, maxWidth, maxHeight, type, quality, readOnly, view, ...column }: PictureColumnParams<TRow> & Pick<PictureGalleryProps, "view">): TableColumn<TRow>;
|
|
175
|
+
export {};
|