@svgrid/grid 1.2.22 → 1.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GridFooter.svelte +34 -20
- package/dist/GridFooter.svelte.d.ts +8 -0
- package/dist/SvAutoComplete.svelte +89 -0
- package/dist/SvAutoComplete.svelte.d.ts +16 -0
- package/dist/SvButton.svelte +97 -0
- package/dist/SvButton.svelte.d.ts +23 -0
- package/dist/SvCalendar.svelte +409 -0
- package/dist/SvCalendar.svelte.d.ts +52 -0
- package/dist/SvCheckBox.svelte +82 -0
- package/dist/SvCheckBox.svelte.d.ts +19 -0
- package/dist/SvColorInput.svelte +160 -0
- package/dist/SvColorInput.svelte.d.ts +15 -0
- package/dist/SvComboBox.svelte +108 -0
- package/dist/SvComboBox.svelte.d.ts +15 -0
- package/dist/SvCountryInput.svelte +125 -0
- package/dist/SvCountryInput.svelte.d.ts +14 -0
- package/dist/SvDateTimePicker.svelte +265 -0
- package/dist/SvDateTimePicker.svelte.d.ts +38 -0
- package/dist/SvDropDownList.svelte +120 -0
- package/dist/SvDropDownList.svelte.d.ts +15 -0
- package/dist/SvForm.svelte +147 -0
- package/dist/SvForm.svelte.d.ts +29 -0
- package/dist/SvGauge.svelte +97 -0
- package/dist/SvGauge.svelte.d.ts +26 -0
- package/dist/SvGrid.controller.svelte.d.ts +16 -2
- package/dist/SvGrid.controller.svelte.js +63 -8
- package/dist/SvGrid.css +84 -31
- package/dist/SvGrid.helpers.d.ts +4 -0
- package/dist/SvGrid.helpers.js +40 -12
- package/dist/SvGrid.svelte +84 -5
- package/dist/SvGrid.types.d.ts +36 -0
- package/dist/SvGridDropdown.svelte +16 -30
- package/dist/SvGridDropdown.svelte.d.ts +4 -0
- package/dist/SvListBox.svelte +89 -0
- package/dist/SvListBox.svelte.d.ts +22 -0
- package/dist/SvMaskedInput.svelte +66 -0
- package/dist/SvMaskedInput.svelte.d.ts +15 -0
- package/dist/SvNumberInput.svelte +116 -0
- package/dist/SvNumberInput.svelte.d.ts +18 -0
- package/dist/SvPasswordInput.svelte +100 -0
- package/dist/SvPasswordInput.svelte.d.ts +18 -0
- package/dist/SvPhoneInput.svelte +87 -0
- package/dist/SvPhoneInput.svelte.d.ts +19 -0
- package/dist/SvRadioGroup.svelte +85 -0
- package/dist/SvRadioGroup.svelte.d.ts +20 -0
- package/dist/SvRating.svelte +91 -0
- package/dist/SvRating.svelte.d.ts +18 -0
- package/dist/SvRepeatButton.svelte +89 -0
- package/dist/SvRepeatButton.svelte.d.ts +21 -0
- package/dist/SvSlider.svelte +155 -0
- package/dist/SvSlider.svelte.d.ts +20 -0
- package/dist/SvSwitchButton.svelte +87 -0
- package/dist/SvSwitchButton.svelte.d.ts +14 -0
- package/dist/SvTabs.svelte +109 -0
- package/dist/SvTabs.svelte.d.ts +26 -0
- package/dist/SvTagsInput.svelte +70 -0
- package/dist/SvTagsInput.svelte.d.ts +14 -0
- package/dist/SvTimePicker.svelte +201 -0
- package/dist/SvTimePicker.svelte.d.ts +30 -0
- package/dist/SvToggleButton.svelte +57 -0
- package/dist/SvToggleButton.svelte.d.ts +16 -0
- package/dist/SvTree.svelte +131 -0
- package/dist/SvTree.svelte.d.ts +27 -0
- package/dist/build-api.js +78 -1
- package/dist/cdn/svgrid.js +11674 -5907
- package/dist/cdn/svgrid.svelte-external.js +10436 -4671
- package/dist/cell-render.d.ts +4 -0
- package/dist/cell-render.js +35 -1
- package/dist/clipboard.js +19 -1
- package/dist/collaboration.d.ts +2 -0
- package/dist/collaboration.js +4 -0
- package/dist/core.d.ts +22 -1
- package/dist/countries.d.ts +15 -0
- package/dist/countries.js +61 -0
- package/dist/createAutocomplete.svelte.d.ts +77 -0
- package/dist/createAutocomplete.svelte.js +100 -0
- package/dist/createCalendar.svelte.d.ts +192 -0
- package/dist/createCalendar.svelte.js +402 -0
- package/dist/createCheckbox.svelte.d.ts +45 -0
- package/dist/createCheckbox.svelte.js +26 -0
- package/dist/createColorInput.svelte.d.ts +67 -0
- package/dist/createColorInput.svelte.js +100 -0
- package/dist/createCombobox.svelte.d.ts +102 -0
- package/dist/createCombobox.svelte.js +171 -0
- package/dist/createCountryInput.svelte.d.ts +86 -0
- package/dist/createCountryInput.svelte.js +126 -0
- package/dist/createDateTimePicker.svelte.d.ts +83 -0
- package/dist/createDateTimePicker.svelte.js +202 -0
- package/dist/createDropdownList.svelte.d.ts +78 -0
- package/dist/createDropdownList.svelte.js +117 -0
- package/dist/createGauge.svelte.d.ts +56 -0
- package/dist/createGauge.svelte.js +49 -0
- package/dist/createListbox.svelte.d.ts +79 -0
- package/dist/createListbox.svelte.js +117 -0
- package/dist/createMaskedInput.svelte.d.ts +30 -0
- package/dist/createMaskedInput.svelte.js +62 -0
- package/dist/createNumberInput.svelte.d.ts +72 -0
- package/dist/createNumberInput.svelte.js +167 -0
- package/dist/createPasswordInput.svelte.d.ts +60 -0
- package/dist/createPasswordInput.svelte.js +72 -0
- package/dist/createPhoneInput.svelte.d.ts +46 -0
- package/dist/createPhoneInput.svelte.js +105 -0
- package/dist/createRadioGroup.svelte.d.ts +64 -0
- package/dist/createRadioGroup.svelte.js +73 -0
- package/dist/createRating.svelte.d.ts +70 -0
- package/dist/createRating.svelte.js +85 -0
- package/dist/createSlider.svelte.d.ts +71 -0
- package/dist/createSlider.svelte.js +123 -0
- package/dist/createSwitch.svelte.d.ts +43 -0
- package/dist/createSwitch.svelte.js +41 -0
- package/dist/createTabs.svelte.d.ts +78 -0
- package/dist/createTabs.svelte.js +92 -0
- package/dist/createTagsInput.svelte.d.ts +65 -0
- package/dist/createTagsInput.svelte.js +93 -0
- package/dist/createTimePicker.svelte.d.ts +106 -0
- package/dist/createTimePicker.svelte.js +248 -0
- package/dist/createToggle.svelte.d.ts +43 -0
- package/dist/createToggle.svelte.js +39 -0
- package/dist/createTree.svelte.d.ts +96 -0
- package/dist/createTree.svelte.js +194 -0
- package/dist/datetime/date-core.d.ts +88 -0
- package/dist/datetime/date-core.js +165 -0
- package/dist/datetime/date-format.d.ts +39 -0
- package/dist/datetime/date-format.js +371 -0
- package/dist/datetime/date-restrict.d.ts +23 -0
- package/dist/datetime/date-restrict.js +50 -0
- package/dist/datetime/date-selection.d.ts +25 -0
- package/dist/datetime/date-selection.js +94 -0
- package/dist/datetime/mask.d.ts +21 -0
- package/dist/datetime/mask.js +90 -0
- package/dist/editing.d.ts +1 -1
- package/dist/editing.js +7 -0
- package/dist/editor-contract.d.ts +48 -0
- package/dist/editor-contract.js +26 -0
- package/dist/editors/cell-editors.d.ts +2 -2
- package/dist/editors/cell-editors.js +3 -1
- package/dist/export-format.d.ts +178 -0
- package/dist/export-format.js +419 -0
- package/dist/hyperformula-adapter.d.ts +4 -0
- package/dist/hyperformula-adapter.js +15 -6
- package/dist/index.d.ts +60 -0
- package/dist/index.js +72 -0
- package/dist/list-option.d.ts +10 -0
- package/dist/list-option.js +7 -0
- package/dist/menus.js +18 -2
- package/dist/popover.d.ts +48 -0
- package/dist/popover.js +65 -0
- package/dist/row-resize.d.ts +4 -4
- package/dist/row-resize.js +8 -5
- package/dist/selection.d.ts +6 -0
- package/dist/selection.js +31 -5
- package/dist/server-data-source.d.ts +43 -0
- package/dist/server-data-source.js +100 -0
- package/dist/sparkline.js +8 -4
- package/dist/svgrid-wrapper.types.d.ts +26 -1
- package/package.json +6 -1
- package/src/GridFooter.svelte +34 -20
- package/src/SvAutoComplete.svelte +89 -0
- package/src/SvButton.svelte +97 -0
- package/src/SvCalendar.svelte +409 -0
- package/src/SvCalendar.test.ts +211 -0
- package/src/SvCheckBox.svelte +82 -0
- package/src/SvColorInput.svelte +160 -0
- package/src/SvComboBox.svelte +108 -0
- package/src/SvCountryInput.svelte +125 -0
- package/src/SvDateTimePicker.svelte +265 -0
- package/src/SvDateTimePicker.test.ts +136 -0
- package/src/SvDropDownList.svelte +120 -0
- package/src/SvForm.svelte +147 -0
- package/src/SvGauge.svelte +97 -0
- package/src/SvGrid.controller.svelte.ts +74 -8
- package/src/SvGrid.css +84 -31
- package/src/SvGrid.helpers.ts +41 -12
- package/src/SvGrid.svelte +84 -5
- package/src/SvGrid.types.ts +33 -0
- package/src/SvGridDropdown.svelte +16 -30
- package/src/SvListBox.svelte +89 -0
- package/src/SvMaskedInput.svelte +66 -0
- package/src/SvNumberInput.svelte +116 -0
- package/src/SvPasswordInput.svelte +100 -0
- package/src/SvPhoneInput.svelte +87 -0
- package/src/SvRadioGroup.svelte +85 -0
- package/src/SvRating.svelte +91 -0
- package/src/SvRepeatButton.svelte +89 -0
- package/src/SvSlider.svelte +155 -0
- package/src/SvSwitchButton.svelte +87 -0
- package/src/SvTabs.svelte +109 -0
- package/src/SvTagsInput.svelte +70 -0
- package/src/SvTimePicker.svelte +201 -0
- package/src/SvTimePicker.test.ts +98 -0
- package/src/SvToggleButton.svelte +57 -0
- package/src/SvTree.svelte +131 -0
- package/src/build-api.ts +115 -0
- package/src/cell-render.test.ts +38 -0
- package/src/cell-render.ts +43 -0
- package/src/clipboard.test.ts +18 -0
- package/src/clipboard.ts +24 -1
- package/src/collaboration.test.ts +30 -0
- package/src/collaboration.ts +6 -0
- package/src/core.ts +27 -3
- package/src/countries.ts +71 -0
- package/src/createAutocomplete.svelte.ts +104 -0
- package/src/createCalendar.svelte.ts +488 -0
- package/src/createCheckbox.svelte.ts +74 -0
- package/src/createColorInput.svelte.ts +115 -0
- package/src/createCombobox.svelte.ts +158 -0
- package/src/createCountryInput.svelte.ts +126 -0
- package/src/createDateTimePicker.svelte.ts +216 -0
- package/src/createDropdownList.svelte.ts +125 -0
- package/src/createGauge.svelte.ts +86 -0
- package/src/createListbox.svelte.ts +186 -0
- package/src/createMaskedInput.svelte.ts +81 -0
- package/src/createNumberInput.svelte.ts +193 -0
- package/src/createPasswordInput.svelte.ts +87 -0
- package/src/createPhoneInput.svelte.ts +119 -0
- package/src/createRadioGroup.svelte.ts +132 -0
- package/src/createRating.svelte.ts +145 -0
- package/src/createSlider.svelte.ts +160 -0
- package/src/createSwitch.svelte.ts +78 -0
- package/src/createTabs.svelte.ts +129 -0
- package/src/createTagsInput.svelte.ts +98 -0
- package/src/createTimePicker.svelte.ts +289 -0
- package/src/createToggle.svelte.ts +69 -0
- package/src/createTree.svelte.ts +216 -0
- package/src/datetime/date-core.test.ts +217 -0
- package/src/datetime/date-core.ts +204 -0
- package/src/datetime/date-format.test.ts +121 -0
- package/src/datetime/date-format.ts +317 -0
- package/src/datetime/date-restrict.ts +60 -0
- package/src/datetime/date-selection.test.ts +129 -0
- package/src/datetime/date-selection.ts +137 -0
- package/src/datetime/mask.test.ts +36 -0
- package/src/datetime/mask.ts +84 -0
- package/src/editing.test.ts +22 -0
- package/src/editing.ts +7 -1
- package/src/editor-contract.test.ts +32 -0
- package/src/editor-contract.ts +60 -0
- package/src/editors/cell-editors.ts +7 -1
- package/src/export-data-api.test.ts +126 -0
- package/src/export-format.test.ts +107 -0
- package/src/export-format.ts +598 -0
- package/src/hyperformula-adapter.test.ts +35 -1
- package/src/hyperformula-adapter.ts +18 -6
- package/src/index.ts +110 -0
- package/src/list-option.ts +15 -0
- package/src/menus.ts +21 -2
- package/src/popover.ts +79 -0
- package/src/row-resize.test.ts +25 -0
- package/src/row-resize.ts +8 -5
- package/src/selection.test.ts +36 -4
- package/src/selection.ts +30 -9
- package/src/server-data-source.test.ts +201 -0
- package/src/server-data-source.ts +148 -0
- package/src/sparkline.test.ts +9 -0
- package/src/sparkline.ts +9 -4
- package/src/svgrid-wrapper.types.ts +28 -1
- package/src/svgrid.behavior.test.ts +27 -0
- package/src/svgrid.new-features.wrapper.test.ts +27 -1
- package/src/ui-buttons.test.ts +105 -0
- package/src/ui-composite.test.ts +89 -0
- package/src/ui-inputs.test.ts +118 -0
- package/src/ui-range.test.ts +61 -0
- package/src/ui-selection.test.ts +119 -0
package/dist/cell-render.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ export declare function createCellRender<TFeatures extends TableFeatures = Table
|
|
|
6
6
|
computeRowClass: (row: Row<TData>, rowIndex: number) => string;
|
|
7
7
|
computeCellClass: (row: Row<TData>, column: Column<TData>) => string;
|
|
8
8
|
computeCellTooltip: (row: Row<TData>, column: Column<TData>) => string | null;
|
|
9
|
+
computeCellValidity: (row: Row<TData>, column: Column<TData>) => {
|
|
10
|
+
invalid: boolean;
|
|
11
|
+
message: string | null;
|
|
12
|
+
};
|
|
9
13
|
computeCellNote: (row: Row<TData>, column: Column<TData>) => string | null;
|
|
10
14
|
getColumnEditorOptions: (column: Column<TData>, row?: Row<TData> | null) => CellEditorOption[];
|
|
11
15
|
formatListCellValue: (column: Column<TData>, value: unknown, row?: Row<TData> | null) => string;
|
package/dist/cell-render.js
CHANGED
|
@@ -5,7 +5,7 @@ import { normalizeEditorOptions, } from "./index";
|
|
|
5
5
|
import "./sv-grid-scrollbar";
|
|
6
6
|
import { formatNumericWithConfig, getDateFormatter, resolveDatePattern, } from "./cell-formatting";
|
|
7
7
|
import { resolveCellFormat, } from "./conditional-formatting";
|
|
8
|
-
import { resolveClassList, getOptionLabel, asDate, } from "./SvGrid.helpers";
|
|
8
|
+
import { getCellKey, resolveClassList, getOptionLabel, asDate, } from "./SvGrid.helpers";
|
|
9
9
|
import { getPinnedCellValue, } from "./cell-values";
|
|
10
10
|
export function createCellRender(ctx) {
|
|
11
11
|
function cellConditionalFormat(row, column, value) {
|
|
@@ -69,6 +69,39 @@ export function createCellRender(ctx) {
|
|
|
69
69
|
}
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve per-cell validity via the column's declarative `validate` hook.
|
|
74
|
+
* Runs for every rendered cell so pre-existing bad data is flagged on load.
|
|
75
|
+
* Returns `{ invalid, message }` - `invalid` drives the red highlight class,
|
|
76
|
+
* `message` (when present) becomes the cell's tooltip.
|
|
77
|
+
*/
|
|
78
|
+
function computeCellValidity(row, column) {
|
|
79
|
+
const rule = column.columnDef.validate;
|
|
80
|
+
if (typeof rule !== "function")
|
|
81
|
+
return { invalid: false, message: null };
|
|
82
|
+
// Read the edit-aware value: inline edits land in `editedCellValues`
|
|
83
|
+
// (keyed rowId:colId) and are NOT written into the row's memoized value
|
|
84
|
+
// cache, so `getCellValueByColumnId` would return the stale pre-edit value
|
|
85
|
+
// and validation would never re-run after an edit. Consult the overlay
|
|
86
|
+
// first - same rule the display path (getCellDisplayValue) and summaries
|
|
87
|
+
// use - so a cell re-validates live as the user types.
|
|
88
|
+
const edited = ctx.editedCellValues ?? {};
|
|
89
|
+
const key = getCellKey(row.id, column.id);
|
|
90
|
+
const value = key in edited ? edited[key] : row.getCellValueByColumnId(column.id);
|
|
91
|
+
const out = rule({
|
|
92
|
+
value,
|
|
93
|
+
row: row.original,
|
|
94
|
+
rowIndex: row.index,
|
|
95
|
+
column,
|
|
96
|
+
});
|
|
97
|
+
// Valid: null / undefined / true. Invalid: false or a message string.
|
|
98
|
+
if (out == null || out === true)
|
|
99
|
+
return { invalid: false, message: null };
|
|
100
|
+
if (out === false)
|
|
101
|
+
return { invalid: true, message: null };
|
|
102
|
+
const msg = String(out);
|
|
103
|
+
return { invalid: true, message: msg.trim() ? msg : null };
|
|
104
|
+
}
|
|
72
105
|
/**
|
|
73
106
|
* Resolve a per-cell note (a longer comment / annotation). Notes
|
|
74
107
|
* come from the grid's `notes` prop - a `{ [rowId]: { [columnId]: string } }`
|
|
@@ -236,6 +269,7 @@ export function createCellRender(ctx) {
|
|
|
236
269
|
computeRowClass,
|
|
237
270
|
computeCellClass,
|
|
238
271
|
computeCellTooltip,
|
|
272
|
+
computeCellValidity,
|
|
239
273
|
computeCellNote,
|
|
240
274
|
getColumnEditorOptions,
|
|
241
275
|
formatListCellValue,
|
package/dist/clipboard.js
CHANGED
|
@@ -355,6 +355,7 @@ export function createClipboard(ctx) {
|
|
|
355
355
|
const endCol = Math.max(anchor.colIndex, focus.colIndex);
|
|
356
356
|
const next = ctx.internalData.slice();
|
|
357
357
|
let mutated = false;
|
|
358
|
+
const changes = [];
|
|
358
359
|
for (let r = startRow; r <= endRow; r += 1) {
|
|
359
360
|
const row = ctx.allRows[r];
|
|
360
361
|
if (!row || isGroupRow(row))
|
|
@@ -381,8 +382,18 @@ export function createClipboard(ctx) {
|
|
|
381
382
|
// else. parseEditorValue handles the per-type coercion.
|
|
382
383
|
const editorType = (column.columnDef.editorType ??
|
|
383
384
|
"text");
|
|
384
|
-
|
|
385
|
+
const field = column.columnDef.field;
|
|
386
|
+
const oldValue = updated[field];
|
|
387
|
+
const cleared = parseEditorValue(editorType, "");
|
|
388
|
+
updated[field] = cleared;
|
|
385
389
|
rowChanged = true;
|
|
390
|
+
changes.push({
|
|
391
|
+
rowIndex: dataIndex,
|
|
392
|
+
columnId: column.id,
|
|
393
|
+
oldValue,
|
|
394
|
+
newValue: cleared,
|
|
395
|
+
row: updated,
|
|
396
|
+
});
|
|
386
397
|
}
|
|
387
398
|
if (rowChanged) {
|
|
388
399
|
next[dataIndex] = updated;
|
|
@@ -392,6 +403,13 @@ export function createClipboard(ctx) {
|
|
|
392
403
|
if (mutated) {
|
|
393
404
|
ctx.internalData = next;
|
|
394
405
|
ctx.grid.store.setState((prev) => ({ ...prev }));
|
|
406
|
+
// Fire onCellValueChange per cleared cell - same as paste's writeCellRaw -
|
|
407
|
+
// so consumers (formula engines, autosave) recompute. Clear IS a value
|
|
408
|
+
// change; without this, a HyperFormula-backed grid wouldn't re-evaluate.
|
|
409
|
+
if (ctx.props.onCellValueChange) {
|
|
410
|
+
for (const ch of changes)
|
|
411
|
+
ctx.props.onCellValueChange(ch);
|
|
412
|
+
}
|
|
395
413
|
}
|
|
396
414
|
return mutated;
|
|
397
415
|
}
|
package/dist/collaboration.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ export type CollabMessage = {
|
|
|
43
43
|
export type CollabTransport = {
|
|
44
44
|
post(msg: CollabMessage): void;
|
|
45
45
|
subscribe(handler: (msg: CollabMessage) => void): () => void;
|
|
46
|
+
/** Release any underlying resource (e.g. a BroadcastChannel). Optional. */
|
|
47
|
+
dispose?(): void;
|
|
46
48
|
};
|
|
47
49
|
export type Collaboration = {
|
|
48
50
|
/** Broadcast where this user's cursor is (or null when it leaves). */
|
package/dist/collaboration.js
CHANGED
|
@@ -14,6 +14,9 @@ export function broadcastChannelTransport(name) {
|
|
|
14
14
|
channel.addEventListener('message', listener);
|
|
15
15
|
return () => channel.removeEventListener('message', listener);
|
|
16
16
|
},
|
|
17
|
+
dispose() {
|
|
18
|
+
channel?.close();
|
|
19
|
+
},
|
|
17
20
|
};
|
|
18
21
|
}
|
|
19
22
|
export function createCollaboration(options) {
|
|
@@ -93,6 +96,7 @@ export function createCollaboration(options) {
|
|
|
93
96
|
unsubscribe();
|
|
94
97
|
if (pruneTimer)
|
|
95
98
|
clearInterval(pruneTimer);
|
|
99
|
+
transport.dispose?.(); // release the channel (BroadcastChannel etc.)
|
|
96
100
|
},
|
|
97
101
|
};
|
|
98
102
|
}
|
package/dist/core.d.ts
CHANGED
|
@@ -173,7 +173,7 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
|
|
|
173
173
|
* and `columnGroupShow: 'closed'` children show until the user expands it.
|
|
174
174
|
*/
|
|
175
175
|
openByDefault?: boolean;
|
|
176
|
-
editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'autocomplete' | 'textarea' | 'color' | 'rating';
|
|
176
|
+
editorType?: 'text' | 'number' | 'date' | 'datetime' | 'time' | 'date-native' | 'datetime-native' | 'time-native' | 'password' | 'checkbox' | 'list' | 'chips' | 'select' | 'rich-select' | 'autocomplete' | 'textarea' | 'color' | 'rating';
|
|
177
177
|
/**
|
|
178
178
|
* Custom in-cell editor. Receives the cell context PLUS a `commit(value)`
|
|
179
179
|
* and `cancel()` helper. Use when none of the built-in `editorType`s fit;
|
|
@@ -191,6 +191,27 @@ export type ColumnDef<TFeatures extends TableFeatures, TData extends RowData> =
|
|
|
191
191
|
* string skips the tooltip.
|
|
192
192
|
*/
|
|
193
193
|
tooltip?: string | ((ctx: CellContext<TData>) => string | null | undefined);
|
|
194
|
+
/**
|
|
195
|
+
* Declarative per-cell validation (Handsontable-style). Runs for EVERY
|
|
196
|
+
* rendered cell - including values already present in `data` on load, not
|
|
197
|
+
* just on edit - so bad data is flagged immediately. Invalid cells get the
|
|
198
|
+
* `sv-grid-cell-invalid` class (red highlight) and the returned message as
|
|
199
|
+
* their tooltip.
|
|
200
|
+
*
|
|
201
|
+
* Return value:
|
|
202
|
+
* - `null` / `undefined` / `true` → valid (no highlight)
|
|
203
|
+
* - `false` → invalid, no message
|
|
204
|
+
* - a non-empty `string` → invalid, string is the tooltip
|
|
205
|
+
*
|
|
206
|
+
* The value keeps rendering as-is (the grid does NOT roll it back); pair
|
|
207
|
+
* with `onCellValueChange` if you also want to reject the commit.
|
|
208
|
+
*/
|
|
209
|
+
validate?: (params: {
|
|
210
|
+
value: unknown;
|
|
211
|
+
row: TData;
|
|
212
|
+
rowIndex: number;
|
|
213
|
+
column: Column<TData>;
|
|
214
|
+
}) => string | boolean | null | undefined;
|
|
194
215
|
/**
|
|
195
216
|
* Gate editing per column or per cell.
|
|
196
217
|
*
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* countries - a compact country reference for SvPhoneInput / SvCountryInput.
|
|
3
|
+
* ISO 3166-1 alpha-2 code, display name, E.164 dial code, and a flag emoji
|
|
4
|
+
* (derived from the code so no image assets are needed). This is a curated
|
|
5
|
+
* common-set; extend `COUNTRIES` for full coverage.
|
|
6
|
+
*/
|
|
7
|
+
export type Country = {
|
|
8
|
+
code: string;
|
|
9
|
+
name: string;
|
|
10
|
+
dial: string;
|
|
11
|
+
};
|
|
12
|
+
/** Regional-indicator flag emoji from an ISO alpha-2 code. */
|
|
13
|
+
export declare function flagEmoji(code: string): string;
|
|
14
|
+
export declare const COUNTRIES: Country[];
|
|
15
|
+
export declare const COUNTRY_BY_CODE: Map<string, Country>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Regional-indicator flag emoji from an ISO alpha-2 code. */
|
|
2
|
+
export function flagEmoji(code) {
|
|
3
|
+
return code
|
|
4
|
+
.toUpperCase()
|
|
5
|
+
.replace(/./g, (c) => String.fromCodePoint(127397 + c.charCodeAt(0)));
|
|
6
|
+
}
|
|
7
|
+
export const COUNTRIES = [
|
|
8
|
+
{ code: 'US', name: 'United States', dial: '+1' },
|
|
9
|
+
{ code: 'CA', name: 'Canada', dial: '+1' },
|
|
10
|
+
{ code: 'GB', name: 'United Kingdom', dial: '+44' },
|
|
11
|
+
{ code: 'IE', name: 'Ireland', dial: '+353' },
|
|
12
|
+
{ code: 'FR', name: 'France', dial: '+33' },
|
|
13
|
+
{ code: 'DE', name: 'Germany', dial: '+49' },
|
|
14
|
+
{ code: 'ES', name: 'Spain', dial: '+34' },
|
|
15
|
+
{ code: 'PT', name: 'Portugal', dial: '+351' },
|
|
16
|
+
{ code: 'IT', name: 'Italy', dial: '+39' },
|
|
17
|
+
{ code: 'NL', name: 'Netherlands', dial: '+31' },
|
|
18
|
+
{ code: 'BE', name: 'Belgium', dial: '+32' },
|
|
19
|
+
{ code: 'CH', name: 'Switzerland', dial: '+41' },
|
|
20
|
+
{ code: 'AT', name: 'Austria', dial: '+43' },
|
|
21
|
+
{ code: 'SE', name: 'Sweden', dial: '+46' },
|
|
22
|
+
{ code: 'NO', name: 'Norway', dial: '+47' },
|
|
23
|
+
{ code: 'DK', name: 'Denmark', dial: '+45' },
|
|
24
|
+
{ code: 'FI', name: 'Finland', dial: '+358' },
|
|
25
|
+
{ code: 'PL', name: 'Poland', dial: '+48' },
|
|
26
|
+
{ code: 'CZ', name: 'Czechia', dial: '+420' },
|
|
27
|
+
{ code: 'GR', name: 'Greece', dial: '+30' },
|
|
28
|
+
{ code: 'BG', name: 'Bulgaria', dial: '+359' },
|
|
29
|
+
{ code: 'RO', name: 'Romania', dial: '+40' },
|
|
30
|
+
{ code: 'UA', name: 'Ukraine', dial: '+380' },
|
|
31
|
+
{ code: 'RU', name: 'Russia', dial: '+7' },
|
|
32
|
+
{ code: 'TR', name: 'Turkey', dial: '+90' },
|
|
33
|
+
{ code: 'IL', name: 'Israel', dial: '+972' },
|
|
34
|
+
{ code: 'AE', name: 'United Arab Emirates', dial: '+971' },
|
|
35
|
+
{ code: 'SA', name: 'Saudi Arabia', dial: '+966' },
|
|
36
|
+
{ code: 'IN', name: 'India', dial: '+91' },
|
|
37
|
+
{ code: 'PK', name: 'Pakistan', dial: '+92' },
|
|
38
|
+
{ code: 'CN', name: 'China', dial: '+86' },
|
|
39
|
+
{ code: 'HK', name: 'Hong Kong', dial: '+852' },
|
|
40
|
+
{ code: 'JP', name: 'Japan', dial: '+81' },
|
|
41
|
+
{ code: 'KR', name: 'South Korea', dial: '+82' },
|
|
42
|
+
{ code: 'SG', name: 'Singapore', dial: '+65' },
|
|
43
|
+
{ code: 'MY', name: 'Malaysia', dial: '+60' },
|
|
44
|
+
{ code: 'TH', name: 'Thailand', dial: '+66' },
|
|
45
|
+
{ code: 'ID', name: 'Indonesia', dial: '+62' },
|
|
46
|
+
{ code: 'PH', name: 'Philippines', dial: '+63' },
|
|
47
|
+
{ code: 'VN', name: 'Vietnam', dial: '+84' },
|
|
48
|
+
{ code: 'AU', name: 'Australia', dial: '+61' },
|
|
49
|
+
{ code: 'NZ', name: 'New Zealand', dial: '+64' },
|
|
50
|
+
{ code: 'ZA', name: 'South Africa', dial: '+27' },
|
|
51
|
+
{ code: 'NG', name: 'Nigeria', dial: '+234' },
|
|
52
|
+
{ code: 'EG', name: 'Egypt', dial: '+20' },
|
|
53
|
+
{ code: 'KE', name: 'Kenya', dial: '+254' },
|
|
54
|
+
{ code: 'MA', name: 'Morocco', dial: '+212' },
|
|
55
|
+
{ code: 'BR', name: 'Brazil', dial: '+55' },
|
|
56
|
+
{ code: 'AR', name: 'Argentina', dial: '+54' },
|
|
57
|
+
{ code: 'CL', name: 'Chile', dial: '+56' },
|
|
58
|
+
{ code: 'CO', name: 'Colombia', dial: '+57' },
|
|
59
|
+
{ code: 'MX', name: 'Mexico', dial: '+52' },
|
|
60
|
+
];
|
|
61
|
+
export const COUNTRY_BY_CODE = new Map(COUNTRIES.map((c) => [c.code, c]));
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createAutocomplete - the HEADLESS core behind <SvAutoComplete>: a free-text
|
|
3
|
+
* field with a live-filtered suggestion list (accepts ANY typed value; the
|
|
4
|
+
* suggestions are shortcuts). Roving active index + keyboard, exposed as
|
|
5
|
+
* **prop-getters** you spread onto YOUR OWN markup. No styles/DOM/portal - those
|
|
6
|
+
* stay in the styled component.
|
|
7
|
+
*
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <script lang="ts">
|
|
10
|
+
* import { createAutocomplete } from '@svgrid/grid'
|
|
11
|
+
* let value = $state('')
|
|
12
|
+
* const ac = createAutocomplete({ value: () => value, suggestions: () => list, onChange: (v) => (value = v) })
|
|
13
|
+
* </script>
|
|
14
|
+
* <input {...ac.inputProps()} />
|
|
15
|
+
* {#if ac.open}
|
|
16
|
+
* <ul {...ac.listboxProps()}>
|
|
17
|
+
* {#each ac.filtered as opt, i (opt.value)}<li {...ac.optionProps(i)}>{opt.label}</li>{/each}
|
|
18
|
+
* </ul>
|
|
19
|
+
* {/if}
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { type ListOption } from './list-option';
|
|
23
|
+
/** Reactive inputs are passed as getters so the core tracks live prop changes. */
|
|
24
|
+
export type AutocompleteConfig = {
|
|
25
|
+
value: () => string;
|
|
26
|
+
onChange?: (value: string) => void;
|
|
27
|
+
/** Suggestions - strings or {value,label} (label shown, value inserted). */
|
|
28
|
+
suggestions: () => ReadonlyArray<string | ListOption>;
|
|
29
|
+
minChars?: () => number;
|
|
30
|
+
disabled?: () => boolean;
|
|
31
|
+
ariaLabel?: () => string | undefined;
|
|
32
|
+
/** DOM focus hook provided by the renderer; the core never touches the DOM. */
|
|
33
|
+
focusInput?: () => void;
|
|
34
|
+
};
|
|
35
|
+
export declare function createAutocomplete(config: AutocompleteConfig): {
|
|
36
|
+
/** Panel open state. */
|
|
37
|
+
readonly open: boolean;
|
|
38
|
+
/** Highlighted suggestion index into `filtered`. */
|
|
39
|
+
readonly activeIndex: number;
|
|
40
|
+
/** Suggestions after the live substring filter (capped at 10). */
|
|
41
|
+
readonly filtered: ListOption[];
|
|
42
|
+
/** Controlled text value. */
|
|
43
|
+
readonly value: string;
|
|
44
|
+
isActive: (i: number) => boolean;
|
|
45
|
+
setActive: (i: number) => void;
|
|
46
|
+
maybeOpen: () => void;
|
|
47
|
+
close: () => void;
|
|
48
|
+
pick: (o: ListOption | undefined) => void;
|
|
49
|
+
onInput: (e: Event) => void;
|
|
50
|
+
onKeydown: (e: KeyboardEvent) => void;
|
|
51
|
+
/** Spread onto the text <input>. */
|
|
52
|
+
inputProps: () => {
|
|
53
|
+
role: "combobox";
|
|
54
|
+
'aria-expanded': boolean;
|
|
55
|
+
'aria-autocomplete': "list";
|
|
56
|
+
'aria-label': string | undefined;
|
|
57
|
+
value: string;
|
|
58
|
+
disabled: boolean;
|
|
59
|
+
oninput: (e: Event) => void;
|
|
60
|
+
onfocus: () => void;
|
|
61
|
+
onkeydown: (e: KeyboardEvent) => void;
|
|
62
|
+
};
|
|
63
|
+
/** Spread onto the listbox container. */
|
|
64
|
+
listboxProps: () => {
|
|
65
|
+
role: "listbox";
|
|
66
|
+
};
|
|
67
|
+
/** Spread onto the suggestion at `index` (index into `filtered`). */
|
|
68
|
+
optionProps: (index: number) => {
|
|
69
|
+
role: "option";
|
|
70
|
+
tabindex: number;
|
|
71
|
+
'aria-selected': boolean;
|
|
72
|
+
'data-idx': number;
|
|
73
|
+
onclick: () => void;
|
|
74
|
+
onpointermove: () => void;
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
export type Autocomplete = ReturnType<typeof createAutocomplete>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createAutocomplete - the HEADLESS core behind <SvAutoComplete>: a free-text
|
|
3
|
+
* field with a live-filtered suggestion list (accepts ANY typed value; the
|
|
4
|
+
* suggestions are shortcuts). Roving active index + keyboard, exposed as
|
|
5
|
+
* **prop-getters** you spread onto YOUR OWN markup. No styles/DOM/portal - those
|
|
6
|
+
* stay in the styled component.
|
|
7
|
+
*
|
|
8
|
+
* ```svelte
|
|
9
|
+
* <script lang="ts">
|
|
10
|
+
* import { createAutocomplete } from '@svgrid/grid'
|
|
11
|
+
* let value = $state('')
|
|
12
|
+
* const ac = createAutocomplete({ value: () => value, suggestions: () => list, onChange: (v) => (value = v) })
|
|
13
|
+
* </script>
|
|
14
|
+
* <input {...ac.inputProps()} />
|
|
15
|
+
* {#if ac.open}
|
|
16
|
+
* <ul {...ac.listboxProps()}>
|
|
17
|
+
* {#each ac.filtered as opt, i (opt.value)}<li {...ac.optionProps(i)}>{opt.label}</li>{/each}
|
|
18
|
+
* </ul>
|
|
19
|
+
* {/if}
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { filterOptions } from './list-option';
|
|
23
|
+
export function createAutocomplete(config) {
|
|
24
|
+
const minChars = () => config.minChars?.() ?? 1;
|
|
25
|
+
let open = $state(false);
|
|
26
|
+
let active = $state(0);
|
|
27
|
+
const asOptions = $derived(config.suggestions().map((s) => (typeof s === 'string' ? { value: s, label: s } : s)));
|
|
28
|
+
const filtered = $derived(config.value().length >= minChars() ? filterOptions(asOptions, config.value()).slice(0, 10) : []);
|
|
29
|
+
function maybeOpen() { open = filtered.length > 0; if (open)
|
|
30
|
+
active = 0; }
|
|
31
|
+
function pick(o) { if (!o)
|
|
32
|
+
return; config.onChange?.(String(o.value)); open = false; config.focusInput?.(); }
|
|
33
|
+
function close() { open = false; }
|
|
34
|
+
function onInput(e) { config.onChange?.(e.currentTarget.value); queueMicrotask(maybeOpen); }
|
|
35
|
+
function onKeydown(e) {
|
|
36
|
+
if (!open) {
|
|
37
|
+
if (e.key === 'ArrowDown') {
|
|
38
|
+
queueMicrotask(maybeOpen);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (e.key === 'ArrowDown') {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
active = Math.min(active + 1, filtered.length - 1);
|
|
45
|
+
}
|
|
46
|
+
else if (e.key === 'ArrowUp') {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
active = Math.max(active - 1, 0);
|
|
49
|
+
}
|
|
50
|
+
else if (e.key === 'Enter') {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
pick(filtered[active]);
|
|
53
|
+
}
|
|
54
|
+
else if (e.key === 'Escape') {
|
|
55
|
+
close();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
/** Panel open state. */
|
|
60
|
+
get open() { return open; },
|
|
61
|
+
/** Highlighted suggestion index into `filtered`. */
|
|
62
|
+
get activeIndex() { return active; },
|
|
63
|
+
/** Suggestions after the live substring filter (capped at 10). */
|
|
64
|
+
get filtered() { return filtered; },
|
|
65
|
+
/** Controlled text value. */
|
|
66
|
+
get value() { return config.value(); },
|
|
67
|
+
isActive: (i) => i === active,
|
|
68
|
+
setActive: (i) => { active = i; },
|
|
69
|
+
maybeOpen,
|
|
70
|
+
close,
|
|
71
|
+
pick,
|
|
72
|
+
onInput,
|
|
73
|
+
onKeydown,
|
|
74
|
+
/** Spread onto the text <input>. */
|
|
75
|
+
inputProps: () => ({
|
|
76
|
+
role: 'combobox',
|
|
77
|
+
'aria-expanded': open,
|
|
78
|
+
'aria-autocomplete': 'list',
|
|
79
|
+
'aria-label': config.ariaLabel?.(),
|
|
80
|
+
value: config.value(),
|
|
81
|
+
disabled: config.disabled?.() ?? false,
|
|
82
|
+
oninput: onInput,
|
|
83
|
+
onfocus: maybeOpen,
|
|
84
|
+
onkeydown: onKeydown,
|
|
85
|
+
}),
|
|
86
|
+
/** Spread onto the listbox container. */
|
|
87
|
+
listboxProps: () => ({
|
|
88
|
+
role: 'listbox',
|
|
89
|
+
}),
|
|
90
|
+
/** Spread onto the suggestion at `index` (index into `filtered`). */
|
|
91
|
+
optionProps: (index) => ({
|
|
92
|
+
role: 'option',
|
|
93
|
+
tabindex: -1,
|
|
94
|
+
'aria-selected': index === active,
|
|
95
|
+
'data-idx': index,
|
|
96
|
+
onclick: () => pick(filtered[index]),
|
|
97
|
+
onpointermove: () => { active = index; },
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createCalendar - the HEADLESS core behind <SvCalendar>, in the same spirit as
|
|
3
|
+
* `createListbox` / `createSvGrid`: a runes-based state machine (view page +
|
|
4
|
+
* drill level, roving focus, every Smart `selectionMode`, range hover preview,
|
|
5
|
+
* full keyboard) with **prop-getters** you spread onto YOUR OWN markup. No
|
|
6
|
+
* styles, no DOM assumptions. It reuses the framework-free date engine in
|
|
7
|
+
* ./datetime for all the actual date math / selection / restriction, so this
|
|
8
|
+
* file only owns the reactive component-level state + interaction wiring.
|
|
9
|
+
*
|
|
10
|
+
* ```svelte
|
|
11
|
+
* <script lang="ts">
|
|
12
|
+
* import { createCalendar } from '@svgrid/grid'
|
|
13
|
+
* let value = $state<Date | null>(new Date())
|
|
14
|
+
* const cal = createCalendar({ value: () => value, onChange: (d) => (value = d[0] ?? null) })
|
|
15
|
+
* </script>
|
|
16
|
+
* <div {...cal.gridProps()}>
|
|
17
|
+
* {#each cal.panels[0].matrix as week}
|
|
18
|
+
* {#each week as cell}
|
|
19
|
+
* <button {...cal.dayProps(cell, cal.panels[0].month)}>{cell.date.getDate()}</button>
|
|
20
|
+
* {/each}
|
|
21
|
+
* {/each}
|
|
22
|
+
* </div>
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The styled <SvCalendar> is one renderer over this core; it keeps the render-only
|
|
26
|
+
* concerns (WAAPI view-change animation, mouse-wheel navigation, DOM refs) itself.
|
|
27
|
+
*/
|
|
28
|
+
import { type DateLike, type MonthMatrixCell } from './datetime/date-core';
|
|
29
|
+
import { type SelectionMode } from './datetime/date-selection';
|
|
30
|
+
import { type RestrictOptions } from './datetime/date-restrict';
|
|
31
|
+
export type DisplayMode = 'month' | 'year' | 'decade';
|
|
32
|
+
export type CalendarNameFormat = 'narrow' | 'short' | 'long';
|
|
33
|
+
/** Selected value(s). Single Date for one/zeroOrOne, array for multi modes. */
|
|
34
|
+
export type CalendarValue = Date | number | string | ReadonlyArray<Date | number | string> | null;
|
|
35
|
+
/** A one-click shortcut shown in the presets rail. `value` is a single date
|
|
36
|
+
* (or an [start, end] range for range mode); pass a function for "today"-
|
|
37
|
+
* relative shortcuts that resolve at click time. */
|
|
38
|
+
export type CalendarPreset = {
|
|
39
|
+
label: string;
|
|
40
|
+
value: Date | number | string | readonly [Date | number | string, Date | number | string] | (() => Date | number | string | readonly [Date | number | string, Date | number | string]);
|
|
41
|
+
};
|
|
42
|
+
/** How the calendar animates a navigation / drill (a render concern the styled
|
|
43
|
+
* component acts on; the core only reports the direction). */
|
|
44
|
+
export type CalendarAnimation = 'slide' | 'fade' | 'none';
|
|
45
|
+
/** Why the visible view last changed - drives the styled component's animation. */
|
|
46
|
+
export type CalendarNavDir = 'next' | 'prev' | 'drillDown' | 'drillUp' | 'fade';
|
|
47
|
+
/** Per-day interaction/visual state (booleans the renderer maps to classes). */
|
|
48
|
+
export type CalendarDayState = {
|
|
49
|
+
disabled: boolean;
|
|
50
|
+
selected: boolean;
|
|
51
|
+
important: boolean;
|
|
52
|
+
today: boolean;
|
|
53
|
+
outside: boolean;
|
|
54
|
+
focused: boolean;
|
|
55
|
+
preview: boolean;
|
|
56
|
+
};
|
|
57
|
+
/** Reactive inputs are passed as getters so the core tracks live prop changes;
|
|
58
|
+
* callbacks are plain closures. */
|
|
59
|
+
export type CalendarConfig = {
|
|
60
|
+
value: () => CalendarValue;
|
|
61
|
+
onChange?: (dates: Date[]) => void;
|
|
62
|
+
onNavigate?: (viewDate: Date, displayMode: DisplayMode) => void;
|
|
63
|
+
selectionMode?: () => SelectionMode;
|
|
64
|
+
min?: () => DateLike | null;
|
|
65
|
+
max?: () => DateLike | null;
|
|
66
|
+
restrictedDates?: () => RestrictOptions['restrictedDates'];
|
|
67
|
+
importantDates?: () => ReadonlyArray<DateLike> | ((d: Date) => boolean) | null;
|
|
68
|
+
firstDayOfWeek?: () => number;
|
|
69
|
+
weeks?: () => number;
|
|
70
|
+
months?: () => number;
|
|
71
|
+
displayMode?: () => DisplayMode;
|
|
72
|
+
disabled?: () => boolean;
|
|
73
|
+
readonly?: () => boolean;
|
|
74
|
+
locale?: () => string;
|
|
75
|
+
dayNameFormat?: () => CalendarNameFormat;
|
|
76
|
+
monthNameFormat?: () => CalendarNameFormat;
|
|
77
|
+
dateTooltip?: () => ((date: Date) => string | null | undefined) | undefined;
|
|
78
|
+
};
|
|
79
|
+
/** Normalize a calendar value to an ordered day-midnight list (pure). */
|
|
80
|
+
export declare function normalizeCalendarValue(v: CalendarValue): Date[];
|
|
81
|
+
export declare function createCalendar(config: CalendarConfig): {
|
|
82
|
+
readonly view: Date;
|
|
83
|
+
readonly mode: DisplayMode;
|
|
84
|
+
readonly title: string;
|
|
85
|
+
readonly panels: {
|
|
86
|
+
month: Date;
|
|
87
|
+
title: string;
|
|
88
|
+
matrix: MonthMatrixCell[][];
|
|
89
|
+
}[];
|
|
90
|
+
readonly weekdayHeaders: {
|
|
91
|
+
label: string;
|
|
92
|
+
weekday: number;
|
|
93
|
+
}[];
|
|
94
|
+
readonly yearCells: {
|
|
95
|
+
index: number;
|
|
96
|
+
label: string;
|
|
97
|
+
current: boolean;
|
|
98
|
+
selected: boolean;
|
|
99
|
+
}[];
|
|
100
|
+
readonly decadeCells: {
|
|
101
|
+
year: number;
|
|
102
|
+
outside: boolean;
|
|
103
|
+
current: boolean;
|
|
104
|
+
selected: boolean;
|
|
105
|
+
}[];
|
|
106
|
+
readonly selectedDates: Date[];
|
|
107
|
+
readonly previewRange: Date[] | null;
|
|
108
|
+
readonly focusDate: Date;
|
|
109
|
+
readonly hoverDate: Date | null;
|
|
110
|
+
readonly canClear: boolean;
|
|
111
|
+
readonly isInteractive: boolean;
|
|
112
|
+
/** Increments on every view/drill change; the styled component watches it to
|
|
113
|
+
* replay its WAAPI animation on the updated DOM. */
|
|
114
|
+
readonly navToken: number;
|
|
115
|
+
/** Why the view last changed (read untracked from the animation effect). */
|
|
116
|
+
readonly navDir: CalendarNavDir;
|
|
117
|
+
dayState: (d: Date, panelMonth: Date) => CalendarDayState;
|
|
118
|
+
inPreview: (d: Date) => boolean;
|
|
119
|
+
formatFullDate: (d: Date) => string;
|
|
120
|
+
formatMonthTitle: (d: Date) => string;
|
|
121
|
+
pickDay: (d: Date, e?: {
|
|
122
|
+
ctrlKey?: boolean;
|
|
123
|
+
metaKey?: boolean;
|
|
124
|
+
shiftKey?: boolean;
|
|
125
|
+
}) => void;
|
|
126
|
+
step: (dir: -1 | 1) => void;
|
|
127
|
+
drillUp: () => void;
|
|
128
|
+
pickMonth: (monthIndex: number) => void;
|
|
129
|
+
pickYear: (year: number) => void;
|
|
130
|
+
goToday: () => void;
|
|
131
|
+
applyPreset: (p: CalendarPreset) => void;
|
|
132
|
+
clearSelection: () => void;
|
|
133
|
+
setHover: (d: Date | null) => Date | null;
|
|
134
|
+
onKeydown: (e: KeyboardEvent) => void;
|
|
135
|
+
/** Previous / Next navigation button. */
|
|
136
|
+
navProps(dir: -1 | 1): {
|
|
137
|
+
type: "button";
|
|
138
|
+
disabled: boolean;
|
|
139
|
+
'aria-label': string;
|
|
140
|
+
onclick: () => void;
|
|
141
|
+
};
|
|
142
|
+
/** The centered title button that drills up (month -> year -> decade). */
|
|
143
|
+
titleProps(): {
|
|
144
|
+
type: "button";
|
|
145
|
+
disabled: boolean;
|
|
146
|
+
'aria-live': "polite";
|
|
147
|
+
onclick: () => void;
|
|
148
|
+
};
|
|
149
|
+
/** The grid container: keyboard + ARIA. Works for month, year and decade
|
|
150
|
+
* modes (the handler dispatches on the current mode). */
|
|
151
|
+
gridProps(): {
|
|
152
|
+
role: "grid";
|
|
153
|
+
'aria-label': string;
|
|
154
|
+
tabindex: number;
|
|
155
|
+
onkeydown: (e: KeyboardEvent) => void;
|
|
156
|
+
};
|
|
157
|
+
/** A single day button in the month grid. Combine with `dayState` for the
|
|
158
|
+
* visual class flags. */
|
|
159
|
+
dayProps(cell: MonthMatrixCell, panelMonth: Date): {
|
|
160
|
+
type: "button";
|
|
161
|
+
role: "gridcell";
|
|
162
|
+
'aria-selected': boolean;
|
|
163
|
+
'aria-disabled': boolean;
|
|
164
|
+
'aria-current': "date" | undefined;
|
|
165
|
+
'aria-label': string;
|
|
166
|
+
title: string | undefined;
|
|
167
|
+
tabindex: number;
|
|
168
|
+
disabled: boolean;
|
|
169
|
+
onclick: (e: MouseEvent) => void;
|
|
170
|
+
onpointerenter: () => Date | null;
|
|
171
|
+
onpointerleave: () => Date | null;
|
|
172
|
+
};
|
|
173
|
+
/** A month cell in year mode. */
|
|
174
|
+
monthCellProps(monthIndex: number): {
|
|
175
|
+
type: "button";
|
|
176
|
+
disabled: boolean;
|
|
177
|
+
onclick: () => void;
|
|
178
|
+
};
|
|
179
|
+
/** A year cell in decade mode. */
|
|
180
|
+
yearCellProps(year: number): {
|
|
181
|
+
type: "button";
|
|
182
|
+
disabled: boolean;
|
|
183
|
+
onclick: () => void;
|
|
184
|
+
};
|
|
185
|
+
/** A preset shortcut button. */
|
|
186
|
+
presetProps(preset: CalendarPreset): {
|
|
187
|
+
type: "button";
|
|
188
|
+
disabled: boolean;
|
|
189
|
+
onclick: () => void;
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
export type Calendar = ReturnType<typeof createCalendar>;
|