@eifi1/ui-kit 0.21.0 → 0.23.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/README.md +42 -25
- package/dist/chart.d.ts +19 -14
- package/dist/components/account-chips.d.ts +10 -3
- package/dist/components/account-chips.js +5 -2
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/account-settings.d.ts +33 -2
- package/dist/components/account-settings.js +43 -21
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/amount-input.d.ts +53 -14
- package/dist/components/amount-input.js +17 -28
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/autocomplete.d.ts +29 -0
- package/dist/components/autocomplete.js +134 -104
- package/dist/components/autocomplete.js.map +1 -1
- package/dist/components/button-group.d.ts +19 -14
- package/dist/components/calculator.d.ts +19 -14
- package/dist/components/checkbox-group.d.ts +104 -0
- package/dist/components/checkbox-group.js +111 -0
- package/dist/components/checkbox-group.js.map +1 -0
- package/dist/components/checkbox.d.ts +19 -0
- package/dist/components/checkbox.js +30 -7
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/chip.d.ts +18 -0
- package/dist/components/chip.js +47 -10
- package/dist/components/chip.js.map +1 -1
- package/dist/components/column-mapper.d.ts +182 -0
- package/dist/components/column-mapper.js +375 -0
- package/dist/components/column-mapper.js.map +1 -0
- package/dist/components/combobox-core.d.ts +39 -2
- package/dist/components/combobox-core.js +29 -6
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +91 -2
- package/dist/components/combobox.js +454 -308
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +69 -161
- package/dist/components/confirm-dialog.js +7 -8
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +16 -11
- package/dist/components/country-select.d.ts +167 -0
- package/dist/components/country-select.js +293 -0
- package/dist/components/country-select.js.map +1 -0
- package/dist/components/currency-select.d.ts +17 -1
- package/dist/components/currency-select.js +56 -23
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +69 -166
- package/dist/components/danger-confirm.js +144 -50
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +1 -2
- package/dist/components/data-table-filter-popover.d.ts +1 -2
- package/dist/components/data-table-filters.d.ts +1 -2
- package/dist/components/data-table-labels.d.ts +4 -97
- package/dist/components/data-table-labels.js +9 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table-pagination.d.ts +3 -1
- package/dist/components/data-table.d.ts +1 -2
- package/dist/components/data-table.js +98 -3
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +66 -5
- package/dist/components/date-picker.js +378 -66
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +42 -1
- package/dist/components/entity-combobox.js +154 -113
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +19 -14
- package/dist/components/field-parts.d.ts +224 -0
- package/dist/components/field-parts.js +156 -0
- package/dist/components/field-parts.js.map +1 -0
- package/dist/components/field-strip.d.ts +105 -0
- package/dist/components/field-strip.js +46 -0
- package/dist/components/field-strip.js.map +1 -0
- package/dist/components/file-button.d.ts +19 -14
- package/dist/components/file-button.js +13 -3
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +41 -15
- package/dist/components/file-dropzone.js +57 -34
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/form-actions.d.ts +18 -13
- package/dist/components/form-actions.js +69 -5
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/iban-input.d.ts +69 -0
- package/dist/components/iban-input.js +125 -0
- package/dist/components/iban-input.js.map +1 -0
- package/dist/components/icon-picker.d.ts +21 -2
- package/dist/components/icon-picker.js +19 -4
- package/dist/components/icon-picker.js.map +1 -1
- package/dist/components/inline-edit-field.d.ts +167 -0
- package/dist/components/inline-edit-field.js +293 -0
- package/dist/components/inline-edit-field.js.map +1 -0
- package/dist/components/language-select.d.ts +130 -0
- package/dist/components/language-select.js +18 -0
- package/dist/components/language-select.js.map +1 -0
- package/dist/components/line-items.d.ts +25 -3
- package/dist/components/line-items.js +55 -46
- package/dist/components/line-items.js.map +1 -1
- package/dist/components/list.d.ts +25 -0
- package/dist/components/list.js +16 -5
- package/dist/components/list.js.map +1 -1
- package/dist/components/money-field.d.ts +32 -14
- package/dist/components/money-field.js.map +1 -1
- package/dist/components/month-picker.d.ts +52 -4
- package/dist/components/month-picker.js +291 -86
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +26 -1
- package/dist/components/multi-entity-combobox.js +143 -102
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +8 -1
- package/dist/components/multi-select.js +9 -4
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +34 -19
- package/dist/components/number-field.js +6 -20
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +79 -19
- package/dist/components/number-input.js +90 -38
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +19 -14
- package/dist/components/one-time-code-input.d.ts +100 -0
- package/dist/components/one-time-code-input.js +137 -0
- package/dist/components/one-time-code-input.js.map +1 -0
- package/dist/components/phone-input.d.ts +69 -0
- package/dist/components/phone-input.js +171 -0
- package/dist/components/phone-input.js.map +1 -0
- package/dist/components/reauth-dialog.d.ts +2 -2
- package/dist/components/reauth-dialog.js +6 -8
- package/dist/components/reauth-dialog.js.map +1 -1
- package/dist/components/series-chart.d.ts +19 -14
- package/dist/components/settings-fields.d.ts +19 -14
- package/dist/components/share-card.d.ts +16 -11
- package/dist/components/sign-chip.d.ts +66 -0
- package/dist/components/sign-chip.js +39 -0
- package/dist/components/sign-chip.js.map +1 -0
- package/dist/components/swatch-picker.d.ts +43 -2
- package/dist/components/swatch-picker.js +80 -32
- package/dist/components/swatch-picker.js.map +1 -1
- package/dist/components/switch.d.ts +19 -0
- package/dist/components/switch.js +24 -6
- package/dist/components/switch.js.map +1 -1
- package/dist/components/text-link.d.ts +18 -13
- package/dist/components/tile-radio.d.ts +88 -13
- package/dist/components/tile-radio.js +28 -11
- package/dist/components/tile-radio.js.map +1 -1
- package/dist/components/time-input.d.ts +24 -15
- package/dist/components/time-input.js.map +1 -1
- package/dist/components/toggle-group.d.ts +47 -1
- package/dist/components/toggle-group.js +110 -69
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/trigger-aria.d.ts +3 -0
- package/dist/components/trigger-aria.js +3 -1
- package/dist/components/trigger-aria.js.map +1 -1
- package/dist/components/ui.d.ts +16 -11
- package/dist/components/ui.js +284 -88
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -2
- package/dist/{data-table-3mi2R3so.d.ts → data-table-labels-B7OdnM0S.d.ts} +140 -3
- package/dist/data-table.d.ts +1 -2
- package/dist/data-table.js +2 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-attachment.d.ts +1 -1
- package/dist/feedback/feedback-attachment.js +348 -41
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +1 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +3 -2
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +68 -253
- package/dist/feedback/feedback-thread.js +46 -10
- package/dist/feedback/feedback-thread.js.map +1 -1
- package/dist/{kit-labels-D1J2_jyD.d.ts → feedback-BxeQVzwq.d.ts} +1206 -20
- package/dist/{feedback-attachment-WFiXJ8We.d.ts → feedback-attachment-fGAzZPf0.d.ts} +178 -11
- package/dist/feedback.d.ts +66 -2
- package/dist/hooks/use-file-drop.d.ts +19 -14
- package/dist/i18n/defaults.d.ts +19 -14
- package/dist/i18n/defaults.js +19 -2
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.d.ts +19 -14
- package/dist/i18n/german.js +84 -5
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +15 -10
- package/dist/i18n/kit-labels.js +8 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/languages.d.ts +19 -14
- package/dist/i18n/locales/de-CH.d.ts +19 -14
- package/dist/i18n/locales/en.d.ts +19 -14
- package/dist/i18n/locales/en.js +16 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +19 -14
- package/dist/i18n/locales/es.js +83 -5
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +19 -14
- package/dist/i18n/locales/fr.js +82 -5
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +19 -14
- package/dist/i18n/locales/hu.js +85 -5
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +19 -14
- package/dist/i18n/locales/it.js +84 -5
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +19 -14
- package/dist/i18n/locales/zh.js +80 -5
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.d.ts +19 -14
- package/dist/i18n/review.js +27 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +21 -10
- package/dist/index.js +73 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/column-mapping.d.ts +81 -0
- package/dist/lib/column-mapping.js +108 -0
- package/dist/lib/column-mapping.js.map +1 -0
- package/dist/lib/countries.d.ts +43 -0
- package/dist/lib/countries.js +39 -0
- package/dist/lib/countries.js.map +1 -0
- package/dist/lib/decimal-marks.d.ts +46 -0
- package/dist/lib/decimal-marks.js +40 -0
- package/dist/lib/decimal-marks.js.map +1 -0
- package/dist/lib/iban.d.ts +98 -0
- package/dist/lib/iban.js +154 -0
- package/dist/lib/iban.js.map +1 -0
- package/dist/lib/isin.d.ts +30 -0
- package/dist/lib/isin.js +36 -0
- package/dist/lib/isin.js.map +1 -0
- package/dist/lib/phone.d.ts +69 -0
- package/dist/lib/phone.js +121 -0
- package/dist/lib/phone.js.map +1 -0
- package/dist/lib/table-text.d.ts +109 -1
- package/dist/lib/table-text.js +122 -1
- package/dist/lib/table-text.js.map +1 -1
- package/dist/rhf/fields.d.ts +233 -18
- package/dist/rhf/fields.js +456 -3
- package/dist/rhf/fields.js.map +1 -1
- package/dist/rhf/form.d.ts +19 -14
- package/dist/rhf.d.ts +22 -15
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +18 -13
- package/dist/shell/top-bar-brand.d.ts +19 -14
- package/dist/shell/topbar-action-menu.d.ts +36 -3
- package/dist/shell/topbar-action-menu.js +74 -33
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +18 -13
- package/dist/table-text.d.ts +1 -1
- package/dist/tour/tour.js +20 -24
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +49 -16
- package/dist/wizard/stepper-nav.js +4 -0
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard.d.ts +19 -14
- package/package.json +1 -1
- package/src/components/account-chips.tsx +17 -3
- package/src/components/account-settings.tsx +92 -26
- package/src/components/amount-input.tsx +68 -56
- package/src/components/autocomplete.tsx +198 -114
- package/src/components/checkbox-group.tsx +229 -0
- package/src/components/checkbox.tsx +72 -8
- package/src/components/chip.tsx +80 -10
- package/src/components/column-mapper.tsx +666 -0
- package/src/components/combobox-core.tsx +82 -9
- package/src/components/combobox.tsx +661 -340
- package/src/components/confirm-dialog.tsx +12 -8
- package/src/components/country-select.tsx +556 -0
- package/src/components/currency-select.tsx +109 -33
- package/src/components/danger-confirm.tsx +429 -82
- package/src/components/data-table-labels.ts +16 -1
- package/src/components/data-table.tsx +175 -6
- package/src/components/date-picker.tsx +595 -71
- package/src/components/entity-combobox.tsx +235 -124
- package/src/components/field-parts.tsx +403 -0
- package/src/components/field-strip.tsx +149 -0
- package/src/components/file-button.tsx +36 -3
- package/src/components/file-dropzone.tsx +106 -38
- package/src/components/form-actions.tsx +147 -6
- package/src/components/iban-input.tsx +231 -0
- package/src/components/icon-picker.tsx +47 -6
- package/src/components/inline-edit-field.tsx +533 -0
- package/src/components/language-select.tsx +78 -0
- package/src/components/line-items.tsx +35 -2
- package/src/components/list.tsx +55 -6
- package/src/components/money-field.tsx +13 -0
- package/src/components/month-picker.tsx +400 -63
- package/src/components/multi-entity-combobox.tsx +207 -120
- package/src/components/multi-select.tsx +80 -58
- package/src/components/number-field.tsx +28 -46
- package/src/components/number-input.tsx +210 -43
- package/src/components/one-time-code-input.tsx +288 -0
- package/src/components/phone-input.tsx +299 -0
- package/src/components/reauth-dialog.tsx +17 -18
- package/src/components/sign-chip.tsx +103 -0
- package/src/components/swatch-picker.tsx +143 -31
- package/src/components/switch.tsx +58 -7
- package/src/components/tile-radio.tsx +145 -29
- package/src/components/time-input.tsx +8 -1
- package/src/components/toggle-group.tsx +206 -73
- package/src/components/trigger-aria.ts +5 -0
- package/src/components/ui.tsx +479 -138
- package/src/data-table.ts +2 -1
- package/src/feedback/feedback-attachment.tsx +597 -46
- package/src/feedback/feedback-dialog.tsx +9 -3
- package/src/feedback/feedback-inbox.tsx +3 -2
- package/src/feedback/feedback-thread.tsx +113 -9
- package/src/i18n/defaults.ts +18 -1
- package/src/i18n/german.ts +89 -0
- package/src/i18n/kit-labels.tsx +82 -2
- package/src/i18n/locales/en.ts +36 -4
- package/src/i18n/locales/es.ts +87 -0
- package/src/i18n/locales/fr.ts +87 -0
- package/src/i18n/locales/hu.ts +83 -0
- package/src/i18n/locales/it.ts +88 -0
- package/src/i18n/locales/zh.ts +76 -0
- package/src/i18n/review.ts +26 -0
- package/src/index.ts +71 -3
- package/src/lib/column-mapping.ts +234 -0
- package/src/lib/countries.ts +91 -0
- package/src/lib/decimal-marks.ts +99 -0
- package/src/lib/iban.ts +171 -0
- package/src/lib/isin.ts +62 -0
- package/src/lib/phone.ts +211 -0
- package/src/lib/table-text.ts +271 -0
- package/src/rhf/fields.tsx +860 -9
- package/src/rhf.ts +3 -1
- package/src/shell/topbar-action-menu.tsx +134 -38
- package/src/tour/tour.tsx +66 -28
- package/src/wizard/stepper-nav.tsx +35 -1
|
@@ -3,7 +3,14 @@
|
|
|
3
3
|
// ships no translations; the English defaults below make the table usable with no
|
|
4
4
|
// wiring.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// A type-only import: erased at build time, so this module stays free of the table
|
|
7
|
+
// itself (and of react-router), which `i18n/defaults` relies on.
|
|
8
|
+
import type { DataTableSortLabels } from "./data-table";
|
|
9
|
+
|
|
10
|
+
/** The phone sort control's four keys (`sortBy`, `sortDefault`, `sortAscending`,
|
|
11
|
+
* `sortDescending`, 0.22.0) are {@link DataTableSortLabels}', declared beside the
|
|
12
|
+
* control and part of this namespace like every other key. */
|
|
13
|
+
export interface DataTableLabels extends DataTableSortLabels {
|
|
7
14
|
// Table chrome
|
|
8
15
|
columns: string;
|
|
9
16
|
selectAllRows: string;
|
|
@@ -143,6 +150,14 @@ export const DEFAULT_DATA_TABLE_LABELS: DataTableLabels = {
|
|
|
143
150
|
booleanTrue: "Yes",
|
|
144
151
|
booleanFalse: "No",
|
|
145
152
|
booleanUnset: "Not set",
|
|
153
|
+
// The phone sort control (0.22.0). The same words as `DEFAULT_DATA_TABLE_SORT_LABELS`
|
|
154
|
+
// in data-table.tsx, written out rather than spread in: importing that VALUE here
|
|
155
|
+
// would make data-table.tsx and this module import each other (data-table.tsx reads
|
|
156
|
+
// its resolver from here), and would pull the whole table into `i18n/defaults`.
|
|
157
|
+
sortBy: "Sort by",
|
|
158
|
+
sortDefault: "Default order",
|
|
159
|
+
sortAscending: "Ascending",
|
|
160
|
+
sortDescending: "Descending",
|
|
146
161
|
};
|
|
147
162
|
|
|
148
163
|
/**
|
|
@@ -3,8 +3,10 @@ import type { CSSProperties, ReactNode, TdHTMLAttributes, ThHTMLAttributes } fro
|
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import {
|
|
5
5
|
ArrowDown,
|
|
6
|
+
ArrowDownWideNarrow,
|
|
6
7
|
ArrowUp,
|
|
7
8
|
ArrowUpDown,
|
|
9
|
+
ArrowUpNarrowWide,
|
|
8
10
|
ChevronDown,
|
|
9
11
|
ChevronRight,
|
|
10
12
|
Filter,
|
|
@@ -12,7 +14,7 @@ import {
|
|
|
12
14
|
Trash2,
|
|
13
15
|
X,
|
|
14
16
|
} from "lucide-react";
|
|
15
|
-
import { Card, IconButton, Spinner } from "./ui";
|
|
17
|
+
import { Card, IconButton, Select, Spinner } from "./ui";
|
|
16
18
|
import { cn } from "../lib/cn";
|
|
17
19
|
import {
|
|
18
20
|
defaultFilterState,
|
|
@@ -33,7 +35,7 @@ import { FullBleedDialog } from "./full-bleed-dialog";
|
|
|
33
35
|
import { Popover } from "./popover";
|
|
34
36
|
import { useMediaQuery } from "../hooks/use-media-query";
|
|
35
37
|
import { useAnnounce } from "../hooks/use-announce";
|
|
36
|
-
import { resolveDataTableLabels, type DataTableLabels } from "./data-table-labels";
|
|
38
|
+
import { DEFAULT_DATA_TABLE_LABELS, resolveDataTableLabels, type DataTableLabels } from "./data-table-labels";
|
|
37
39
|
import { useKitLabelOverrides, useKitLocale } from "../i18n/kit-labels";
|
|
38
40
|
import { Tooltip } from "./tooltip";
|
|
39
41
|
import { dirOf, isRtl, type Direction } from "../lib/direction";
|
|
@@ -78,6 +80,14 @@ export interface DataTableColumn<T> {
|
|
|
78
80
|
* Default `"asc"`.
|
|
79
81
|
*/
|
|
80
82
|
firstSort?: SortDir;
|
|
83
|
+
/**
|
|
84
|
+
* The column's name as plain text, for the places a ReactNode `header` cannot go:
|
|
85
|
+
* the phone sort control's options ({@link DataTableProps.mobileSort}), the spoken
|
|
86
|
+
* "Sorted by …" and the column-settings checklist. Only needed when `header` is not
|
|
87
|
+
* a string (an icon, a unit suffix); without it those places fall back to the
|
|
88
|
+
* header string, then to `key`.
|
|
89
|
+
*/
|
|
90
|
+
headerText?: string;
|
|
81
91
|
/**
|
|
82
92
|
* Extra attributes for this column's `<td>` in a given row — a `data-*` hook, a
|
|
83
93
|
* `title`, an `aria-describedby`, a class. keksdose's accounts page
|
|
@@ -390,6 +400,18 @@ export interface DataTableProps<T> {
|
|
|
390
400
|
* wastes space (feedback #317). Desktop is unaffected.
|
|
391
401
|
*/
|
|
392
402
|
mobileCard?: (row: T) => ReactNode;
|
|
403
|
+
/**
|
|
404
|
+
* A "Sort by" select and a direction button above the phone card list (keksdose
|
|
405
|
+
* K10). The card list has no header row, so without it a phone user is stuck with
|
|
406
|
+
* whatever order the table opened in. It drives the same sort state as the column
|
|
407
|
+
* headers — `sorts`/`onSortsChange` when controlled, the URL and `storageKey` when
|
|
408
|
+
* not — and offers the columns a header click could sort (those with a `sortBy`).
|
|
409
|
+
* Each option is named by the column's `headerText`, else its string `header`.
|
|
410
|
+
*
|
|
411
|
+
* Off by default, so no existing phone layout gains a row. Strings:
|
|
412
|
+
* {@link DataTableSortLabels}. Phones only; the desktop table is unchanged.
|
|
413
|
+
*/
|
|
414
|
+
mobileSort?: boolean;
|
|
393
415
|
/**
|
|
394
416
|
* Swipe actions for a mobile row, revealed by dragging it horizontally. Return
|
|
395
417
|
* `null` (or empty sides) for rows that should not move — a locked row, one whose
|
|
@@ -683,7 +705,120 @@ function cleanAttrs(
|
|
|
683
705
|
*/
|
|
684
706
|
function columnLabel<T>(col: DataTableColumn<T>, labels?: DataTableLabels): string {
|
|
685
707
|
if (col.key === ROW_ACTIONS_KEY && labels) return labels.actions;
|
|
686
|
-
return typeof col.header === "string" ? col.header : col.key;
|
|
708
|
+
return col.headerText ?? (typeof col.header === "string" ? col.header : col.key);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// ---------- Phone sort control (keksdose K10) ----------
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* The phone sort control's strings (keksdose K10). They are `dataTable` strings —
|
|
715
|
+
* read from the table's resolved labels, so the `labels` prop and the provider's
|
|
716
|
+
* `dataTable` namespace reach them — and are declared here, beside the control, with
|
|
717
|
+
* English defaults until `DataTableLabels` declares them itself.
|
|
718
|
+
*/
|
|
719
|
+
export interface DataTableSortLabels {
|
|
720
|
+
/** The control's visible label: "Sort by". */
|
|
721
|
+
sortBy: string;
|
|
722
|
+
/** The "no sort" option — the rows in the order they were given: "Default order". */
|
|
723
|
+
sortDefault: string;
|
|
724
|
+
/** The direction button's name while the sort ascends: "Ascending". */
|
|
725
|
+
sortAscending: string;
|
|
726
|
+
/** …and while it descends: "Descending". */
|
|
727
|
+
sortDescending: string;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** The phone sort control's words, as they sit in {@link DEFAULT_DATA_TABLE_LABELS}
|
|
731
|
+
* (DataTableLabels extends DataTableSortLabels; one source for the English). */
|
|
732
|
+
export const DEFAULT_DATA_TABLE_SORT_LABELS: DataTableSortLabels = {
|
|
733
|
+
sortBy: DEFAULT_DATA_TABLE_LABELS.sortBy,
|
|
734
|
+
sortDefault: DEFAULT_DATA_TABLE_LABELS.sortDefault,
|
|
735
|
+
sortAscending: DEFAULT_DATA_TABLE_LABELS.sortAscending,
|
|
736
|
+
sortDescending: DEFAULT_DATA_TABLE_LABELS.sortDescending,
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
const flipDir = (d: SortDir): SortDir => (d === "asc" ? "desc" : "asc");
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* The card list's sort control: a "Sort by" select and a direction button.
|
|
743
|
+
*
|
|
744
|
+
* keksdose K10 (inputs audit 2026-10-02 §5; its aggregated report tables, #258): a
|
|
745
|
+
* table is sorted by its header row and the phone card list has none, so the two
|
|
746
|
+
* decisions the header carries — which column, which direction — were unreachable
|
|
747
|
+
* below the breakpoint. keksdose hand-built this row over its DataTable to answer
|
|
748
|
+
* "who did I pay the most" on the device it was asked on; this is that row, driven by
|
|
749
|
+
* the SAME sort state as the headers (controlled `sorts` included), so turning the
|
|
750
|
+
* phone sideways keeps the order and a sort chosen here is the one the URL and the
|
|
751
|
+
* storage key hold.
|
|
752
|
+
*
|
|
753
|
+
* The rules are the header's: a newly picked column starts in its `firstSort`, the
|
|
754
|
+
* direction button flips the primary sort (secondary ones stay), and "Default order"
|
|
755
|
+
* — the third click of a `"tri"` cycle — is offered only under `"tri"`, since a
|
|
756
|
+
* `"toggle"` table promises it is always ranked by something. The select's label is
|
|
757
|
+
* a real `<label>` beside it, and the button sits outside that label: a click inside
|
|
758
|
+
* a label is forwarded to the control it names, so a nested button would flip AND
|
|
759
|
+
* open the select.
|
|
760
|
+
*/
|
|
761
|
+
function MobileSort<T>({
|
|
762
|
+
columns,
|
|
763
|
+
sorts,
|
|
764
|
+
sortCycle,
|
|
765
|
+
compact,
|
|
766
|
+
labels,
|
|
767
|
+
onPick,
|
|
768
|
+
onFlip,
|
|
769
|
+
}: {
|
|
770
|
+
columns: DataTableColumn<T>[];
|
|
771
|
+
sorts: SortState[];
|
|
772
|
+
sortCycle: SortCycle;
|
|
773
|
+
compact: boolean;
|
|
774
|
+
labels: DataTableLabels;
|
|
775
|
+
onPick: (key: string | null) => void;
|
|
776
|
+
onFlip: () => void;
|
|
777
|
+
}) {
|
|
778
|
+
const selectId = useId();
|
|
779
|
+
const sortLabels: DataTableSortLabels = labels;
|
|
780
|
+
if (columns.length === 0) return null;
|
|
781
|
+
// A persisted or URL sort can name a column with no `sortBy` (or a hidden one): the
|
|
782
|
+
// sort chain drops it, and so does the control rather than claiming it.
|
|
783
|
+
const primary = sorts[0] && columns.some((c) => c.key === sorts[0].key) ? sorts[0] : null;
|
|
784
|
+
const offerDefault = sortCycle === "tri" || primary === null;
|
|
785
|
+
const desc = primary?.dir === "desc";
|
|
786
|
+
return (
|
|
787
|
+
<div
|
|
788
|
+
data-table-mobile-sort=""
|
|
789
|
+
className={cn(
|
|
790
|
+
"flex items-center gap-2 border-b border-[var(--border)]",
|
|
791
|
+
compact ? "px-3 py-1.5" : "px-4 py-2",
|
|
792
|
+
)}
|
|
793
|
+
>
|
|
794
|
+
<label htmlFor={selectId} className="shrink-0 text-xs text-[var(--text-muted)]">
|
|
795
|
+
{sortLabels.sortBy}
|
|
796
|
+
</label>
|
|
797
|
+
<Select
|
|
798
|
+
id={selectId}
|
|
799
|
+
size={compact ? "sm" : "md"}
|
|
800
|
+
className="min-w-0 flex-1"
|
|
801
|
+
value={primary?.key ?? ""}
|
|
802
|
+
onChange={(e) => onPick(e.target.value || null)}
|
|
803
|
+
>
|
|
804
|
+
{offerDefault && <option value="">{sortLabels.sortDefault}</option>}
|
|
805
|
+
{columns.map((col) => (
|
|
806
|
+
<option key={col.key} value={col.key}>
|
|
807
|
+
{columnLabel(col, labels)}
|
|
808
|
+
</option>
|
|
809
|
+
))}
|
|
810
|
+
</Select>
|
|
811
|
+
<IconButton
|
|
812
|
+
size={compact ? "xs" : "md"}
|
|
813
|
+
variant="secondary"
|
|
814
|
+
label={desc ? sortLabels.sortDescending : sortLabels.sortAscending}
|
|
815
|
+
disabled={primary === null}
|
|
816
|
+
onClick={onFlip}
|
|
817
|
+
>
|
|
818
|
+
{desc ? <ArrowDownWideNarrow /> : <ArrowUpNarrowWide />}
|
|
819
|
+
</IconButton>
|
|
820
|
+
</div>
|
|
821
|
+
);
|
|
687
822
|
}
|
|
688
823
|
|
|
689
824
|
/**
|
|
@@ -857,6 +992,7 @@ export function DataTable<T>({
|
|
|
857
992
|
mobileGroupBy,
|
|
858
993
|
mobileGroupLabel,
|
|
859
994
|
mobileCard,
|
|
995
|
+
mobileSort = false,
|
|
860
996
|
mobileSwipeActions,
|
|
861
997
|
leadingRow,
|
|
862
998
|
density = "comfortable",
|
|
@@ -1125,6 +1261,13 @@ export function DataTable<T>({
|
|
|
1125
1261
|
firstDir: col?.firstSort,
|
|
1126
1262
|
cycle: sortCycle,
|
|
1127
1263
|
});
|
|
1264
|
+
commitSorts(next, key);
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
// Header clicks and the phone sort control (`mobileSort`) land here alike, so both
|
|
1268
|
+
// go through the same owner and say the same thing.
|
|
1269
|
+
const commitSorts = (next: SortState[], key: string) => {
|
|
1270
|
+
const col = columns.find((c) => c.key === key);
|
|
1128
1271
|
if (onSortsChange) onSortsChange(next);
|
|
1129
1272
|
else setInternalSorts(next);
|
|
1130
1273
|
|
|
@@ -1405,9 +1548,9 @@ export function DataTable<T>({
|
|
|
1405
1548
|
|
|
1406
1549
|
// ---- Mobile card list (md:hidden) ----
|
|
1407
1550
|
// Renders the same paged/filtered/sorted slice but as stacked cards instead
|
|
1408
|
-
// of a horizontally-scrolling table.
|
|
1409
|
-
//
|
|
1410
|
-
//
|
|
1551
|
+
// of a horizontally-scrolling table. Column settings stay desktop-only; the
|
|
1552
|
+
// filters come through a bottom sheet (feedback #299) and the sort through the
|
|
1553
|
+
// opt-in `mobileSort` row (keksdose K10), both on the table's own state.
|
|
1411
1554
|
const mobileColumns = visibleColumns.filter((c) => !c.mobileHidden);
|
|
1412
1555
|
const mobilePrimaryCol =
|
|
1413
1556
|
mobileColumns.find((c) => c.mobilePrimary) ?? mobileColumns[0] ?? null;
|
|
@@ -1765,6 +1908,32 @@ export function DataTable<T>({
|
|
|
1765
1908
|
locale={locale}
|
|
1766
1909
|
/>
|
|
1767
1910
|
)}
|
|
1911
|
+
{mobileSort && (
|
|
1912
|
+
<MobileSort
|
|
1913
|
+
columns={visibleColumns.filter((c) => (!isServer || !!onSortsChange) && !!c.sortBy)}
|
|
1914
|
+
sorts={sorts}
|
|
1915
|
+
sortCycle={sortCycle}
|
|
1916
|
+
compact={compact}
|
|
1917
|
+
labels={labels}
|
|
1918
|
+
onPick={(key) => {
|
|
1919
|
+
if (key === null) {
|
|
1920
|
+
if (sorts.length > 0) commitSorts([], sorts[0].key);
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
if (sorts[0]?.key === key) return;
|
|
1924
|
+
// A newly picked column starts where its header's first click would.
|
|
1925
|
+
const col = columns.find((c) => c.key === key);
|
|
1926
|
+
commitSorts([{ key, dir: col?.firstSort ?? "asc" }], key);
|
|
1927
|
+
}}
|
|
1928
|
+
onFlip={() => {
|
|
1929
|
+
if (sorts.length === 0) return;
|
|
1930
|
+
commitSorts(
|
|
1931
|
+
sorts.map((s, i) => (i === 0 ? { ...s, dir: flipDir(s.dir) } : s)),
|
|
1932
|
+
sorts[0].key,
|
|
1933
|
+
);
|
|
1934
|
+
}}
|
|
1935
|
+
/>
|
|
1936
|
+
)}
|
|
1768
1937
|
<ul
|
|
1769
1938
|
className={cn(
|
|
1770
1939
|
"divide-y divide-[var(--border)]",
|