@eifi1/ui-kit 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -17
- package/dist/chart.d.ts +3 -2
- package/dist/components/alert-banner.d.ts +59 -10
- package/dist/components/alert-banner.js +114 -8
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +3 -0
- package/dist/components/button-group.d.ts +26 -0
- package/dist/components/button-group.js +49 -0
- package/dist/components/button-group.js.map +1 -0
- package/dist/components/calculator.d.ts +3 -0
- package/dist/components/chart-zoom.d.ts +63 -14
- package/dist/components/chart-zoom.js +82 -16
- package/dist/components/chart-zoom.js.map +1 -1
- package/dist/components/chip.d.ts +67 -2
- package/dist/components/chip.js +73 -8
- package/dist/components/chip.js.map +1 -1
- package/dist/components/confirm-dialog.d.ts +120 -0
- package/dist/components/confirm-dialog.js +96 -0
- package/dist/components/confirm-dialog.js.map +1 -0
- package/dist/components/copy-button.d.ts +62 -0
- package/dist/components/copy-button.js +95 -0
- package/dist/components/copy-button.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-pagination.d.ts +5 -1
- package/dist/components/data-table-pagination.js +71 -58
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table-sort.d.ts +28 -5
- package/dist/components/data-table-sort.js +11 -7
- package/dist/components/data-table-sort.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +544 -423
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +51 -5
- package/dist/components/date-picker.js +152 -40
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +60 -0
- package/dist/components/description-list.js +112 -0
- package/dist/components/description-list.js.map +1 -0
- package/dist/components/disclosure.d.ts +37 -2
- package/dist/components/disclosure.js +14 -5
- package/dist/components/disclosure.js.map +1 -1
- package/dist/components/facing-pair.d.ts +2 -0
- package/dist/components/file-button.d.ts +17 -1
- package/dist/components/file-button.js +8 -1
- package/dist/components/file-button.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +54 -9
- package/dist/components/file-dropzone.js +100 -70
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/floating-panel.d.ts +107 -0
- package/dist/components/floating-panel.js +206 -0
- package/dist/components/floating-panel.js.map +1 -0
- package/dist/components/full-bleed-dialog.d.ts +12 -1
- package/dist/components/full-bleed-dialog.js +28 -5
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/modal.d.ts +6 -2
- package/dist/components/modal.js +2 -1
- package/dist/components/modal.js.map +1 -1
- package/dist/components/number-field.d.ts +3 -0
- package/dist/components/number-input.d.ts +3 -0
- package/dist/components/numpad-sheet.d.ts +3 -0
- package/dist/components/progress-bar.d.ts +54 -0
- package/dist/components/progress-bar.js +94 -0
- package/dist/components/progress-bar.js.map +1 -0
- package/dist/components/scroll-area.d.ts +53 -0
- package/dist/components/scroll-area.js +86 -0
- package/dist/components/scroll-area.js.map +1 -0
- package/dist/components/separator.d.ts +23 -0
- package/dist/components/separator.js +24 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/series-chart-ticks.d.ts +34 -1
- package/dist/components/series-chart-ticks.js +83 -1
- package/dist/components/series-chart-ticks.js.map +1 -1
- package/dist/components/series-chart.d.ts +314 -19
- package/dist/components/series-chart.js +510 -120
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/skeleton.d.ts +36 -0
- package/dist/components/skeleton.js +35 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/stat-tile.d.ts +60 -6
- package/dist/components/stat-tile.js +60 -26
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/table.d.ts +83 -0
- package/dist/components/table.js +166 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/toggle-legend.d.ts +3 -2
- package/dist/components/toggle-legend.js +1 -1
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/tree-view.d.ts +129 -0
- package/dist/components/tree-view.js +376 -0
- package/dist/components/tree-view.js.map +1 -0
- package/dist/components/treemap.d.ts +9 -2
- package/dist/components/treemap.js +6 -2
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/ui.d.ts +94 -13
- package/dist/components/ui.js +111 -29
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/{data-table-filters-noy0Abvi.d.ts → data-table-filters-CF1PXqjQ.d.ts} +73 -3
- package/dist/data-table.d.ts +2 -2
- package/dist/data-table.js.map +1 -1
- package/dist/hooks/use-copy-to-clipboard.d.ts +28 -0
- package/dist/hooks/use-copy-to-clipboard.js +81 -0
- package/dist/hooks/use-copy-to-clipboard.js.map +1 -0
- package/dist/hooks/use-debounce.d.ts +43 -0
- package/dist/hooks/use-debounce.js +56 -0
- package/dist/hooks/use-debounce.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +72 -0
- package/dist/hooks/use-file-drop.js +57 -0
- package/dist/hooks/use-file-drop.js.map +1 -0
- package/dist/i18n/defaults.d.ts +3 -0
- package/dist/i18n/defaults.js +7 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +15 -0
- package/dist/i18n/kit-labels.js +6 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +43 -0
- package/dist/i18n/locales/de-CH-informal.js +8 -0
- package/dist/i18n/locales/de-CH-informal.js.map +1 -0
- package/dist/i18n/locales/de-CH.d.ts +3 -0
- package/dist/i18n/locales/de-CH.js +1 -14
- package/dist/i18n/locales/de-CH.js.map +1 -1
- package/dist/i18n/locales/de-informal.d.ts +64 -0
- package/dist/i18n/locales/de-informal.js +37 -0
- package/dist/i18n/locales/de-informal.js.map +1 -0
- package/dist/i18n/locales/de.d.ts +3 -0
- package/dist/i18n/locales/de.js +25 -0
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +3 -0
- package/dist/i18n/locales/es.js +25 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +3 -0
- package/dist/i18n/locales/fr.js +25 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +3 -0
- package/dist/i18n/locales/hu.js +25 -0
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +3 -0
- package/dist/i18n/locales/it.js +25 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +3 -0
- package/dist/i18n/locales/zh.js +25 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/swiss.d.ts +13 -0
- package/dist/i18n/swiss.js +19 -0
- package/dist/i18n/swiss.js.map +1 -0
- package/dist/index.d.ts +25 -10
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/dates.d.ts +37 -1
- package/dist/lib/dates.js +19 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/search/command-palette.d.ts +15 -1
- package/dist/search/command-palette.js +10 -2
- package/dist/search/command-palette.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +35 -2
- package/dist/wizard/stepper-nav.js +54 -22
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +107 -5
- package/dist/wizard/types.js +2 -1
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +141 -21
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-summary.d.ts +10 -2
- package/dist/wizard/wizard-summary.js +3 -1
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/dist/wizard.d.ts +4 -1
- package/dist/wizard.js.map +1 -1
- package/package.json +1 -1
- package/src/components/alert-banner.tsx +211 -20
- package/src/components/button-group.tsx +75 -0
- package/src/components/chart-zoom.tsx +158 -20
- package/src/components/chip.tsx +160 -9
- package/src/components/confirm-dialog.tsx +242 -0
- package/src/components/copy-button.tsx +158 -0
- package/src/components/data-table-pagination.tsx +19 -6
- package/src/components/data-table-sort.ts +49 -10
- package/src/components/data-table.tsx +293 -24
- package/src/components/date-picker.tsx +262 -57
- package/src/components/description-list.tsx +174 -0
- package/src/components/disclosure.tsx +58 -5
- package/src/components/file-button.tsx +22 -2
- package/src/components/file-dropzone.tsx +198 -100
- package/src/components/floating-panel.tsx +341 -0
- package/src/components/full-bleed-dialog.tsx +53 -5
- package/src/components/modal.tsx +9 -2
- package/src/components/progress-bar.tsx +163 -0
- package/src/components/scroll-area.tsx +129 -0
- package/src/components/separator.tsx +37 -0
- package/src/components/series-chart-ticks.ts +135 -0
- package/src/components/series-chart.tsx +934 -67
- package/src/components/skeleton.tsx +65 -0
- package/src/components/stat-tile.tsx +160 -27
- package/src/components/table.tsx +263 -0
- package/src/components/toggle-legend.tsx +4 -3
- package/src/components/tree-view.tsx +589 -0
- package/src/components/treemap.tsx +13 -2
- package/src/components/ui.tsx +270 -39
- package/src/data-table.ts +2 -0
- package/src/hooks/use-copy-to-clipboard.ts +122 -0
- package/src/hooks/use-debounce.ts +105 -0
- package/src/hooks/use-file-drop.ts +123 -0
- package/src/i18n/defaults.ts +6 -0
- package/src/i18n/kit-labels.tsx +19 -0
- package/src/i18n/locales/de-CH-informal.ts +10 -0
- package/src/i18n/locales/de-CH.ts +1 -16
- package/src/i18n/locales/de-informal.ts +61 -0
- package/src/i18n/locales/de.ts +25 -0
- package/src/i18n/locales/es.ts +25 -0
- package/src/i18n/locales/fr.ts +25 -0
- package/src/i18n/locales/hu.ts +25 -0
- package/src/i18n/locales/it.ts +25 -0
- package/src/i18n/locales/zh.ts +25 -0
- package/src/i18n/swiss.ts +25 -0
- package/src/index.ts +29 -0
- package/src/lib/dates.ts +48 -0
- package/src/search/command-palette.tsx +29 -3
- package/src/wizard/stepper-nav.tsx +102 -28
- package/src/wizard/types.ts +106 -4
- package/src/wizard/use-wizard.ts +211 -31
- package/src/wizard/wizard-summary.tsx +24 -12
- package/src/wizard.ts +3 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { SortState } from './components/data-table-sort.js';
|
|
3
|
+
import { SortDir, SortState, SortCycle } from './components/data-table-sort.js';
|
|
4
4
|
import { SwipeAction } from './components/swipeable-row.js';
|
|
5
5
|
import { DataTableLabels } from './components/data-table-labels.js';
|
|
6
6
|
|
|
@@ -28,6 +28,14 @@ interface DataTableColumn<T> {
|
|
|
28
28
|
* see without reaching into React elements it deliberately treats as opaque.
|
|
29
29
|
*/
|
|
30
30
|
noRowLink?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The direction this column sorts in on its FIRST click. `"desc"` for money and
|
|
33
|
+
* count columns, where the rows worth reading are the large ones and an ascending
|
|
34
|
+
* first click opens on the zero rows (keksdose's aggregated report tables). The
|
|
35
|
+
* rest of the cycle follows from it — see {@link DataTableProps.sortCycle}.
|
|
36
|
+
* Default `"asc"`.
|
|
37
|
+
*/
|
|
38
|
+
firstSort?: SortDir;
|
|
31
39
|
}
|
|
32
40
|
interface ServerPagination {
|
|
33
41
|
page: number;
|
|
@@ -239,7 +247,69 @@ interface DataTableProps<T> {
|
|
|
239
247
|
* "hide upcoming/scheduled" toggle).
|
|
240
248
|
*/
|
|
241
249
|
leadingRow?: ReactNode;
|
|
250
|
+
/**
|
|
251
|
+
* Row height. `"compact"` is lenkbank's in-card tables: five `text-xs` tables with
|
|
252
|
+
* `px-2 py-1` cells sitting inside cards, which at the default padding came out at
|
|
253
|
+
* twice their height and pushed the card's own content below the fold — the whole
|
|
254
|
+
* reason they were still hand-rolled `<table>`s. It tightens the header, the cells,
|
|
255
|
+
* the selection checkboxes, the pager and the phone cards together, so a compact
|
|
256
|
+
* table is compact everywhere rather than a dense body under a roomy header.
|
|
257
|
+
*
|
|
258
|
+
* Defaults to `"comfortable"`, which is the table every caller has today.
|
|
259
|
+
*/
|
|
260
|
+
density?: DataTableDensity;
|
|
261
|
+
/**
|
|
262
|
+
* What a repeated click on a sorted header does. `"tri"` (the default, and the only
|
|
263
|
+
* behaviour before 0.8.0): first direction → the other → unsorted. `"toggle"`: first
|
|
264
|
+
* direction ⇄ the other, never unsorted — for a report table that is always ranked
|
|
265
|
+
* by something. Each column's first direction is its own `firstSort`. `aria-sort`
|
|
266
|
+
* and the spoken "Sorted by …" follow whatever the click produced, so they are
|
|
267
|
+
* right under either cycle.
|
|
268
|
+
*/
|
|
269
|
+
sortCycle?: SortCycle;
|
|
270
|
+
/**
|
|
271
|
+
* The desktop table's power-user chrome, as one switch. `"full"` (default) is the
|
|
272
|
+
* table as it has always been. `"minimal"` is a compact report table in a half-width
|
|
273
|
+
* card: no column-settings rail, no resize handles, no multi-sort (and so no
|
|
274
|
+
* "Shift-click to add a sort" tooltip) — the three pieces that cost width and
|
|
275
|
+
* attention and that a ten-row summary never needs. Each can still be set on its
|
|
276
|
+
* own below; an explicit boolean wins over the preset.
|
|
277
|
+
*/
|
|
278
|
+
chrome?: DataTableChrome;
|
|
279
|
+
/**
|
|
280
|
+
* The vertical "Columns (n/m)" rail and its show/hide + auto-size panel. Default:
|
|
281
|
+
* on, unless `chrome="minimal"`. With it off, every column is shown and a hidden
|
|
282
|
+
* set persisted under `storageKey` is ignored — there would be no way to get a
|
|
283
|
+
* column back.
|
|
284
|
+
*/
|
|
285
|
+
columnSettings?: boolean;
|
|
286
|
+
/**
|
|
287
|
+
* The drag handles on the header's trailing edges. Default: on, unless
|
|
288
|
+
* `chrome="minimal"`. With it off, widths persisted under `storageKey` are ignored
|
|
289
|
+
* for the same reason as above: nothing could reset them.
|
|
290
|
+
*/
|
|
291
|
+
resizable?: boolean;
|
|
292
|
+
/**
|
|
293
|
+
* Shift-click adds a secondary sort criterion. Default: on, unless
|
|
294
|
+
* `chrome="minimal"`. With it off, a shift-click sorts like a plain click and the
|
|
295
|
+
* header drops the tooltip that advertises the gesture.
|
|
296
|
+
*/
|
|
297
|
+
multiSort?: boolean;
|
|
298
|
+
/**
|
|
299
|
+
* The card around the table — border, surface, radius, shadow. Set false to sit the
|
|
300
|
+
* table inside the app's own card, under its own caption and CSV button, without a
|
|
301
|
+
* frame inside a frame. The table's layout is unchanged; only the chrome goes.
|
|
302
|
+
* Default true.
|
|
303
|
+
*/
|
|
304
|
+
frame?: boolean;
|
|
305
|
+
/** Extra classes for the table's root element (the card, or with `frame={false}`
|
|
306
|
+
* the plain wrapper). Merged last, so a caller's margin or width wins. */
|
|
307
|
+
className?: string;
|
|
242
308
|
}
|
|
309
|
+
/** See {@link DataTableProps.chrome}. */
|
|
310
|
+
type DataTableChrome = "full" | "minimal";
|
|
311
|
+
/** See {@link DataTableProps.density}. */
|
|
312
|
+
type DataTableDensity = "comfortable" | "compact";
|
|
243
313
|
type FilterState = Record<string, FilterValue>;
|
|
244
314
|
|
|
245
315
|
/** What {@link DataTableProps.mobileSwipeActions} returns for one row. */
|
|
@@ -253,7 +323,7 @@ interface MobileSwipeActions {
|
|
|
253
323
|
/** Committed by dragging physically RIGHT, whatever the direction. */
|
|
254
324
|
right?: SwipeAction[];
|
|
255
325
|
}
|
|
256
|
-
declare function DataTable<T>({ rows, columns, rowKey, defaultPageSize, onRowClick, rowHref, expandedRow, isExpanded, rowClassName, rowAttributes, paginated, empty, storageKey, urlSync, fillHeight, maxBodyHeight, serverPagination, filters: filtersProp, onFiltersChange, sorts: sortsProp, onSortsChange, selection, labels: labelsProp, locale: localeProp, storageKeyPrefix, mobileExpandAsDialog, mobileGroupBy, mobileGroupLabel, mobileCard, mobileSwipeActions, leadingRow, }: DataTableProps<T>): react.JSX.Element;
|
|
326
|
+
declare function DataTable<T>({ rows, columns, rowKey, defaultPageSize, onRowClick, rowHref, expandedRow, isExpanded, rowClassName, rowAttributes, paginated, empty, storageKey, urlSync, fillHeight, maxBodyHeight, serverPagination, filters: filtersProp, onFiltersChange, sorts: sortsProp, onSortsChange, selection, labels: labelsProp, locale: localeProp, storageKeyPrefix, mobileExpandAsDialog, mobileGroupBy, mobileGroupLabel, mobileCard, mobileSwipeActions, leadingRow, density, sortCycle, chrome, columnSettings: columnSettingsProp, resizable: resizableProp, multiSort: multiSortProp, frame, className, }: DataTableProps<T>): react.JSX.Element;
|
|
257
327
|
|
|
258
328
|
/** How a column is filtered. `text`/`select`/`date`/`number` each read a value
|
|
259
329
|
* off the row and compare it against the user's {@link FilterValue}. */
|
|
@@ -313,4 +383,4 @@ declare function decodeFilterValueOfType(type: FilterValue["type"], raw: string)
|
|
|
313
383
|
/** Inverse of {@link encodeFilterValue}, typed by the column's filter config. */
|
|
314
384
|
declare function decodeFilterValue<T>(filter: ColumnFilter<T>, raw: string): FilterValue;
|
|
315
385
|
|
|
316
|
-
export { type ColumnFilter as C, DataTable as D, type FilterState as F, type MobileSwipeActions as M, type ServerPagination as S, type
|
|
386
|
+
export { type ColumnFilter as C, DataTable as D, type FilterState as F, type MobileSwipeActions as M, type ServerPagination as S, type DataTableChrome as a, type DataTableColumn as b, type DataTableDensity as c, type DataTableProps as d, type FilterValue as e, decodeFilterValue as f, decodeFilterValueOfType as g, defaultFilterState as h, encodeFilterValue as i, isFilterActive as j, rowMatches as k, resolveFilter as r };
|
package/dist/data-table.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { DEFAULT_DATA_TABLE_LABELS, DataTableLabels, missingDataTableLabels, resolveDataTableLabels } from './components/data-table-labels.js';
|
|
2
|
-
export { SortDir, SortState, decodeSorts, encodeSorts, nextSorts, normalizeSorts } from './components/data-table-sort.js';
|
|
3
|
-
export { C as ColumnFilter, D as DataTable, a as
|
|
2
|
+
export { SortCycle, SortDir, SortState, SortStepOptions, decodeSorts, encodeSorts, nextSorts, normalizeSorts } from './components/data-table-sort.js';
|
|
3
|
+
export { C as ColumnFilter, D as DataTable, a as DataTableChrome, b as DataTableColumn, c as DataTableDensity, d as DataTableProps, F as FilterState, e as FilterValue, M as MobileSwipeActions, S as ServerPagination, f as decodeFilterValue, g as decodeFilterValueOfType, h as defaultFilterState, i as encodeFilterValue, j as isFilterActive, r as resolveFilter, k as rowMatches } from './data-table-filters-CF1PXqjQ.js';
|
|
4
4
|
export { PAGE_SIZE_OPTIONS, Pagination } from './components/data-table-pagination.js';
|
|
5
5
|
export { FilterPopover } from './components/data-table-filter-popover.js';
|
|
6
6
|
import 'react';
|
package/dist/data-table.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/data-table.ts"],"sourcesContent":["// `@eifi1/ui-kit/data-table` — the table suite.\n//\n// A re-slicing of the main barrel, not a new API. This entry point requires\n// `react-router`: DataTable calls useSearchParams unconditionally, above any `urlSync`\n// branch, so a Router is needed even with URL sync switched off.\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// `SortState` comes from data-table-sort above; re-exporting the module wholesale\n// would collide with it, which is why the main barrel names these explicitly too.\nexport { DataTable } from \"./components/data-table\";\nexport type {\n DataTableColumn,\n DataTableProps,\n ServerPagination,\n FilterState,\n MobileSwipeActions,\n} from \"./components/data-table\";\n"],"mappings":";AAKA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/data-table.ts"],"sourcesContent":["// `@eifi1/ui-kit/data-table` — the table suite.\n//\n// A re-slicing of the main barrel, not a new API. This entry point requires\n// `react-router`: DataTable calls useSearchParams unconditionally, above any `urlSync`\n// branch, so a Router is needed even with URL sync switched off.\nexport * from \"./components/data-table-labels\";\nexport * from \"./components/data-table-sort\";\nexport * from \"./components/data-table-filters\";\nexport * from \"./components/data-table-pagination\";\nexport { FilterPopover } from \"./components/data-table-filter-popover\";\n// `SortState` comes from data-table-sort above; re-exporting the module wholesale\n// would collide with it, which is why the main barrel names these explicitly too.\nexport { DataTable } from \"./components/data-table\";\nexport type {\n DataTableColumn,\n DataTableProps,\n ServerPagination,\n FilterState,\n MobileSwipeActions,\n DataTableDensity,\n DataTableChrome,\n} from \"./components/data-table\";\n"],"mappings":";AAKA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,qBAAqB;AAG9B,SAAS,iBAAiB;","names":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
type CopyState = "idle" | "copied" | "failed";
|
|
2
|
+
interface UseCopyToClipboardOptions {
|
|
3
|
+
/** How long `copied` / `failed` stays up before the state returns to `idle`, in
|
|
4
|
+
* ms. `0` keeps it until the next copy or {@link UseCopyToClipboardReturn.reset}. */
|
|
5
|
+
resetAfter?: number;
|
|
6
|
+
}
|
|
7
|
+
interface UseCopyToClipboardReturn {
|
|
8
|
+
state: CopyState;
|
|
9
|
+
/** Copy `text`. Resolves to whether it actually reached the clipboard — the same
|
|
10
|
+
* answer `state` gives, for a caller that wants to act on it directly. */
|
|
11
|
+
copy: (text: string) => Promise<boolean>;
|
|
12
|
+
reset: () => void;
|
|
13
|
+
}
|
|
14
|
+
/** Copy `text`, by the Clipboard API when there is one and the legacy path when
|
|
15
|
+
* there is not — or when the API refuses (a denied permission, a document that is
|
|
16
|
+
* not focused). Never throws. */
|
|
17
|
+
declare function copyToClipboard(text: string): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Copy text and KNOW whether it worked.
|
|
20
|
+
*
|
|
21
|
+
* keksdose had two copy buttons that flipped to "Copied" on click and never looked at
|
|
22
|
+
* the promise — so on the http LAN build, where there is no Clipboard API, they
|
|
23
|
+
* confirmed a copy that had not happened. The state here is set from the result, and
|
|
24
|
+
* a failure is a state of its own rather than a quiet return to idle.
|
|
25
|
+
*/
|
|
26
|
+
declare function useCopyToClipboard({ resetAfter }?: UseCopyToClipboardOptions): UseCopyToClipboardReturn;
|
|
27
|
+
|
|
28
|
+
export { type CopyState, type UseCopyToClipboardOptions, type UseCopyToClipboardReturn, copyToClipboard, useCopyToClipboard };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
function legacyCopy(text) {
|
|
4
|
+
if (typeof document === "undefined" || typeof document.execCommand !== "function") return false;
|
|
5
|
+
const active = document.activeElement;
|
|
6
|
+
const selection = document.getSelection();
|
|
7
|
+
const ranges = [];
|
|
8
|
+
if (selection) for (let i = 0; i < selection.rangeCount; i++) ranges.push(selection.getRangeAt(i));
|
|
9
|
+
const area = document.createElement("textarea");
|
|
10
|
+
area.value = text;
|
|
11
|
+
area.setAttribute("readonly", "");
|
|
12
|
+
area.style.position = "fixed";
|
|
13
|
+
area.style.top = "0";
|
|
14
|
+
area.style.insetInlineStart = "-9999px";
|
|
15
|
+
area.style.opacity = "0";
|
|
16
|
+
document.body.appendChild(area);
|
|
17
|
+
area.select();
|
|
18
|
+
let ok = false;
|
|
19
|
+
try {
|
|
20
|
+
ok = document.execCommand("copy");
|
|
21
|
+
} catch {
|
|
22
|
+
ok = false;
|
|
23
|
+
}
|
|
24
|
+
area.remove();
|
|
25
|
+
if (selection) {
|
|
26
|
+
selection.removeAllRanges();
|
|
27
|
+
for (const r of ranges) selection.addRange(r);
|
|
28
|
+
}
|
|
29
|
+
active?.focus?.();
|
|
30
|
+
return ok;
|
|
31
|
+
}
|
|
32
|
+
async function copyToClipboard(text) {
|
|
33
|
+
const clipboard = typeof navigator !== "undefined" ? navigator.clipboard : void 0;
|
|
34
|
+
if (clipboard && typeof clipboard.writeText === "function") {
|
|
35
|
+
try {
|
|
36
|
+
await clipboard.writeText(text);
|
|
37
|
+
return true;
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return legacyCopy(text);
|
|
42
|
+
}
|
|
43
|
+
function useCopyToClipboard({ resetAfter = 2e3 } = {}) {
|
|
44
|
+
const [state, setState] = useState("idle");
|
|
45
|
+
const timer = useRef(null);
|
|
46
|
+
const mounted = useRef(true);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
mounted.current = true;
|
|
49
|
+
return () => {
|
|
50
|
+
mounted.current = false;
|
|
51
|
+
if (timer.current) clearTimeout(timer.current);
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
const reset = useCallback(() => {
|
|
55
|
+
if (timer.current) clearTimeout(timer.current);
|
|
56
|
+
timer.current = null;
|
|
57
|
+
setState("idle");
|
|
58
|
+
}, []);
|
|
59
|
+
const copy = useCallback(
|
|
60
|
+
async (text) => {
|
|
61
|
+
if (timer.current) clearTimeout(timer.current);
|
|
62
|
+
const ok = await copyToClipboard(text);
|
|
63
|
+
if (!mounted.current) return ok;
|
|
64
|
+
setState(ok ? "copied" : "failed");
|
|
65
|
+
if (resetAfter > 0) {
|
|
66
|
+
timer.current = setTimeout(() => {
|
|
67
|
+
timer.current = null;
|
|
68
|
+
setState("idle");
|
|
69
|
+
}, resetAfter);
|
|
70
|
+
}
|
|
71
|
+
return ok;
|
|
72
|
+
},
|
|
73
|
+
[resetAfter]
|
|
74
|
+
);
|
|
75
|
+
return { state, copy, reset };
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
copyToClipboard,
|
|
79
|
+
useCopyToClipboard
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=use-copy-to-clipboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-copy-to-clipboard.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport type CopyState = \"idle\" | \"copied\" | \"failed\";\n\nexport interface UseCopyToClipboardOptions {\n /** How long `copied` / `failed` stays up before the state returns to `idle`, in\n * ms. `0` keeps it until the next copy or {@link UseCopyToClipboardReturn.reset}. */\n resetAfter?: number;\n}\n\nexport interface UseCopyToClipboardReturn {\n state: CopyState;\n /** Copy `text`. Resolves to whether it actually reached the clipboard — the same\n * answer `state` gives, for a caller that wants to act on it directly. */\n copy: (text: string) => Promise<boolean>;\n reset: () => void;\n}\n\n/**\n * The legacy path: select a throwaway `<textarea>` and ask the document to copy it.\n *\n * `navigator.clipboard` exists only in a secure context, so an app opened over plain\n * http on a LAN address (how keksdose is tested on a phone) has no Clipboard API at\n * all. `execCommand(\"copy\")` is deprecated but still implemented everywhere, and it\n * answers with a boolean, which is all this needs. Focus and the user's selection are\n * put back afterwards: copying must not move the keyboard.\n */\nfunction legacyCopy(text: string): boolean {\n if (typeof document === \"undefined\" || typeof document.execCommand !== \"function\") return false;\n const active = document.activeElement as HTMLElement | null;\n const selection = document.getSelection();\n const ranges: Range[] = [];\n if (selection) for (let i = 0; i < selection.rangeCount; i++) ranges.push(selection.getRangeAt(i));\n\n const area = document.createElement(\"textarea\");\n area.value = text;\n area.setAttribute(\"readonly\", \"\");\n // Off-screen but rendered: a `display: none` textarea cannot be selected.\n area.style.position = \"fixed\";\n area.style.top = \"0\";\n area.style.insetInlineStart = \"-9999px\";\n area.style.opacity = \"0\";\n document.body.appendChild(area);\n area.select();\n let ok = false;\n try {\n ok = document.execCommand(\"copy\");\n } catch {\n ok = false;\n }\n area.remove();\n if (selection) {\n selection.removeAllRanges();\n for (const r of ranges) selection.addRange(r);\n }\n active?.focus?.();\n return ok;\n}\n\n/** Copy `text`, by the Clipboard API when there is one and the legacy path when\n * there is not — or when the API refuses (a denied permission, a document that is\n * not focused). Never throws. */\nexport async function copyToClipboard(text: string): Promise<boolean> {\n const clipboard = typeof navigator !== \"undefined\" ? navigator.clipboard : undefined;\n if (clipboard && typeof clipboard.writeText === \"function\") {\n try {\n await clipboard.writeText(text);\n return true;\n } catch {\n // Fall through: the API exists but refused. The legacy path sometimes succeeds\n // where the permission prompt was dismissed.\n }\n }\n return legacyCopy(text);\n}\n\n/**\n * Copy text and KNOW whether it worked.\n *\n * keksdose had two copy buttons that flipped to \"Copied\" on click and never looked at\n * the promise — so on the http LAN build, where there is no Clipboard API, they\n * confirmed a copy that had not happened. The state here is set from the result, and\n * a failure is a state of its own rather than a quiet return to idle.\n */\nexport function useCopyToClipboard({ resetAfter = 2000 }: UseCopyToClipboardOptions = {}): UseCopyToClipboardReturn {\n const [state, setState] = useState<CopyState>(\"idle\");\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const mounted = useRef(true);\n\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n if (timer.current) clearTimeout(timer.current);\n };\n }, []);\n\n const reset = useCallback(() => {\n if (timer.current) clearTimeout(timer.current);\n timer.current = null;\n setState(\"idle\");\n }, []);\n\n const copy = useCallback(\n async (text: string) => {\n if (timer.current) clearTimeout(timer.current);\n const ok = await copyToClipboard(text);\n if (!mounted.current) return ok;\n setState(ok ? \"copied\" : \"failed\");\n if (resetAfter > 0) {\n timer.current = setTimeout(() => {\n timer.current = null;\n setState(\"idle\");\n }, resetAfter);\n }\n return ok;\n },\n [resetAfter],\n );\n\n return { state, copy, reset };\n}\n"],"mappings":";AAAA,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AA2BzD,SAAS,WAAW,MAAuB;AACzC,MAAI,OAAO,aAAa,eAAe,OAAO,SAAS,gBAAgB,WAAY,QAAO;AAC1F,QAAM,SAAS,SAAS;AACxB,QAAM,YAAY,SAAS,aAAa;AACxC,QAAM,SAAkB,CAAC;AACzB,MAAI,UAAW,UAAS,IAAI,GAAG,IAAI,UAAU,YAAY,IAAK,QAAO,KAAK,UAAU,WAAW,CAAC,CAAC;AAEjG,QAAM,OAAO,SAAS,cAAc,UAAU;AAC9C,OAAK,QAAQ;AACb,OAAK,aAAa,YAAY,EAAE;AAEhC,OAAK,MAAM,WAAW;AACtB,OAAK,MAAM,MAAM;AACjB,OAAK,MAAM,mBAAmB;AAC9B,OAAK,MAAM,UAAU;AACrB,WAAS,KAAK,YAAY,IAAI;AAC9B,OAAK,OAAO;AACZ,MAAI,KAAK;AACT,MAAI;AACF,SAAK,SAAS,YAAY,MAAM;AAAA,EAClC,QAAQ;AACN,SAAK;AAAA,EACP;AACA,OAAK,OAAO;AACZ,MAAI,WAAW;AACb,cAAU,gBAAgB;AAC1B,eAAW,KAAK,OAAQ,WAAU,SAAS,CAAC;AAAA,EAC9C;AACA,UAAQ,QAAQ;AAChB,SAAO;AACT;AAKA,eAAsB,gBAAgB,MAAgC;AACpE,QAAM,YAAY,OAAO,cAAc,cAAc,UAAU,YAAY;AAC3E,MAAI,aAAa,OAAO,UAAU,cAAc,YAAY;AAC1D,QAAI;AACF,YAAM,UAAU,UAAU,IAAI;AAC9B,aAAO;AAAA,IACT,QAAQ;AAAA,IAGR;AAAA,EACF;AACA,SAAO,WAAW,IAAI;AACxB;AAUO,SAAS,mBAAmB,EAAE,aAAa,IAAK,IAA+B,CAAC,GAA6B;AAClH,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoB,MAAM;AACpD,QAAM,QAAQ,OAA6C,IAAI;AAC/D,QAAM,UAAU,OAAO,IAAI;AAE3B,YAAU,MAAM;AACd,YAAQ,UAAU;AAClB,WAAO,MAAM;AACX,cAAQ,UAAU;AAClB,UAAI,MAAM,QAAS,cAAa,MAAM,OAAO;AAAA,IAC/C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,QAAQ,YAAY,MAAM;AAC9B,QAAI,MAAM,QAAS,cAAa,MAAM,OAAO;AAC7C,UAAM,UAAU;AAChB,aAAS,MAAM;AAAA,EACjB,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO;AAAA,IACX,OAAO,SAAiB;AACtB,UAAI,MAAM,QAAS,cAAa,MAAM,OAAO;AAC7C,YAAM,KAAK,MAAM,gBAAgB,IAAI;AACrC,UAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,eAAS,KAAK,WAAW,QAAQ;AACjC,UAAI,aAAa,GAAG;AAClB,cAAM,UAAU,WAAW,MAAM;AAC/B,gBAAM,UAAU;AAChB,mBAAS,MAAM;AAAA,QACjB,GAAG,UAAU;AAAA,MACf;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,SAAO,EAAE,OAAO,MAAM,MAAM;AAC9B;","names":[]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A value that follows `value`, but only once it has stopped changing for `ms`.
|
|
3
|
+
*
|
|
4
|
+
* kastlan asked for the pair in this module because each of its search boxes carried
|
|
5
|
+
* its own copy of the same six lines — a `useEffect` with a `setTimeout` — and two of
|
|
6
|
+
* them forgot the cleanup, so a stale query landed AFTER the fresh one and replaced
|
|
7
|
+
* its results. The cleanup is the whole point of having one implementation.
|
|
8
|
+
*
|
|
9
|
+
* The first render returns `value` itself, not `undefined`: a list filtered by the
|
|
10
|
+
* debounced query must render its initial state immediately, not after `ms`.
|
|
11
|
+
*/
|
|
12
|
+
declare function useDebounce<T>(value: T, ms: number): T;
|
|
13
|
+
interface DebouncedCallbackOptions {
|
|
14
|
+
/**
|
|
15
|
+
* The longest a call may be held back, however often it is re-triggered. Without
|
|
16
|
+
* it a user who never stops typing never saves; with it, a draft autosave still
|
|
17
|
+
* lands every `maxWait` ms while the typing goes on.
|
|
18
|
+
*/
|
|
19
|
+
maxWait?: number;
|
|
20
|
+
}
|
|
21
|
+
/** The debounced function, plus the two escapes a caller needs around it. */
|
|
22
|
+
type DebouncedFunction<A extends unknown[]> = ((...args: A) => void) & {
|
|
23
|
+
/** Drop the pending call, if there is one. */
|
|
24
|
+
cancel: () => void;
|
|
25
|
+
/** Run the pending call now, if there is one — e.g. on blur or before navigating
|
|
26
|
+
* away, so the last keystrokes of a form are not lost. */
|
|
27
|
+
flush: () => void;
|
|
28
|
+
/** Whether a call is waiting. */
|
|
29
|
+
pending: () => boolean;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* `fn`, called only once calls have stopped arriving for `ms` — with the arguments
|
|
33
|
+
* of the LAST call.
|
|
34
|
+
*
|
|
35
|
+
* The returned function keeps its identity across renders (so it can sit in an
|
|
36
|
+
* effect's dependency list or be handed to a memoised child) and always calls the
|
|
37
|
+
* LATEST `fn`, so a handler that closes over current state never runs a stale copy.
|
|
38
|
+
* A pending call is cancelled on unmount: a debounced save firing into an unmounted
|
|
39
|
+
* form is the bug kastlan reported, not a feature.
|
|
40
|
+
*/
|
|
41
|
+
declare function useDebouncedCallback<A extends unknown[]>(fn: (...args: A) => void, ms: number, { maxWait }?: DebouncedCallbackOptions): DebouncedFunction<A>;
|
|
42
|
+
|
|
43
|
+
export { type DebouncedCallbackOptions, type DebouncedFunction, useDebounce, useDebouncedCallback };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
function useDebounce(value, ms) {
|
|
4
|
+
const [debounced, setDebounced] = useState(value);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
const timer = setTimeout(() => setDebounced(value), ms);
|
|
7
|
+
return () => clearTimeout(timer);
|
|
8
|
+
}, [value, ms]);
|
|
9
|
+
return debounced;
|
|
10
|
+
}
|
|
11
|
+
function useDebouncedCallback(fn, ms, { maxWait } = {}) {
|
|
12
|
+
const fnRef = useRef(fn);
|
|
13
|
+
useLayoutEffect(() => {
|
|
14
|
+
fnRef.current = fn;
|
|
15
|
+
});
|
|
16
|
+
const timer = useRef(null);
|
|
17
|
+
const maxTimer = useRef(null);
|
|
18
|
+
const lastArgs = useRef(null);
|
|
19
|
+
const clear = useCallback(() => {
|
|
20
|
+
if (timer.current) clearTimeout(timer.current);
|
|
21
|
+
if (maxTimer.current) clearTimeout(maxTimer.current);
|
|
22
|
+
timer.current = null;
|
|
23
|
+
maxTimer.current = null;
|
|
24
|
+
}, []);
|
|
25
|
+
const invoke = useCallback(() => {
|
|
26
|
+
const args = lastArgs.current;
|
|
27
|
+
clear();
|
|
28
|
+
lastArgs.current = null;
|
|
29
|
+
if (args) fnRef.current(...args);
|
|
30
|
+
}, [clear]);
|
|
31
|
+
useEffect(() => clear, [clear]);
|
|
32
|
+
return useMemo(() => {
|
|
33
|
+
const debounced = ((...args) => {
|
|
34
|
+
lastArgs.current = args;
|
|
35
|
+
if (timer.current) clearTimeout(timer.current);
|
|
36
|
+
timer.current = setTimeout(invoke, ms);
|
|
37
|
+
if (maxWait !== void 0 && !maxTimer.current) {
|
|
38
|
+
maxTimer.current = setTimeout(invoke, maxWait);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
debounced.cancel = () => {
|
|
42
|
+
clear();
|
|
43
|
+
lastArgs.current = null;
|
|
44
|
+
};
|
|
45
|
+
debounced.flush = () => {
|
|
46
|
+
if (lastArgs.current) invoke();
|
|
47
|
+
};
|
|
48
|
+
debounced.pending = () => lastArgs.current !== null;
|
|
49
|
+
return debounced;
|
|
50
|
+
}, [ms, maxWait, invoke, clear]);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
useDebounce,
|
|
54
|
+
useDebouncedCallback
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=use-debounce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-debounce.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\n\n/**\n * A value that follows `value`, but only once it has stopped changing for `ms`.\n *\n * kastlan asked for the pair in this module because each of its search boxes carried\n * its own copy of the same six lines — a `useEffect` with a `setTimeout` — and two of\n * them forgot the cleanup, so a stale query landed AFTER the fresh one and replaced\n * its results. The cleanup is the whole point of having one implementation.\n *\n * The first render returns `value` itself, not `undefined`: a list filtered by the\n * debounced query must render its initial state immediately, not after `ms`.\n */\nexport function useDebounce<T>(value: T, ms: number): T {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const timer = setTimeout(() => setDebounced(value), ms);\n return () => clearTimeout(timer);\n }, [value, ms]);\n return debounced;\n}\n\nexport interface DebouncedCallbackOptions {\n /**\n * The longest a call may be held back, however often it is re-triggered. Without\n * it a user who never stops typing never saves; with it, a draft autosave still\n * lands every `maxWait` ms while the typing goes on.\n */\n maxWait?: number;\n}\n\n/** The debounced function, plus the two escapes a caller needs around it. */\nexport type DebouncedFunction<A extends unknown[]> = ((...args: A) => void) & {\n /** Drop the pending call, if there is one. */\n cancel: () => void;\n /** Run the pending call now, if there is one — e.g. on blur or before navigating\n * away, so the last keystrokes of a form are not lost. */\n flush: () => void;\n /** Whether a call is waiting. */\n pending: () => boolean;\n};\n\n/**\n * `fn`, called only once calls have stopped arriving for `ms` — with the arguments\n * of the LAST call.\n *\n * The returned function keeps its identity across renders (so it can sit in an\n * effect's dependency list or be handed to a memoised child) and always calls the\n * LATEST `fn`, so a handler that closes over current state never runs a stale copy.\n * A pending call is cancelled on unmount: a debounced save firing into an unmounted\n * form is the bug kastlan reported, not a feature.\n */\nexport function useDebouncedCallback<A extends unknown[]>(\n fn: (...args: A) => void,\n ms: number,\n { maxWait }: DebouncedCallbackOptions = {},\n): DebouncedFunction<A> {\n const fnRef = useRef(fn);\n // Layout effect, not render-time assignment: a ref written during render is a\n // side effect React may replay or discard. Nothing can call the debounced function\n // between this commit and the layout effect, so it is never one render behind.\n useLayoutEffect(() => {\n fnRef.current = fn;\n });\n\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const maxTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lastArgs = useRef<A | null>(null);\n\n const clear = useCallback(() => {\n if (timer.current) clearTimeout(timer.current);\n if (maxTimer.current) clearTimeout(maxTimer.current);\n timer.current = null;\n maxTimer.current = null;\n }, []);\n\n const invoke = useCallback(() => {\n const args = lastArgs.current;\n clear();\n lastArgs.current = null;\n if (args) fnRef.current(...args);\n }, [clear]);\n\n useEffect(() => clear, [clear]);\n\n return useMemo(() => {\n const debounced = ((...args: A) => {\n lastArgs.current = args;\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(invoke, ms);\n if (maxWait !== undefined && !maxTimer.current) {\n maxTimer.current = setTimeout(invoke, maxWait);\n }\n }) as DebouncedFunction<A>;\n debounced.cancel = () => {\n clear();\n lastArgs.current = null;\n };\n debounced.flush = () => {\n if (lastArgs.current) invoke();\n };\n debounced.pending = () => lastArgs.current !== null;\n return debounced;\n }, [ms, maxWait, invoke, clear]);\n}\n"],"mappings":";AAAA,SAAS,aAAa,WAAW,iBAAiB,SAAS,QAAQ,gBAAgB;AAa5E,SAAS,YAAe,OAAU,IAAe;AACtD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,YAAU,MAAM;AACd,UAAM,QAAQ,WAAW,MAAM,aAAa,KAAK,GAAG,EAAE;AACtD,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,OAAO,EAAE,CAAC;AACd,SAAO;AACT;AAgCO,SAAS,qBACd,IACA,IACA,EAAE,QAAQ,IAA8B,CAAC,GACnB;AACtB,QAAM,QAAQ,OAAO,EAAE;AAIvB,kBAAgB,MAAM;AACpB,UAAM,UAAU;AAAA,EAClB,CAAC;AAED,QAAM,QAAQ,OAA6C,IAAI;AAC/D,QAAM,WAAW,OAA6C,IAAI;AAClE,QAAM,WAAW,OAAiB,IAAI;AAEtC,QAAM,QAAQ,YAAY,MAAM;AAC9B,QAAI,MAAM,QAAS,cAAa,MAAM,OAAO;AAC7C,QAAI,SAAS,QAAS,cAAa,SAAS,OAAO;AACnD,UAAM,UAAU;AAChB,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS,YAAY,MAAM;AAC/B,UAAM,OAAO,SAAS;AACtB,UAAM;AACN,aAAS,UAAU;AACnB,QAAI,KAAM,OAAM,QAAQ,GAAG,IAAI;AAAA,EACjC,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM,OAAO,CAAC,KAAK,CAAC;AAE9B,SAAO,QAAQ,MAAM;AACnB,UAAM,aAAa,IAAI,SAAY;AACjC,eAAS,UAAU;AACnB,UAAI,MAAM,QAAS,cAAa,MAAM,OAAO;AAC7C,YAAM,UAAU,WAAW,QAAQ,EAAE;AACrC,UAAI,YAAY,UAAa,CAAC,SAAS,SAAS;AAC9C,iBAAS,UAAU,WAAW,QAAQ,OAAO;AAAA,MAC/C;AAAA,IACF;AACA,cAAU,SAAS,MAAM;AACvB,YAAM;AACN,eAAS,UAAU;AAAA,IACrB;AACA,cAAU,QAAQ,MAAM;AACtB,UAAI,SAAS,QAAS,QAAO;AAAA,IAC/B;AACA,cAAU,UAAU,MAAM,SAAS,YAAY;AAC/C,WAAO;AAAA,EACT,GAAG,CAAC,IAAI,SAAS,QAAQ,KAAK,CAAC;AACjC;","names":[]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DragEvent, ReactElement } from 'react';
|
|
2
|
+
import { UseFilePickerOptions } from '../components/file-button.js';
|
|
3
|
+
import '../components/ui.js';
|
|
4
|
+
import '../components/tooltip.js';
|
|
5
|
+
import './use-anchored-rect.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Turn ANY element into a file drop target — kastlan's ask, for the document list of
|
|
9
|
+
* a booking and the rows of its gantt, which are drop targets without being a
|
|
10
|
+
* `FileDropzone` (a dashed box with a Browse button inside would be the wrong thing
|
|
11
|
+
* to draw over a list).
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { dropProps, isOver, element } = useFileDrop({ accept: ".pdf", multiple: true,
|
|
15
|
+
* maxSize: 10_000_000, onFiles: attach, onReject: ([r]) => setError(r.message) });
|
|
16
|
+
* return <>{element}<ul {...dropProps} data-drop-over={isOver || undefined}>…</ul></>;
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* The screening is `useFilePicker`'s own — `accept` re-checked (a drop ignores the
|
|
20
|
+
* dialog's filter), `maxSize`, `maxFiles`, `isValid`, `onPick` — so a file refused by
|
|
21
|
+
* `FileButton` is refused here in the same words. It comes with `open()` as well, so
|
|
22
|
+
* the same options can also back a "choose a file" menu item beside the drop target.
|
|
23
|
+
*/
|
|
24
|
+
/** `useFilePicker`'s options, minus `capture` (a camera does not take drops). */
|
|
25
|
+
type UseFileDropOptions = Omit<UseFilePickerOptions, "capture">;
|
|
26
|
+
/** Spread onto the drop target. Four handlers, nothing else: the element keeps its
|
|
27
|
+
* own role, name and focus behaviour. */
|
|
28
|
+
interface FileDropProps<E extends Element = Element> {
|
|
29
|
+
onDragEnter: (e: DragEvent<E>) => void;
|
|
30
|
+
onDragOver: (e: DragEvent<E>) => void;
|
|
31
|
+
onDragLeave: (e: DragEvent<E>) => void;
|
|
32
|
+
onDrop: (e: DragEvent<E>) => void;
|
|
33
|
+
}
|
|
34
|
+
interface UseFileDropReturn<E extends Element = Element> {
|
|
35
|
+
dropProps: FileDropProps<E>;
|
|
36
|
+
/** A FILE drag is over the target (and it is not `disabled`). Style from this. */
|
|
37
|
+
isOver: boolean;
|
|
38
|
+
/** Open the system picker with the same options — from a click handler only. */
|
|
39
|
+
open: () => void;
|
|
40
|
+
/** Screen and deliver files that arrived another way (a paste). */
|
|
41
|
+
take: (files: ArrayLike<File> | null | undefined) => void;
|
|
42
|
+
/** The live region that speaks a refusal (and the picker's hidden input). Render it
|
|
43
|
+
* once, anywhere; without it a refusal reaches `onReject` but is not announced. */
|
|
44
|
+
element: ReactElement;
|
|
45
|
+
}
|
|
46
|
+
/** Whether a drag carries files — a dragged link, text or a row of the page does not,
|
|
47
|
+
* and must not light the target up or be swallowed by it. */
|
|
48
|
+
declare function dragHasFiles(e: DragEvent): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* @internal The drag half on its own, shared with `FileDropzone`.
|
|
51
|
+
*
|
|
52
|
+
* `dragenter`/`dragleave` fire for every CHILD the pointer crosses: moving from the
|
|
53
|
+
* target onto a label inside it is a leave of the target followed by an enter of the
|
|
54
|
+
* label, which bubbles. A boolean flipped by each one flickers off and on across
|
|
55
|
+
* every child, and `relatedTarget` — the usual fix — is `null` in Safari's drag
|
|
56
|
+
* events. So this counts: +1 per enter, -1 per leave, over while above zero, and a
|
|
57
|
+
* drop resets it (the drop replaces the leave that would have balanced the enter).
|
|
58
|
+
*
|
|
59
|
+
* A file drag stops propagating here, so a target nested in another (a row inside a
|
|
60
|
+
* page-wide drop area) takes its own drop, and the outer one's count falls back to
|
|
61
|
+
* zero while the pointer is over the inner one — only one of them lights up.
|
|
62
|
+
*/
|
|
63
|
+
declare function useDragTarget<E extends Element = Element>({ disabled, onDropFiles, }: {
|
|
64
|
+
disabled?: boolean;
|
|
65
|
+
onDropFiles: (files: FileList | File[]) => void;
|
|
66
|
+
}): {
|
|
67
|
+
dropProps: FileDropProps<E>;
|
|
68
|
+
isOver: boolean;
|
|
69
|
+
};
|
|
70
|
+
declare function useFileDrop<E extends Element = Element>(options: UseFileDropOptions): UseFileDropReturn<E>;
|
|
71
|
+
|
|
72
|
+
export { type FileDropProps, type UseFileDropOptions, type UseFileDropReturn, dragHasFiles, useDragTarget, useFileDrop };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import { useFilePicker } from "../components/file-button.js";
|
|
4
|
+
function dragHasFiles(e) {
|
|
5
|
+
return Array.from(e.dataTransfer?.types ?? []).includes("Files");
|
|
6
|
+
}
|
|
7
|
+
function useDragTarget({
|
|
8
|
+
disabled,
|
|
9
|
+
onDropFiles
|
|
10
|
+
}) {
|
|
11
|
+
const depth = useRef(0);
|
|
12
|
+
const [over, setOver] = useState(false);
|
|
13
|
+
const dropProps = {
|
|
14
|
+
onDragEnter: (e) => {
|
|
15
|
+
if (!dragHasFiles(e)) return;
|
|
16
|
+
e.stopPropagation();
|
|
17
|
+
e.preventDefault();
|
|
18
|
+
depth.current += 1;
|
|
19
|
+
if (!disabled) setOver(true);
|
|
20
|
+
},
|
|
21
|
+
onDragOver: (e) => {
|
|
22
|
+
if (!dragHasFiles(e)) return;
|
|
23
|
+
e.stopPropagation();
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
e.dataTransfer.dropEffect = disabled ? "none" : "copy";
|
|
26
|
+
},
|
|
27
|
+
onDragLeave: (e) => {
|
|
28
|
+
if (!dragHasFiles(e)) return;
|
|
29
|
+
e.stopPropagation();
|
|
30
|
+
depth.current = Math.max(0, depth.current - 1);
|
|
31
|
+
if (depth.current === 0) setOver(false);
|
|
32
|
+
},
|
|
33
|
+
onDrop: (e) => {
|
|
34
|
+
if (!dragHasFiles(e)) return;
|
|
35
|
+
e.stopPropagation();
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
depth.current = 0;
|
|
38
|
+
setOver(false);
|
|
39
|
+
if (!disabled) onDropFiles(e.dataTransfer.files);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return { dropProps, isOver: over && !disabled };
|
|
43
|
+
}
|
|
44
|
+
function useFileDrop(options) {
|
|
45
|
+
const picker = useFilePicker(options);
|
|
46
|
+
const { dropProps, isOver } = useDragTarget({
|
|
47
|
+
disabled: options.disabled,
|
|
48
|
+
onDropFiles: picker.take
|
|
49
|
+
});
|
|
50
|
+
return { dropProps, isOver, open: picker.open, take: picker.take, element: picker.element };
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
dragHasFiles,
|
|
54
|
+
useDragTarget,
|
|
55
|
+
useFileDrop
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=use-file-drop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/use-file-drop.ts"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport type { DragEvent, ReactElement } from \"react\";\nimport { useFilePicker } from \"../components/file-button\";\nimport type { UseFilePickerOptions } from \"../components/file-button\";\n\n/**\n * Turn ANY element into a file drop target — kastlan's ask, for the document list of\n * a booking and the rows of its gantt, which are drop targets without being a\n * `FileDropzone` (a dashed box with a Browse button inside would be the wrong thing\n * to draw over a list).\n *\n * ```tsx\n * const { dropProps, isOver, element } = useFileDrop({ accept: \".pdf\", multiple: true,\n * maxSize: 10_000_000, onFiles: attach, onReject: ([r]) => setError(r.message) });\n * return <>{element}<ul {...dropProps} data-drop-over={isOver || undefined}>…</ul></>;\n * ```\n *\n * The screening is `useFilePicker`'s own — `accept` re-checked (a drop ignores the\n * dialog's filter), `maxSize`, `maxFiles`, `isValid`, `onPick` — so a file refused by\n * `FileButton` is refused here in the same words. It comes with `open()` as well, so\n * the same options can also back a \"choose a file\" menu item beside the drop target.\n */\n\n/** `useFilePicker`'s options, minus `capture` (a camera does not take drops). */\nexport type UseFileDropOptions = Omit<UseFilePickerOptions, \"capture\">;\n\n/** Spread onto the drop target. Four handlers, nothing else: the element keeps its\n * own role, name and focus behaviour. */\nexport interface FileDropProps<E extends Element = Element> {\n onDragEnter: (e: DragEvent<E>) => void;\n onDragOver: (e: DragEvent<E>) => void;\n onDragLeave: (e: DragEvent<E>) => void;\n onDrop: (e: DragEvent<E>) => void;\n}\n\nexport interface UseFileDropReturn<E extends Element = Element> {\n dropProps: FileDropProps<E>;\n /** A FILE drag is over the target (and it is not `disabled`). Style from this. */\n isOver: boolean;\n /** Open the system picker with the same options — from a click handler only. */\n open: () => void;\n /** Screen and deliver files that arrived another way (a paste). */\n take: (files: ArrayLike<File> | null | undefined) => void;\n /** The live region that speaks a refusal (and the picker's hidden input). Render it\n * once, anywhere; without it a refusal reaches `onReject` but is not announced. */\n element: ReactElement;\n}\n\n/** Whether a drag carries files — a dragged link, text or a row of the page does not,\n * and must not light the target up or be swallowed by it. */\nexport function dragHasFiles(e: DragEvent): boolean {\n return Array.from(e.dataTransfer?.types ?? []).includes(\"Files\");\n}\n\n/**\n * @internal The drag half on its own, shared with `FileDropzone`.\n *\n * `dragenter`/`dragleave` fire for every CHILD the pointer crosses: moving from the\n * target onto a label inside it is a leave of the target followed by an enter of the\n * label, which bubbles. A boolean flipped by each one flickers off and on across\n * every child, and `relatedTarget` — the usual fix — is `null` in Safari's drag\n * events. So this counts: +1 per enter, -1 per leave, over while above zero, and a\n * drop resets it (the drop replaces the leave that would have balanced the enter).\n *\n * A file drag stops propagating here, so a target nested in another (a row inside a\n * page-wide drop area) takes its own drop, and the outer one's count falls back to\n * zero while the pointer is over the inner one — only one of them lights up.\n */\nexport function useDragTarget<E extends Element = Element>({\n disabled,\n onDropFiles,\n}: {\n disabled?: boolean;\n onDropFiles: (files: FileList | File[]) => void;\n}): { dropProps: FileDropProps<E>; isOver: boolean } {\n const depth = useRef(0);\n const [over, setOver] = useState(false);\n\n const dropProps: FileDropProps<E> = {\n onDragEnter: (e) => {\n if (!dragHasFiles(e)) return;\n e.stopPropagation();\n e.preventDefault();\n depth.current += 1;\n if (!disabled) setOver(true);\n },\n onDragOver: (e) => {\n if (!dragHasFiles(e)) return;\n e.stopPropagation();\n // Always cancelled for a file drag, disabled or not: an uncancelled drop makes\n // the browser NAVIGATE to the file, which loses the page.\n e.preventDefault();\n e.dataTransfer.dropEffect = disabled ? \"none\" : \"copy\";\n },\n onDragLeave: (e) => {\n if (!dragHasFiles(e)) return;\n e.stopPropagation();\n depth.current = Math.max(0, depth.current - 1);\n if (depth.current === 0) setOver(false);\n },\n onDrop: (e) => {\n if (!dragHasFiles(e)) return;\n e.stopPropagation();\n e.preventDefault();\n depth.current = 0;\n setOver(false);\n if (!disabled) onDropFiles(e.dataTransfer.files);\n },\n };\n\n return { dropProps, isOver: over && !disabled };\n}\n\nexport function useFileDrop<E extends Element = Element>(\n options: UseFileDropOptions,\n): UseFileDropReturn<E> {\n const picker = useFilePicker(options);\n const { dropProps, isOver } = useDragTarget<E>({\n disabled: options.disabled,\n onDropFiles: picker.take,\n });\n return { dropProps, isOver, open: picker.open, take: picker.take, element: picker.element };\n}\n"],"mappings":";AAAA,SAAS,QAAQ,gBAAgB;AAEjC,SAAS,qBAAqB;AAgDvB,SAAS,aAAa,GAAuB;AAClD,SAAO,MAAM,KAAK,EAAE,cAAc,SAAS,CAAC,CAAC,EAAE,SAAS,OAAO;AACjE;AAgBO,SAAS,cAA2C;AAAA,EACzD;AAAA,EACA;AACF,GAGqD;AACnD,QAAM,QAAQ,OAAO,CAAC;AACtB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AAEtC,QAAM,YAA8B;AAAA,IAClC,aAAa,CAAC,MAAM;AAClB,UAAI,CAAC,aAAa,CAAC,EAAG;AACtB,QAAE,gBAAgB;AAClB,QAAE,eAAe;AACjB,YAAM,WAAW;AACjB,UAAI,CAAC,SAAU,SAAQ,IAAI;AAAA,IAC7B;AAAA,IACA,YAAY,CAAC,MAAM;AACjB,UAAI,CAAC,aAAa,CAAC,EAAG;AACtB,QAAE,gBAAgB;AAGlB,QAAE,eAAe;AACjB,QAAE,aAAa,aAAa,WAAW,SAAS;AAAA,IAClD;AAAA,IACA,aAAa,CAAC,MAAM;AAClB,UAAI,CAAC,aAAa,CAAC,EAAG;AACtB,QAAE,gBAAgB;AAClB,YAAM,UAAU,KAAK,IAAI,GAAG,MAAM,UAAU,CAAC;AAC7C,UAAI,MAAM,YAAY,EAAG,SAAQ,KAAK;AAAA,IACxC;AAAA,IACA,QAAQ,CAAC,MAAM;AACb,UAAI,CAAC,aAAa,CAAC,EAAG;AACtB,QAAE,gBAAgB;AAClB,QAAE,eAAe;AACjB,YAAM,UAAU;AAChB,cAAQ,KAAK;AACb,UAAI,CAAC,SAAU,aAAY,EAAE,aAAa,KAAK;AAAA,IACjD;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,QAAQ,QAAQ,CAAC,SAAS;AAChD;AAEO,SAAS,YACd,SACsB;AACtB,QAAM,SAAS,cAAc,OAAO;AACpC,QAAM,EAAE,WAAW,OAAO,IAAI,cAAiB;AAAA,IAC7C,UAAU,QAAQ;AAAA,IAClB,aAAa,OAAO;AAAA,EACtB,CAAC;AACD,SAAO,EAAE,WAAW,QAAQ,MAAM,OAAO,MAAM,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ;AAC5F;","names":[]}
|
package/dist/i18n/defaults.d.ts
CHANGED
|
@@ -29,6 +29,9 @@ import '../components/file-button.js';
|
|
|
29
29
|
import '../components/measured-grid.js';
|
|
30
30
|
import '../feedback/feedback-attachment.js';
|
|
31
31
|
import '../feedback/feedback-dialog.js';
|
|
32
|
+
import '../components/confirm-dialog.js';
|
|
33
|
+
import '../components/floating-panel.js';
|
|
34
|
+
import '../components/copy-button.js';
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
37
|
* The whole English tree in one object: what a translation is written against, and
|
package/dist/i18n/defaults.js
CHANGED
|
@@ -21,7 +21,10 @@ import { DEFAULT_ICON_PICKER_LABELS } from "../components/icon-picker.js";
|
|
|
21
21
|
import { DEFAULT_DIALOG_FRAME_LABELS } from "../components/dialog-frame.js";
|
|
22
22
|
import { DEFAULT_FILE_PICKER_LABELS } from "../components/file-button.js";
|
|
23
23
|
import { DEFAULT_MEASURED_GRID_LABELS } from "../components/measured-grid.js";
|
|
24
|
+
import { DEFAULT_CONFIRM_DIALOG_LABELS } from "../components/confirm-dialog.js";
|
|
25
|
+
import { DEFAULT_FLOATING_PANEL_LABELS } from "../components/floating-panel.js";
|
|
24
26
|
import { DEFAULT_FEEDBACK_ATTACHMENT_LABELS } from "../feedback/feedback-attachment.js";
|
|
27
|
+
import { DEFAULT_COPY_BUTTON_LABELS } from "../components/copy-button.js";
|
|
25
28
|
import {
|
|
26
29
|
DEFAULT_APP_SHELL_LABELS,
|
|
27
30
|
DEFAULT_CALCULATOR_LABELS,
|
|
@@ -70,7 +73,10 @@ const DEFAULT_UI_KIT_LABELS = {
|
|
|
70
73
|
dialogFrame: DEFAULT_DIALOG_FRAME_LABELS,
|
|
71
74
|
filePicker: DEFAULT_FILE_PICKER_LABELS,
|
|
72
75
|
measuredGrid: DEFAULT_MEASURED_GRID_LABELS,
|
|
73
|
-
feedbackAttachment: DEFAULT_FEEDBACK_ATTACHMENT_LABELS
|
|
76
|
+
feedbackAttachment: DEFAULT_FEEDBACK_ATTACHMENT_LABELS,
|
|
77
|
+
confirmDialog: DEFAULT_CONFIRM_DIALOG_LABELS,
|
|
78
|
+
floatingPanel: DEFAULT_FLOATING_PANEL_LABELS,
|
|
79
|
+
copyButton: DEFAULT_COPY_BUTTON_LABELS
|
|
74
80
|
};
|
|
75
81
|
export {
|
|
76
82
|
DEFAULT_UI_KIT_LABELS
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/i18n/defaults.ts"],"sourcesContent":["import { DEFAULT_DATA_TABLE_LABELS } from \"../components/data-table-labels\";\nimport { DEFAULT_MINI_CALENDAR_LABELS } from \"../components/mini-calendar\";\nimport { DEFAULT_MONTH_PICKER_LABELS } from \"../components/month-picker\";\nimport { DEFAULT_PAGE_CONTENTS_LABELS } from \"../components/page-contents\";\nimport { DEFAULT_POPOVER_LABELS } from \"../components/popover\";\nimport { DEFAULT_CHIP_INPUT_LABELS } from \"../components/chip\";\nimport { DEFAULT_FIELD_SYNC_LABELS } from \"../components/field-sync\";\nimport { DEFAULT_PASSWORD_REVEAL_LABELS, DEFAULT_TABS_LABELS } from \"../components/ui\";\nimport { DEFAULT_WIZARD_LABELS } from \"../wizard/types\";\nimport { DEFAULT_TOUR_LABELS } from \"../tour/tour\";\nimport { DEFAULT_COMMAND_PALETTE_LABELS } from \"../search/command-palette\";\nimport { DEFAULT_SERIES_CHART_LABELS } from \"../components/series-chart-labels\";\nimport { DEFAULT_SPARKLINE_LABELS } from \"../components/sparkline\";\nimport { DEFAULT_STAT_TILE_LABELS } from \"../components/stat-tile\";\nimport { DEFAULT_SIGNATURE_PAD_LABELS } from \"../components/signature-pad\";\nimport { DEFAULT_PASSWORD_STRENGTH_LABELS } from \"../components/password-strength\";\nimport { DEFAULT_DANGER_CONFIRM_LABELS } from \"../components/danger-confirm\";\nimport { DEFAULT_SWATCH_PICKER_LABELS } from \"../components/swatch-picker\";\nimport { DEFAULT_ICON_PICKER_LABELS } from \"../components/icon-picker\";\nimport { DEFAULT_DIALOG_FRAME_LABELS } from \"../components/dialog-frame\";\nimport { DEFAULT_FILE_PICKER_LABELS } from \"../components/file-button\";\nimport { DEFAULT_MEASURED_GRID_LABELS } from \"../components/measured-grid\";\nimport { DEFAULT_FEEDBACK_ATTACHMENT_LABELS } from \"../feedback/feedback-attachment\";\nimport {\n DEFAULT_APP_SHELL_LABELS,\n DEFAULT_CALCULATOR_LABELS,\n DEFAULT_COMBOBOX_LABELS,\n DEFAULT_COMMON_LABELS,\n DEFAULT_CURRENCY_LABELS,\n DEFAULT_DATE_PICKER_LABELS,\n DEFAULT_FILE_LABELS,\n DEFAULT_MULTI_SELECT_LABELS,\n DEFAULT_PICKER_SHEET_LABELS,\n DEFAULT_SWIPEABLE_ROW_LABELS,\n DEFAULT_TOP_BAR_LABELS,\n} from \"./kit-labels\";\nimport type { UiKitLabels } from \"./kit-labels\";\n\n/**\n * The whole English tree in one object: what a translation is written against, and\n * the `reference` for {@link missingKitLabels}.\n *\n * A separate module from the provider on purpose. Components import the provider's\n * hooks; this file imports the components' defaults. Kept together they would be an\n * import cycle through every component in the kit.\n */\nexport const DEFAULT_UI_KIT_LABELS: UiKitLabels = {\n common: DEFAULT_COMMON_LABELS,\n dataTable: DEFAULT_DATA_TABLE_LABELS,\n miniCalendar: DEFAULT_MINI_CALENDAR_LABELS,\n datePicker: DEFAULT_DATE_PICKER_LABELS,\n monthPicker: DEFAULT_MONTH_PICKER_LABELS,\n popover: DEFAULT_POPOVER_LABELS,\n combobox: DEFAULT_COMBOBOX_LABELS,\n multiSelect: DEFAULT_MULTI_SELECT_LABELS,\n calculator: DEFAULT_CALCULATOR_LABELS,\n currency: DEFAULT_CURRENCY_LABELS,\n chipInput: DEFAULT_CHIP_INPUT_LABELS,\n fieldSync: DEFAULT_FIELD_SYNC_LABELS,\n passwordReveal: DEFAULT_PASSWORD_REVEAL_LABELS,\n tabs: DEFAULT_TABS_LABELS,\n appShell: DEFAULT_APP_SHELL_LABELS,\n pageContents: DEFAULT_PAGE_CONTENTS_LABELS,\n topBar: DEFAULT_TOP_BAR_LABELS,\n pickerSheet: DEFAULT_PICKER_SHEET_LABELS,\n swipeableRow: DEFAULT_SWIPEABLE_ROW_LABELS,\n file: DEFAULT_FILE_LABELS,\n wizard: DEFAULT_WIZARD_LABELS,\n tour: DEFAULT_TOUR_LABELS,\n commandPalette: DEFAULT_COMMAND_PALETTE_LABELS,\n seriesChart: DEFAULT_SERIES_CHART_LABELS,\n sparkline: DEFAULT_SPARKLINE_LABELS,\n statTile: DEFAULT_STAT_TILE_LABELS,\n signaturePad: DEFAULT_SIGNATURE_PAD_LABELS,\n passwordStrength: DEFAULT_PASSWORD_STRENGTH_LABELS,\n dangerConfirm: DEFAULT_DANGER_CONFIRM_LABELS,\n swatchPicker: DEFAULT_SWATCH_PICKER_LABELS,\n iconPicker: DEFAULT_ICON_PICKER_LABELS,\n dialogFrame: DEFAULT_DIALOG_FRAME_LABELS,\n filePicker: DEFAULT_FILE_PICKER_LABELS,\n measuredGrid: DEFAULT_MEASURED_GRID_LABELS,\n feedbackAttachment: DEFAULT_FEEDBACK_ATTACHMENT_LABELS,\n};\n"],"mappings":";AAAA,SAAS,iCAAiC;AAC1C,SAAS,oCAAoC;AAC7C,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,8BAA8B;AACvC,SAAS,iCAAiC;AAC1C,SAAS,iCAAiC;AAC1C,SAAS,gCAAgC,2BAA2B;AACpE,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,sCAAsC;AAC/C,SAAS,mCAAmC;AAC5C,SAAS,gCAAgC;AACzC,SAAS,gCAAgC;AACzC,SAAS,oCAAoC;AAC7C,SAAS,wCAAwC;AACjD,SAAS,qCAAqC;AAC9C,SAAS,oCAAoC;AAC7C,SAAS,kCAAkC;AAC3C,SAAS,mCAAmC;AAC5C,SAAS,kCAAkC;AAC3C,SAAS,oCAAoC;AAC7C,SAAS,0CAA0C;AACnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWA,MAAM,wBAAqC;AAAA,EAChD,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,SAAS;AAAA,EACT,UAAU;AAAA,EACV,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,cAAc;AAAA,EACd,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,WAAW;AAAA,EACX,UAAU;AAAA,EACV,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,oBAAoB;
|
|
1
|
+
{"version":3,"sources":["../../src/i18n/defaults.ts"],"sourcesContent":["import { DEFAULT_DATA_TABLE_LABELS } from \"../components/data-table-labels\";\nimport { DEFAULT_MINI_CALENDAR_LABELS } from \"../components/mini-calendar\";\nimport { DEFAULT_MONTH_PICKER_LABELS } from \"../components/month-picker\";\nimport { DEFAULT_PAGE_CONTENTS_LABELS } from \"../components/page-contents\";\nimport { DEFAULT_POPOVER_LABELS } from \"../components/popover\";\nimport { DEFAULT_CHIP_INPUT_LABELS } from \"../components/chip\";\nimport { DEFAULT_FIELD_SYNC_LABELS } from \"../components/field-sync\";\nimport { DEFAULT_PASSWORD_REVEAL_LABELS, DEFAULT_TABS_LABELS } from \"../components/ui\";\nimport { DEFAULT_WIZARD_LABELS } from \"../wizard/types\";\nimport { DEFAULT_TOUR_LABELS } from \"../tour/tour\";\nimport { DEFAULT_COMMAND_PALETTE_LABELS } from \"../search/command-palette\";\nimport { DEFAULT_SERIES_CHART_LABELS } from \"../components/series-chart-labels\";\nimport { DEFAULT_SPARKLINE_LABELS } from \"../components/sparkline\";\nimport { DEFAULT_STAT_TILE_LABELS } from \"../components/stat-tile\";\nimport { DEFAULT_SIGNATURE_PAD_LABELS } from \"../components/signature-pad\";\nimport { DEFAULT_PASSWORD_STRENGTH_LABELS } from \"../components/password-strength\";\nimport { DEFAULT_DANGER_CONFIRM_LABELS } from \"../components/danger-confirm\";\nimport { DEFAULT_SWATCH_PICKER_LABELS } from \"../components/swatch-picker\";\nimport { DEFAULT_ICON_PICKER_LABELS } from \"../components/icon-picker\";\nimport { DEFAULT_DIALOG_FRAME_LABELS } from \"../components/dialog-frame\";\nimport { DEFAULT_FILE_PICKER_LABELS } from \"../components/file-button\";\nimport { DEFAULT_MEASURED_GRID_LABELS } from \"../components/measured-grid\";\nimport { DEFAULT_CONFIRM_DIALOG_LABELS } from \"../components/confirm-dialog\";\nimport { DEFAULT_FLOATING_PANEL_LABELS } from \"../components/floating-panel\";\nimport { DEFAULT_FEEDBACK_ATTACHMENT_LABELS } from \"../feedback/feedback-attachment\";\nimport { DEFAULT_COPY_BUTTON_LABELS } from \"../components/copy-button\";\nimport {\n DEFAULT_APP_SHELL_LABELS,\n DEFAULT_CALCULATOR_LABELS,\n DEFAULT_COMBOBOX_LABELS,\n DEFAULT_COMMON_LABELS,\n DEFAULT_CURRENCY_LABELS,\n DEFAULT_DATE_PICKER_LABELS,\n DEFAULT_FILE_LABELS,\n DEFAULT_MULTI_SELECT_LABELS,\n DEFAULT_PICKER_SHEET_LABELS,\n DEFAULT_SWIPEABLE_ROW_LABELS,\n DEFAULT_TOP_BAR_LABELS,\n} from \"./kit-labels\";\nimport type { UiKitLabels } from \"./kit-labels\";\n\n/**\n * The whole English tree in one object: what a translation is written against, and\n * the `reference` for {@link missingKitLabels}.\n *\n * A separate module from the provider on purpose. Components import the provider's\n * hooks; this file imports the components' defaults. Kept together they would be an\n * import cycle through every component in the kit.\n */\nexport const DEFAULT_UI_KIT_LABELS: UiKitLabels = {\n common: DEFAULT_COMMON_LABELS,\n dataTable: DEFAULT_DATA_TABLE_LABELS,\n miniCalendar: DEFAULT_MINI_CALENDAR_LABELS,\n datePicker: DEFAULT_DATE_PICKER_LABELS,\n monthPicker: DEFAULT_MONTH_PICKER_LABELS,\n popover: DEFAULT_POPOVER_LABELS,\n combobox: DEFAULT_COMBOBOX_LABELS,\n multiSelect: DEFAULT_MULTI_SELECT_LABELS,\n calculator: DEFAULT_CALCULATOR_LABELS,\n currency: DEFAULT_CURRENCY_LABELS,\n chipInput: DEFAULT_CHIP_INPUT_LABELS,\n fieldSync: DEFAULT_FIELD_SYNC_LABELS,\n passwordReveal: DEFAULT_PASSWORD_REVEAL_LABELS,\n tabs: DEFAULT_TABS_LABELS,\n appShell: DEFAULT_APP_SHELL_LABELS,\n pageContents: DEFAULT_PAGE_CONTENTS_LABELS,\n topBar: DEFAULT_TOP_BAR_LABELS,\n pickerSheet: DEFAULT_PICKER_SHEET_LABELS,\n swipeableRow: DEFAULT_SWIPEABLE_ROW_LABELS,\n file: DEFAULT_FILE_LABELS,\n wizard: DEFAULT_WIZARD_LABELS,\n tour: DEFAULT_TOUR_LABELS,\n commandPalette: DEFAULT_COMMAND_PALETTE_LABELS,\n seriesChart: DEFAULT_SERIES_CHART_LABELS,\n sparkline: DEFAULT_SPARKLINE_LABELS,\n statTile: DEFAULT_STAT_TILE_LABELS,\n signaturePad: DEFAULT_SIGNATURE_PAD_LABELS,\n passwordStrength: DEFAULT_PASSWORD_STRENGTH_LABELS,\n dangerConfirm: DEFAULT_DANGER_CONFIRM_LABELS,\n swatchPicker: DEFAULT_SWATCH_PICKER_LABELS,\n iconPicker: DEFAULT_ICON_PICKER_LABELS,\n dialogFrame: DEFAULT_DIALOG_FRAME_LABELS,\n filePicker: DEFAULT_FILE_PICKER_LABELS,\n measuredGrid: DEFAULT_MEASURED_GRID_LABELS,\n feedbackAttachment: DEFAULT_FEEDBACK_ATTACHMENT_LABELS,\n confirmDialog: DEFAULT_CONFIRM_DIALOG_LABELS,\n floatingPanel: DEFAULT_FLOATING_PANEL_LABELS,\n copyButton: DEFAULT_COPY_BUTTON_LABELS,\n};\n"],"mappings":";AAAA,SAAS,iCAAiC;AAC1C,SAAS,oCAAoC;AAC7C,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,8BAA8B;AACvC,SAAS,iCAAiC;AAC1C,SAAS,iCAAiC;AAC1C,SAAS,gCAAgC,2BAA2B;AACpE,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AACpC,SAAS,sCAAsC;AAC/C,SAAS,mCAAmC;AAC5C,SAAS,gCAAgC;AACzC,SAAS,gCAAgC;AACzC,SAAS,oCAAoC;AAC7C,SAAS,wCAAwC;AACjD,SAAS,qCAAqC;AAC9C,SAAS,oCAAoC;AAC7C,SAAS,kCAAkC;AAC3C,SAAS,mCAAmC;AAC5C,SAAS,kCAAkC;AAC3C,SAAS,oCAAoC;AAC7C,SAAS,qCAAqC;AAC9C,SAAS,qCAAqC;AAC9C,SAAS,0CAA0C;AACnD,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAWA,MAAM,wBAAqC;AAAA,EAChD,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,SAAS;AAAA,EACT,UAAU;AAAA,EACV,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,UAAU;AAAA,EACV,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,cAAc;AAAA,EACd,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,WAAW;AAAA,EACX,UAAU;AAAA,EACV,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,YAAY;AACd;","names":[]}
|
|
@@ -23,6 +23,9 @@ import { DialogFrameLabels } from '../components/dialog-frame.js';
|
|
|
23
23
|
import { FilePickerLabels } from '../components/file-button.js';
|
|
24
24
|
import { MeasuredGridLabels } from '../components/measured-grid.js';
|
|
25
25
|
import { FeedbackAttachmentFieldLabels } from '../feedback/feedback-attachment.js';
|
|
26
|
+
import { ConfirmDialogLabels } from '../components/confirm-dialog.js';
|
|
27
|
+
import { FloatingPanelLabels } from '../components/floating-panel.js';
|
|
28
|
+
import { CopyButtonLabels } from '../components/copy-button.js';
|
|
26
29
|
import 'lucide-react';
|
|
27
30
|
import '../components/tooltip.js';
|
|
28
31
|
import '../hooks/use-anchored-rect.js';
|
|
@@ -75,6 +78,9 @@ interface CommonLabels {
|
|
|
75
78
|
* A colon-and-space is not universal punctuation (French puts a space before
|
|
76
79
|
* the colon, Chinese uses a full-width one). */
|
|
77
80
|
fieldValue: (field: string, value: string) => string;
|
|
81
|
+
/** The × that puts away a banner or a notice (`AlertBanner onDismiss`). Not `close`:
|
|
82
|
+
* nothing opened, and "Close" on a banner reads as closing the page it sits on. */
|
|
83
|
+
dismiss: string;
|
|
78
84
|
}
|
|
79
85
|
/** `DatePicker` / `DateRangePicker` chrome. The calendar inside has its own
|
|
80
86
|
* namespace, `miniCalendar`. */
|
|
@@ -87,6 +93,12 @@ interface DatePickerLabels {
|
|
|
87
93
|
previousDay: string;
|
|
88
94
|
nextDay: string;
|
|
89
95
|
today: string;
|
|
96
|
+
/** `DateRangePicker commit="apply"`: the button that commits the drafted range. */
|
|
97
|
+
apply: string;
|
|
98
|
+
/** …and the one that discards it. */
|
|
99
|
+
cancel: string;
|
|
100
|
+
/** Accessible name of `DateRangePicker`'s preset column. */
|
|
101
|
+
presets: string;
|
|
90
102
|
}
|
|
91
103
|
/** The whole combobox family: `Combobox`, `EntityCombobox`,
|
|
92
104
|
* `MultiEntityCombobox`, `InlineEntityCombobox`, `Autocomplete`. */
|
|
@@ -204,6 +216,9 @@ interface UiKitLabels {
|
|
|
204
216
|
filePicker: FilePickerLabels;
|
|
205
217
|
measuredGrid: MeasuredGridLabels;
|
|
206
218
|
feedbackAttachment: FeedbackAttachmentFieldLabels;
|
|
219
|
+
confirmDialog: ConfirmDialogLabels;
|
|
220
|
+
floatingPanel: FloatingPanelLabels;
|
|
221
|
+
copyButton: CopyButtonLabels;
|
|
207
222
|
}
|
|
208
223
|
/** Any subset of the tree, one level deep — each namespace may be partial, and a
|
|
209
224
|
* namespace that holds a record (`dataTable.presets`) is merged key by key. */
|