@svgrid/grid 3.0.4 → 3.0.6
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 -11
- package/dist/GridMenus.svelte +34 -4
- package/dist/SvGrid.controller.svelte.d.ts +33 -5
- package/dist/SvGrid.controller.svelte.js +397 -58
- package/dist/SvGrid.css +200 -2
- package/dist/SvGrid.svelte +350 -40
- package/dist/SvGrid.types.d.ts +433 -7
- package/dist/SvGridDropdown.svelte +20 -0
- package/dist/SvGridDropdown.svelte.d.ts +12 -0
- package/dist/SvModal.svelte +22 -0
- package/dist/SvModal.svelte.d.ts +7 -0
- package/dist/a11y/dismissable.d.ts +10 -0
- package/dist/a11y/dismissable.js +24 -2
- package/dist/build-api.js +92 -37
- package/dist/cdn/{GridMenus-BL7ZgQvU.js → GridMenus-C-NtjlrJ.js} +155 -146
- package/dist/cdn/GridMenus-TssHej3q.js +644 -0
- package/dist/cdn/{SvChartMenu-FBSMINA6.js → SvChartMenu-BFSTpvB-.js} +1 -1
- package/dist/cdn/{SvChartMenu-Bl6PBbkT.js → SvChartMenu-BZ1Iwv0y.js} +1 -1
- package/dist/cdn/{SvDateTimePicker-DQwt4UAs.js → SvDateTimePicker-D9u_cOf8.js} +1 -1
- package/dist/cdn/{SvDateTimePicker-vNU6bZ-q.js → SvDateTimePicker-s_6IUpI7.js} +1 -1
- package/dist/cdn/{SvGridCellEditor-B1p-vCK5.js → SvGridCellEditor-BlyCSp0q.js} +1 -1
- package/dist/cdn/{SvGridCellEditor-D_0q4xAu.js → SvGridCellEditor-ClRRA9lW.js} +1 -1
- package/dist/cdn/{SvGridChart-DzLkSwCH.js → SvGridChart-B4EV8U6t.js} +4 -4
- package/dist/cdn/{SvGridChart-C3EWAZaM.js → SvGridChart-DsmwTyZF.js} +4 -4
- package/dist/cdn/{SvGridChartBuilder-CfII62sZ.js → SvGridChartBuilder-cHloHobN.js} +4 -4
- package/dist/cdn/{SvGridChartBuilder-BE2T1ykB.js → SvGridChartBuilder-vOl7C0Za.js} +4 -4
- package/dist/cdn/{SvGridChartPanel-xf4sWVTo.js → SvGridChartPanel-AcqF-Ll5.js} +5 -5
- package/dist/cdn/{SvGridChartPanel-CCX5_Wgd.js → SvGridChartPanel-biMtSBPA.js} +5 -5
- package/dist/cdn/{SvGridChartView-DYwabQWj.js → SvGridChartView-Dx_GmZuL.js} +2 -2
- package/dist/cdn/{SvGridChartView-CfuXmY5I.js → SvGridChartView-I3rDHXAq.js} +2 -2
- package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-BWeM3lMe.js} +46 -46
- package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CJ6QqTxu.js} +67 -67
- package/dist/cdn/{SvModal-CIZWCcad.js → SvModal-ClxGmpAc.js} +187 -186
- package/dist/cdn/{SvModal-BAE-pjZX.js → SvModal-DhB_VMFR.js} +148 -147
- package/dist/cdn/{cell-formatting-C2Hf5gqd.js → cell-formatting-DVVKOSI9.js} +1 -1
- package/dist/cdn/{chart-Dz7SqMXH.js → chart-DEZxwC0i.js} +1 -1
- package/dist/cdn/{chart-panel-messages-CUbf2R4i.js → chart-panel-messages-D12XcTZJ.js} +1 -1
- package/dist/cdn/{chart-panel-messages-CmNrMdsr.js → chart-panel-messages-DguS7gC5.js} +1 -1
- package/dist/cdn/{chart-summary-BJW_tg_X.js → chart-summary-CMAXBGY-.js} +1 -1
- package/dist/cdn/{chart-trend-CaN9mDEV.js → chart-trend-BkEp61Gj.js} +1 -1
- package/dist/cdn/{dismissable-DAHetSNk.js → dismissable-Brc4EZU1.js} +5 -1
- package/dist/cdn/{export-format-CUDLy2yn.js → export-format-YzdwBww2.js} +1 -1
- package/dist/cdn/{row-resize-niQCp040.js → row-resize-DtOS1KG6.js} +41 -32
- package/dist/cdn/server-block-cache-DIqb3VZn.js +241 -0
- package/dist/cdn/{src-V1uu8iE9.js → src-CgoeSM8k.js} +5339 -4753
- package/dist/cdn/{src-BKhZ6eXd.js → src-DfwxB1TH.js} +9817 -9231
- package/dist/cdn/svgrid.js +28 -27
- package/dist/cdn/svgrid.svelte-external.js +28 -27
- package/dist/cdn/validate-AZoD8BoR.js +80 -0
- package/dist/cell-formatting.js +18 -1
- package/dist/cell-render.js +25 -6
- package/dist/clipboard.d.ts +2 -2
- package/dist/clipboard.js +72 -23
- package/dist/columns.js +7 -2
- package/dist/conditional-formatting.d.ts +2 -0
- package/dist/conditional-formatting.js +2 -0
- package/dist/core.d.ts +22 -6
- package/dist/core.js +401 -38
- package/dist/editing.js +34 -0
- package/dist/gantt-view.svelte.d.ts +24 -0
- package/dist/gantt-view.svelte.js +13 -0
- package/dist/grid-icons.d.ts +2 -2
- package/dist/grid-icons.js +2 -2
- package/dist/grid-messages.d.ts +10 -0
- package/dist/grid-messages.js +9 -0
- package/dist/headless.d.ts +5 -0
- package/dist/headless.js +12 -0
- package/dist/history.d.ts +21 -0
- package/dist/history.js +34 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- package/dist/keyboard-handlers.js +24 -1
- package/dist/keyboard.js +4 -0
- package/dist/row-drag-touch.d.ts +1 -1
- package/dist/row-drag.js +35 -1
- package/dist/row-model.d.ts +139 -0
- package/dist/row-model.js +16 -0
- package/dist/row-resize.js +22 -1
- package/dist/selection.d.ts +2 -1
- package/dist/selection.js +31 -3
- package/dist/server-block-cache.d.ts +219 -0
- package/dist/server-block-cache.js +539 -0
- package/dist/server-data-source.d.ts +274 -8
- package/dist/server-data-source.js +229 -20
- package/dist/server.d.ts +13 -0
- package/dist/server.js +13 -0
- package/dist/sparkline.js +7 -5
- package/dist/svgrid-wrapper.types.d.ts +33 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +29 -3
- package/package.json +11 -1
- package/src/GridMenus.svelte +34 -4
- package/src/SvGrid.controller.svelte.ts +397 -61
- package/src/SvGrid.css +200 -2
- package/src/SvGrid.svelte +350 -40
- package/src/SvGrid.types.ts +453 -7
- package/src/SvGridDropdown.svelte +20 -0
- package/src/SvModal.svelte +22 -0
- package/src/SvModal.test.ts +30 -1
- package/src/a11y/dismissable.test.ts +10 -1
- package/src/a11y/dismissable.ts +22 -2
- package/src/build-api.ts +96 -31
- package/src/cell-formatting.test.ts +17 -0
- package/src/cell-formatting.ts +18 -1
- package/src/cell-render.test.ts +24 -2
- package/src/cell-render.ts +24 -8
- package/src/clipboard.test.ts +107 -0
- package/src/clipboard.ts +62 -23
- package/src/columns.test.ts +4 -4
- package/src/columns.ts +7 -2
- package/src/conditional-formatting.test.ts +8 -0
- package/src/conditional-formatting.ts +3 -0
- package/src/core.rowmodel-cache.test.ts +51 -0
- package/src/core.tick-repair.test.ts +287 -0
- package/src/core.ts +407 -38
- package/src/editing.test.ts +52 -0
- package/src/editing.ts +33 -0
- package/src/gantt-stub.test.svelte +38 -0
- package/src/gantt-view.svelte.ts +35 -0
- package/src/grid-icons.ts +2 -2
- package/src/grid-messages.test.ts +7 -0
- package/src/grid-messages.ts +22 -0
- package/src/headless.ts +24 -0
- package/src/history.test.ts +49 -1
- package/src/history.ts +48 -2
- package/src/icon-seam.test.ts +2 -4
- package/src/index.ts +38 -10
- package/src/keyboard-handlers.coverage.test.ts +65 -0
- package/src/keyboard-handlers.ts +26 -1
- package/src/keyboard.ts +3 -0
- package/src/row-drag-touch.ts +2 -2
- package/src/row-drag.test.ts +51 -0
- package/src/row-drag.ts +35 -2
- package/src/row-model.ts +152 -0
- package/src/row-resize.ts +24 -1
- package/src/selection.test.ts +3 -0
- package/src/selection.ts +33 -3
- package/src/server-block-cache.test.ts +672 -0
- package/src/server-block-cache.ts +690 -0
- package/src/server-data-source.infinite.test.ts +405 -0
- package/src/server-data-source.test.ts +19 -0
- package/src/server-data-source.ts +496 -29
- package/src/server.ts +49 -0
- package/src/sparkline.test.ts +7 -0
- package/src/sparkline.ts +6 -4
- package/src/svgrid-wrapper.types.ts +32 -0
- package/src/svgrid.api.test.ts +21 -0
- package/src/svgrid.charting.test.ts +12 -4
- package/src/svgrid.context-menu.test.ts +12 -0
- package/src/svgrid.detail-rows.svelte.test.ts +187 -0
- package/src/svgrid.filter-menu-scroll.test.ts +9 -0
- package/src/svgrid.gantt-seam.test.ts +199 -0
- package/src/svgrid.live-update-paths.svelte.test.ts +184 -0
- package/src/svgrid.menu-scroll-close.test.ts +10 -0
- package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
- package/src/svgrid.row-model-seam.svelte.test.ts +305 -0
- package/src/svgrid.row-pinning.test.ts +15 -1
- package/src/svgrid.selection-bar-seam.test.ts +1 -1
- package/src/svgrid.sticky-groups.svelte.test.ts +145 -0
- package/src/svgrid.upsell-license.test.ts +8 -5
- package/src/test-setup.ts +12 -0
- package/src/transaction.test.ts +58 -0
- package/src/validate.test.ts +29 -0
- package/src/validate.ts +34 -3
- package/dist/SvGroupCell.svelte +0 -141
- package/dist/SvGroupCell.svelte.d.ts +0 -49
- package/dist/SvRowGroupPanel.svelte +0 -186
- package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
- package/dist/cdn/GridMenus-7kbpnnBW.js +0 -635
- package/dist/cdn/validate-_CDJzgIo.js +0 -75
- package/dist/server-group-model.d.ts +0 -98
- package/dist/server-group-model.js +0 -263
- package/src/SvGroupCell.svelte +0 -141
- package/src/SvRowGroupPanel.svelte +0 -186
- package/src/server-group-model.test.ts +0 -294
- package/src/server-group-model.ts +0 -370
package/dist/SvGrid.types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
|
+
import type { GridRowModel } from "./row-model.js";
|
|
2
3
|
import type { CellEditorType, ColumnDef, RowData, SvGridApi, TableFeatures } from "./index.js";
|
|
3
4
|
import type { ConditionalFormat } from "./conditional-formatting.js";
|
|
4
5
|
import type { GroupDisplayType } from "./group-display.js";
|
|
@@ -1074,8 +1075,256 @@ export type SchedulerConfig<TFeatures extends TableFeatures = TableFeatures, TDa
|
|
|
1074
1075
|
searchable?: boolean;
|
|
1075
1076
|
searchPlaceholder?: string;
|
|
1076
1077
|
};
|
|
1078
|
+
/**
|
|
1079
|
+
* The Gantt axis presets: which unit is a tick and which is the coarser row
|
|
1080
|
+
* grouping them. `week` (day ticks under month majors) is the default.
|
|
1081
|
+
*/
|
|
1082
|
+
export type GanttZoom = "day" | "week" | "month" | "quarter" | "year";
|
|
1083
|
+
/**
|
|
1084
|
+
* The four classic dependency kinds. `FS` (finish-to-start) is the default:
|
|
1085
|
+
* the successor may not start before the predecessor finishes.
|
|
1086
|
+
*/
|
|
1087
|
+
export type GanttDependencyType = "FS" | "SS" | "FF" | "SF";
|
|
1088
|
+
/**
|
|
1089
|
+
* A link from a predecessor task (`from`) to a successor (`to`). Both are row
|
|
1090
|
+
* ids (the grid's `getRowId`). `lag` is in DAYS - negative for a lead, so
|
|
1091
|
+
* `{ type: 'FS', lag: -1 }` lets the successor start a day before the
|
|
1092
|
+
* predecessor finishes.
|
|
1093
|
+
*/
|
|
1094
|
+
export type GanttDependency = {
|
|
1095
|
+
id: string;
|
|
1096
|
+
from: string;
|
|
1097
|
+
to: string;
|
|
1098
|
+
type?: GanttDependencyType;
|
|
1099
|
+
lag?: number;
|
|
1100
|
+
};
|
|
1101
|
+
/** Fired when a task bar is dragged to new dates. {@link GanttConfig.onTaskMove}. */
|
|
1102
|
+
export type GanttTaskMoveEvent<TData extends RowData = RowData> = {
|
|
1103
|
+
row: TData;
|
|
1104
|
+
start: Date;
|
|
1105
|
+
end: Date;
|
|
1106
|
+
/**
|
|
1107
|
+
* The moved row's descendants, shifted by the same delta - present only when
|
|
1108
|
+
* a summary (parent) bar was dragged. Cascaded successors are NOT here; they
|
|
1109
|
+
* arrive through {@link GanttConfig.onDependenciesChange}.
|
|
1110
|
+
*/
|
|
1111
|
+
subtree?: Array<{
|
|
1112
|
+
row: TData;
|
|
1113
|
+
start: Date;
|
|
1114
|
+
end: Date;
|
|
1115
|
+
}>;
|
|
1116
|
+
};
|
|
1117
|
+
/** Fired when a task bar's edge is dragged. {@link GanttConfig.onTaskResize}. */
|
|
1118
|
+
export type GanttTaskResizeEvent<TData extends RowData = RowData> = {
|
|
1119
|
+
row: TData;
|
|
1120
|
+
start: Date;
|
|
1121
|
+
end: Date;
|
|
1122
|
+
/** Which edge the user dragged. */
|
|
1123
|
+
edge: "start" | "end";
|
|
1124
|
+
};
|
|
1125
|
+
/** Fired when a bar's progress grip is dragged. {@link GanttConfig.onProgressChange}. */
|
|
1126
|
+
export type GanttProgressChangeEvent<TData extends RowData = RowData> = {
|
|
1127
|
+
row: TData;
|
|
1128
|
+
/** 0-100, in whole percent. */
|
|
1129
|
+
progress: number;
|
|
1130
|
+
};
|
|
1131
|
+
/** Fired when the Gantt's detail drawer is saved. {@link GanttConfig.onTaskCommit}. */
|
|
1132
|
+
export type GanttTaskCommitEvent<TData extends RowData = RowData> = {
|
|
1133
|
+
row: TData;
|
|
1134
|
+
values: Partial<TData>;
|
|
1135
|
+
};
|
|
1136
|
+
/**
|
|
1137
|
+
* The Gantt's built-in task drawer. Same shape as the scheduler's - a field
|
|
1138
|
+
* list, a title and a width - so one drawer config type covers both views.
|
|
1139
|
+
*/
|
|
1140
|
+
export type GanttDrawerConfig<TData extends RowData = RowData> = SchedulerDrawerConfig<TData>;
|
|
1141
|
+
/**
|
|
1142
|
+
* Turns the grid into a Gantt chart. Set `gantt` and the grid renders its rows
|
|
1143
|
+
* as a task table beside a time chart: one bar per row positioned by start /
|
|
1144
|
+
* end, nested into a work-breakdown tree by `parentField`, with dependency
|
|
1145
|
+
* arrows between linked tasks.
|
|
1146
|
+
*
|
|
1147
|
+
* Like the Kanban board and the scheduler it is a pure *view of the grid*: it
|
|
1148
|
+
* renders the grid's filtered + sorted rows and writes back only through
|
|
1149
|
+
* callbacks, never mutating your data. Dragging a bar fires
|
|
1150
|
+
* {@link GanttConfig.onTaskMove} where you reassign the dates on your own rows.
|
|
1151
|
+
*
|
|
1152
|
+
* Dates are local calendar days and `end` is EXCLUSIVE, except that a date-only
|
|
1153
|
+
* string (`'2026-09-14'`, no time part) is read as the end OF that day - the
|
|
1154
|
+
* inclusive convention planning tools use. So
|
|
1155
|
+
* `{ start: '2026-09-14', end: '2026-09-16' }` draws a three-day bar.
|
|
1156
|
+
*/
|
|
1157
|
+
export type GanttConfig<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> = {
|
|
1158
|
+
/** Field holding each task's start (`Date` | epoch-ms | ISO string). Required. */
|
|
1159
|
+
startField: keyof TData & string;
|
|
1160
|
+
/** Field holding the end. Omit to use `durationField`, else the task is a milestone. */
|
|
1161
|
+
endField?: keyof TData & string;
|
|
1162
|
+
/** Field holding the length in WORKING days, used when `endField` is absent. */
|
|
1163
|
+
durationField?: keyof TData & string;
|
|
1164
|
+
/** Field for the task name. Defaults to the first column's field. */
|
|
1165
|
+
titleField?: keyof TData & string;
|
|
1166
|
+
/** Field holding percent complete (0-100). Drives the bar's inner fill. */
|
|
1167
|
+
progressField?: keyof TData & string;
|
|
1168
|
+
/**
|
|
1169
|
+
* Field holding each row's PARENT task id, nesting the flat rows into a
|
|
1170
|
+
* work-breakdown tree. Parents render a rolled-up summary bar and a collapse
|
|
1171
|
+
* chevron. Rows whose parent is missing become roots rather than vanishing.
|
|
1172
|
+
*
|
|
1173
|
+
* This is the Gantt's own tree - do NOT also set the grid's `treeData` prop.
|
|
1174
|
+
* `treeData` hides collapsed children from the view entirely, which would
|
|
1175
|
+
* drop them out of their phase's summary bar.
|
|
1176
|
+
*/
|
|
1177
|
+
parentField?: keyof TData & string;
|
|
1178
|
+
/**
|
|
1179
|
+
* Boolean field marking a task as a milestone (a diamond, no length). A task
|
|
1180
|
+
* whose end equals its start renders as one regardless.
|
|
1181
|
+
*/
|
|
1182
|
+
milestoneField?: keyof TData & string;
|
|
1183
|
+
/** Field holding a per-task accent color (any CSS color). Else `color`. */
|
|
1184
|
+
colorField?: keyof TData & string;
|
|
1185
|
+
/** Fallback accent color for every bar. */
|
|
1186
|
+
color?: string;
|
|
1187
|
+
/**
|
|
1188
|
+
* Predecessor -> successor links, drawn as arrows between bars. `from` / `to`
|
|
1189
|
+
* are row ids (your `getRowId`). See {@link GanttDependency}.
|
|
1190
|
+
*/
|
|
1191
|
+
dependencies?: ReadonlyArray<GanttDependency>;
|
|
1192
|
+
/**
|
|
1193
|
+
* Per-row field holding that row's links (as `GanttDependency[]` or a plain
|
|
1194
|
+
* list of successor ids). An alternative to the flat `dependencies` array.
|
|
1195
|
+
*/
|
|
1196
|
+
dependencyField?: keyof TData & string;
|
|
1197
|
+
/**
|
|
1198
|
+
* Cascade successors forward on move / resize so every link stays legal,
|
|
1199
|
+
* preserving each task's duration. Defaults to `true` when any dependency is
|
|
1200
|
+
* present. Cascading never pulls a task earlier.
|
|
1201
|
+
*/
|
|
1202
|
+
autoReschedule?: boolean;
|
|
1203
|
+
/**
|
|
1204
|
+
* Schedule in working time (see `nonWorkingDays` / `holidays`): a moved
|
|
1205
|
+
* or cascaded task lands on a working day and keeps its WORKING length, so
|
|
1206
|
+
* a five-day task dragged over a weekend stays five days of work, and the
|
|
1207
|
+
* critical path measures slack in working days. `false` schedules in
|
|
1208
|
+
* calendar time. Default `true`.
|
|
1209
|
+
*/
|
|
1210
|
+
respectWorkingTime?: boolean;
|
|
1211
|
+
/** Fired with the cascaded shifts after a move / resize (never mutates rows). */
|
|
1212
|
+
onDependenciesChange?: (moves: Array<{
|
|
1213
|
+
id: string;
|
|
1214
|
+
start: Date;
|
|
1215
|
+
end: Date;
|
|
1216
|
+
}>) => void;
|
|
1217
|
+
/** Fired when the user draws a new link (drag from one bar's edge to another). */
|
|
1218
|
+
onDependencyAdd?: (dep: GanttDependency) => void;
|
|
1219
|
+
/** Fired when the user removes a link (arrow context menu). */
|
|
1220
|
+
onDependencyRemove?: (id: string) => void;
|
|
1221
|
+
/** The axis preset the chart opens on. Default `'week'`. */
|
|
1222
|
+
zoom?: GanttZoom;
|
|
1223
|
+
/**
|
|
1224
|
+
* The presets the toolbar's zoom stepper offers. Default all five; a single
|
|
1225
|
+
* entry hides the stepper.
|
|
1226
|
+
*/
|
|
1227
|
+
zoomLevels?: ReadonlyArray<GanttZoom>;
|
|
1228
|
+
/** Fired when the zoom preset changes (stepper or Ctrl+wheel). */
|
|
1229
|
+
onZoomChange?: (zoom: GanttZoom) => void;
|
|
1230
|
+
/** First day of the week, 0-6 (0 = Sunday). Default 0. */
|
|
1231
|
+
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
1232
|
+
/**
|
|
1233
|
+
* Weekday numbers (0 = Sun ... 6 = Sat) that are non-working: shaded in the
|
|
1234
|
+
* chart and skipped by duration + cascade arithmetic. Default `[0, 6]`.
|
|
1235
|
+
*/
|
|
1236
|
+
nonWorkingDays?: ReadonlyArray<number>;
|
|
1237
|
+
/** Specific dates that are non-working (holidays, closures). */
|
|
1238
|
+
holidays?: ReadonlyArray<Date | number | string>;
|
|
1239
|
+
/** Shade the non-working columns. Default `true`. */
|
|
1240
|
+
showNonWorking?: boolean;
|
|
1241
|
+
/** Draw the dashed "today" line across the chart. Default `true`. */
|
|
1242
|
+
todayLine?: boolean;
|
|
1243
|
+
/** Earliest date the axis shows and a drag may reach. */
|
|
1244
|
+
minDate?: Date | number | string;
|
|
1245
|
+
/** Latest date the axis shows and a drag may reach. */
|
|
1246
|
+
maxDate?: Date | number | string;
|
|
1247
|
+
/** Calendar days of slack around the first start / last end. Default 7. */
|
|
1248
|
+
rangePaddingDays?: number;
|
|
1249
|
+
/**
|
|
1250
|
+
* Column ids shown in the task table, in order. Defaults to every leaf
|
|
1251
|
+
* column. Two built-ins need no column definition: `'__duration'` (working
|
|
1252
|
+
* days) and `'__progress'` (a small bar).
|
|
1253
|
+
*/
|
|
1254
|
+
tableColumns?: ReadonlyArray<string>;
|
|
1255
|
+
/** Width (px) of the task table pane. Default 360; a splitter resizes it. */
|
|
1256
|
+
tableWidth?: number;
|
|
1257
|
+
/** Height (px) of one task row. Default 32. */
|
|
1258
|
+
rowHeight?: number;
|
|
1259
|
+
/** Parents draw a rolled-up summary bar spanning their children. Default `true`. */
|
|
1260
|
+
summaryBars?: boolean;
|
|
1261
|
+
/**
|
|
1262
|
+
* Where a bar's label sits: `'inside'` (default, falling back to the right
|
|
1263
|
+
* when the bar is too narrow), always `'right'`, or `'none'`.
|
|
1264
|
+
*/
|
|
1265
|
+
labelPosition?: "inside" | "right" | "none";
|
|
1266
|
+
/**
|
|
1267
|
+
* Controlled collapse: the ids of the parent rows whose children are hidden.
|
|
1268
|
+
* Omit to let the Gantt own its own collapse state.
|
|
1269
|
+
*/
|
|
1270
|
+
collapsed?: ReadonlyArray<string>;
|
|
1271
|
+
/** Fired when a chevron (or Expand / Collapse all) changes the collapsed set. */
|
|
1272
|
+
onCollapseChange?: (collapsed: string[]) => void;
|
|
1273
|
+
/**
|
|
1274
|
+
* Enable drag-to-move, edge resize, the progress grip and link drawing.
|
|
1275
|
+
* Without it the chart is read-only.
|
|
1276
|
+
*/
|
|
1277
|
+
editable?: boolean;
|
|
1278
|
+
/**
|
|
1279
|
+
* Enable undo / redo of move, resize and progress edits with `Ctrl/Cmd+Z` and
|
|
1280
|
+
* `Ctrl/Cmd+Shift+Z` (or `Ctrl+Y`). The callbacks re-fire with the reversed
|
|
1281
|
+
* values, so your data follows.
|
|
1282
|
+
*/
|
|
1283
|
+
history?: boolean;
|
|
1284
|
+
/** Fired when a bar is dragged to new dates. */
|
|
1285
|
+
onTaskMove?: (event: GanttTaskMoveEvent<TData>) => void;
|
|
1286
|
+
/** Fired when a bar's edge is dragged. */
|
|
1287
|
+
onTaskResize?: (event: GanttTaskResizeEvent<TData>) => void;
|
|
1288
|
+
/** Fired when the progress grip is dragged. */
|
|
1289
|
+
onProgressChange?: (event: GanttProgressChangeEvent<TData>) => void;
|
|
1290
|
+
/** Fired when empty chart space is double-clicked - create a task there. */
|
|
1291
|
+
onTaskAdd?: (start: Date, end: Date, parentId?: string) => void;
|
|
1292
|
+
/**
|
|
1293
|
+
* Fired from the bar's Delete action. Setting this shows Delete in the
|
|
1294
|
+
* drawer and the context menu. Remove the row from your data in the handler.
|
|
1295
|
+
*/
|
|
1296
|
+
onTaskDelete?: (row: TData) => void;
|
|
1297
|
+
/**
|
|
1298
|
+
* Custom body for a TASK bar. Receives the row. Omit for the built-in label.
|
|
1299
|
+
* A phase's summary bar is a thin spine with no room for a body, so it keeps
|
|
1300
|
+
* its plain label; a milestone has no body at all.
|
|
1301
|
+
*/
|
|
1302
|
+
task?: Snippet<[TData]>;
|
|
1303
|
+
/**
|
|
1304
|
+
* Hover tooltip for a bar. A `Snippet<[TData]>` for custom content, or `true`
|
|
1305
|
+
* for the built-in one (title, dates, duration, percent). Omit to disable.
|
|
1306
|
+
*/
|
|
1307
|
+
tooltip?: boolean | Snippet<[TData]>;
|
|
1308
|
+
/** Delay (ms) before the hover tooltip opens. Default 400. */
|
|
1309
|
+
tooltipDelay?: number;
|
|
1310
|
+
/** Built-in task drawer: `true` for all fields, or a config object. */
|
|
1311
|
+
drawer?: boolean | GanttDrawerConfig<TData>;
|
|
1312
|
+
/** Fired when the drawer is saved. */
|
|
1313
|
+
onTaskCommit?: (event: GanttTaskCommitEvent<TData>) => void;
|
|
1314
|
+
/** Right-click menu for a bar. Return items or `undefined` to suppress. */
|
|
1315
|
+
taskMenu?: (row: TData) => MenuItem[] | undefined;
|
|
1316
|
+
/** Show the search box (binds to the grid's global filter). Default `true`. */
|
|
1317
|
+
searchable?: boolean;
|
|
1318
|
+
searchPlaceholder?: string;
|
|
1319
|
+
};
|
|
1077
1320
|
export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends RowData = RowData> = {
|
|
1078
|
-
|
|
1321
|
+
/**
|
|
1322
|
+
* The rows to render.
|
|
1323
|
+
*
|
|
1324
|
+
* Optional only because `rowModel` can supply them instead; a grid with
|
|
1325
|
+
* neither renders empty. When both are present `data` wins.
|
|
1326
|
+
*/
|
|
1327
|
+
data?: ReadonlyArray<TData>;
|
|
1079
1328
|
columns: Array<ColumnDef<TFeatures, TData>>;
|
|
1080
1329
|
/**
|
|
1081
1330
|
* Kanban board mode. When set, the grid renders its rows as cards in
|
|
@@ -1089,6 +1338,15 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
1089
1338
|
* {@link SchedulerConfig}.
|
|
1090
1339
|
*/
|
|
1091
1340
|
scheduler?: SchedulerConfig<TFeatures, TData>;
|
|
1341
|
+
/**
|
|
1342
|
+
* Gantt mode. When set, the grid renders its rows as a task table beside a
|
|
1343
|
+
* time chart: one bar per row by start / end, a work-breakdown tree from
|
|
1344
|
+
* `parentField`, and dependency arrows. See {@link GanttConfig}.
|
|
1345
|
+
*
|
|
1346
|
+
* A view of the grid like the board and scheduler; the renderer ships in
|
|
1347
|
+
* `@svgrid/enterprise` (call `enableGanttView()`).
|
|
1348
|
+
*/
|
|
1349
|
+
gantt?: GanttConfig<TFeatures, TData>;
|
|
1092
1350
|
/**
|
|
1093
1351
|
* Chart view. When set, the grid renders its FILTERED + SORTED rows as a chart
|
|
1094
1352
|
* instead of a table (search / filters / sort flow through). Unlike board and
|
|
@@ -1694,6 +1952,15 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
1694
1952
|
rowIndex: number;
|
|
1695
1953
|
columnId: string;
|
|
1696
1954
|
}) => unknown;
|
|
1955
|
+
/**
|
|
1956
|
+
* Whether a collapsed row still takes part in a copy or a fill that
|
|
1957
|
+
* spans it. Left out, both skip every collapsed row, which is what
|
|
1958
|
+
* "filter, copy, paste" needs and what a fill dragged over a filtered
|
|
1959
|
+
* list expects: the series runs over the rows that show. A spreadsheet
|
|
1960
|
+
* answers per row: a row hidden by hand is copied and filled, as Excel
|
|
1961
|
+
* does, while a row a filter folded away is not.
|
|
1962
|
+
*/
|
|
1963
|
+
includeCollapsedRows?: (rowIndex: number) => boolean;
|
|
1697
1964
|
/**
|
|
1698
1965
|
* An HTML rendering of what Ctrl+C copies, written to the clipboard as
|
|
1699
1966
|
* `text/html` beside the TSV. Excel and Google Sheets read the HTML
|
|
@@ -1857,10 +2124,11 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
1857
2124
|
*/
|
|
1858
2125
|
onRowSelectionChange?: (selection: Record<string, boolean>, rows: TData[]) => void;
|
|
1859
2126
|
/**
|
|
1860
|
-
* Fires whenever the cell
|
|
1861
|
-
*
|
|
1862
|
-
* `
|
|
1863
|
-
*
|
|
2127
|
+
* Fires whenever the cell selection changes (mouse, keyboard, or
|
|
2128
|
+
* `api.selectCells()`). `ranges` is every selected rectangle, matching
|
|
2129
|
+
* `api.getSelected()`: the ones a Ctrl+click committed and the active one
|
|
2130
|
+
* last, each `[rowStart, colStart, rowEnd, colEnd]` in grid coords. Empty
|
|
2131
|
+
* array when the user clears the selection.
|
|
1864
2132
|
*/
|
|
1865
2133
|
onCellSelectionChange?: (ranges: Array<[number, number, number, number]>) => void;
|
|
1866
2134
|
/**
|
|
@@ -2078,6 +2346,99 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
2078
2346
|
scrollHeight: number;
|
|
2079
2347
|
clientHeight: number;
|
|
2080
2348
|
}) => void;
|
|
2349
|
+
/**
|
|
2350
|
+
* Fires when the range of rows on screen changes, with the first and last
|
|
2351
|
+
* row INDEX (not pixels). Coalesced to one call per frame, so it is cheap
|
|
2352
|
+
* to wire to something that fetches.
|
|
2353
|
+
*
|
|
2354
|
+
* This is the hook a block-loading data source needs and
|
|
2355
|
+
* `onScrollBottomReached` cannot give it: "the user is looking at rows
|
|
2356
|
+
* 4,000-4,020" answers which block to fetch and which to keep, while
|
|
2357
|
+
* "they hit the bottom" only ever means "append more". Both are free; use
|
|
2358
|
+
* this one with `createServerDataSource({ mode: 'infinite' })`, or let
|
|
2359
|
+
* `rowModel` wire it for you.
|
|
2360
|
+
*
|
|
2361
|
+
* Reports `0, data.length - 1` when virtualization is off, since every row
|
|
2362
|
+
* really is rendered.
|
|
2363
|
+
*/
|
|
2364
|
+
onVisibleRangeChange?: (range: {
|
|
2365
|
+
startIndex: number;
|
|
2366
|
+
endIndex: number;
|
|
2367
|
+
}) => void;
|
|
2368
|
+
/**
|
|
2369
|
+
* Marks a row as one whose data has not arrived: `"loading"` draws a
|
|
2370
|
+
* shimmer in every cell, `"failed"` draws a full-width "could not load"
|
|
2371
|
+
* row with a Retry button, and `null` (the default for every row) renders
|
|
2372
|
+
* normally.
|
|
2373
|
+
*
|
|
2374
|
+
* Placeholder rows are inert - not selectable, not editable, and skipped
|
|
2375
|
+
* by cell navigation - because there is nothing there to act on yet.
|
|
2376
|
+
*
|
|
2377
|
+
* `createServerDataSource` in `infinite` mode fills the gaps with rows this
|
|
2378
|
+
* recognises, so the usual wiring is `rowPlaceholder={rowPlaceholderState}`
|
|
2379
|
+
* (or nothing at all, via `rowModel`).
|
|
2380
|
+
*/
|
|
2381
|
+
rowPlaceholder?: (row: TData, rowIndex: number) => "loading" | "failed" | null;
|
|
2382
|
+
/** Called by the Retry button on a `"failed"` placeholder row. */
|
|
2383
|
+
onRetryRow?: (row: TData, rowIndex: number) => void;
|
|
2384
|
+
/**
|
|
2385
|
+
* Hand selection over to an external model.
|
|
2386
|
+
*
|
|
2387
|
+
* The grid normally tracks selection as a record of the row ids it has
|
|
2388
|
+
* seen, which is right until the rows it has seen are a window onto a
|
|
2389
|
+
* million on a server: "select all" then means 20 ticked checkboxes rather
|
|
2390
|
+
* than a million, and the header checkbox cannot honestly say `all`. A
|
|
2391
|
+
* model that stores the RULE ("everything except these three") can answer
|
|
2392
|
+
* both, so when this is set the header checkbox, the row checkboxes and
|
|
2393
|
+
* `api.selectAllRows()` all route through it instead.
|
|
2394
|
+
*
|
|
2395
|
+
* `@svgrid/enterprise` ships one for the server-side row model; this is the
|
|
2396
|
+
* seam it plugs into.
|
|
2397
|
+
*/
|
|
2398
|
+
/**
|
|
2399
|
+
* Drive the grid from a row model instead of wiring a dozen props.
|
|
2400
|
+
*
|
|
2401
|
+
* `createServerDataSource` returns one, and so does the Enterprise
|
|
2402
|
+
* server-side row model, so server-backed grids become:
|
|
2403
|
+
*
|
|
2404
|
+
* ```svelte
|
|
2405
|
+
* <SvGrid rowModel={ctl} {columns} />
|
|
2406
|
+
* ```
|
|
2407
|
+
*
|
|
2408
|
+
* The model supplies `data`, `loading`, `getRowId`, the external sort
|
|
2409
|
+
* and filter wiring, the visible range, placeholder rows, group
|
|
2410
|
+
* accessors, selection and paging - each one only if it implements that
|
|
2411
|
+
* part. A prop written explicitly on the grid always wins, so you can
|
|
2412
|
+
* adopt it and still override one piece.
|
|
2413
|
+
*/
|
|
2414
|
+
rowModel?: GridRowModel<TData>;
|
|
2415
|
+
/**
|
|
2416
|
+
* Columns that REPLACE `columns` while set. The server-side row model
|
|
2417
|
+
* supplies them in pivot mode - one column per pivoted value, grouped
|
|
2418
|
+
* under a header per pivot key - and clears them when pivot mode ends,
|
|
2419
|
+
* so `columns` stays the app's own list. Rarely set by hand.
|
|
2420
|
+
*/
|
|
2421
|
+
pivotResultColumns?: Array<ColumnDef<TFeatures, TData>> | null;
|
|
2422
|
+
rowSelectionModel?: {
|
|
2423
|
+
isSelected: (rowId: string, row: TData) => boolean;
|
|
2424
|
+
/** Whether the header checkbox shows empty, indeterminate, or ticked. */
|
|
2425
|
+
headerState: () => "none" | "some" | "all";
|
|
2426
|
+
toggle: (rowId: string, row: TData, next: boolean) => void;
|
|
2427
|
+
/** The header checkbox: select or clear everything, loaded or not. */
|
|
2428
|
+
toggleAll: (next: boolean) => void;
|
|
2429
|
+
/**
|
|
2430
|
+
* How many rows the rule selects, counting the ones the grid never
|
|
2431
|
+
* loaded; `null` when it cannot say. The selection bar shows this
|
|
2432
|
+
* instead of counting ticked rows on screen.
|
|
2433
|
+
*/
|
|
2434
|
+
selectedCount?: () => number | null;
|
|
2435
|
+
/**
|
|
2436
|
+
* Apply one patch to every selected row, loaded or not. When present,
|
|
2437
|
+
* the bulk-edit drawer sends its edits here instead of writing the
|
|
2438
|
+
* loaded cells. Resolves with how many rows changed.
|
|
2439
|
+
*/
|
|
2440
|
+
bulkUpdate?: (patch: Record<string, unknown>) => Promise<number>;
|
|
2441
|
+
};
|
|
2081
2442
|
/**
|
|
2082
2443
|
* Marks a row as an expandable "detail row". When this returns true the
|
|
2083
2444
|
* grid renders that row as a SINGLE full-width cell (colspan across every
|
|
@@ -2097,12 +2458,43 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
2097
2458
|
row: TData;
|
|
2098
2459
|
rowIndex: number;
|
|
2099
2460
|
}]>;
|
|
2461
|
+
/**
|
|
2462
|
+
* The height of a detail row, in px, or a function of its data. With it
|
|
2463
|
+
* the virtualizer can size detail rows, so master-detail works with
|
|
2464
|
+
* `virtualization` on (the panel scrolls inside its cell when taller).
|
|
2465
|
+
* Without it a detail row is auto height, which needs
|
|
2466
|
+
* `virtualization={false}`.
|
|
2467
|
+
*/
|
|
2468
|
+
detailRowHeight?: number | ((row: TData) => number);
|
|
2469
|
+
/**
|
|
2470
|
+
* A row-header column of chevrons that open and close detail rows. It
|
|
2471
|
+
* sits with the row-number and selection columns: sticky at the left,
|
|
2472
|
+
* no column menu, not resizable, not reorderable, outside the active
|
|
2473
|
+
* cell and the selection. The chevron calls `onDetailToggle` (or, on a
|
|
2474
|
+
* server row model, the model's own toggle) and reads `isDetailOpen`
|
|
2475
|
+
* for its direction; `hasDetail` hides it on rows that have nothing to
|
|
2476
|
+
* open. Detail rows themselves get an empty cell.
|
|
2477
|
+
*/
|
|
2478
|
+
showDetailToggle?: boolean;
|
|
2479
|
+
/**
|
|
2480
|
+
* Open or close the detail under a row. The chevron of `showDetailToggle`
|
|
2481
|
+
* and Ctrl+Enter on a row call it; you keep the open set and insert or
|
|
2482
|
+
* remove the detail row in `data`. A server row model supplies its own
|
|
2483
|
+
* (the `rowModel` prop wires `toggleDetail`), so this is the client side.
|
|
2484
|
+
*/
|
|
2485
|
+
onDetailToggle?: (row: TData, rowIndex: number) => void;
|
|
2486
|
+
/** Whether the detail under a row is open: the chevron's direction and `aria-expanded`. */
|
|
2487
|
+
isDetailOpen?: (row: TData) => boolean;
|
|
2488
|
+
/** Whether a row has a detail to open; the chevron is left out where this returns false. */
|
|
2489
|
+
hasDetail?: (row: TData) => boolean;
|
|
2100
2490
|
/**
|
|
2101
2491
|
* Server-side group / tree keyboard + accessibility, built into the grid. When
|
|
2102
2492
|
* set, the grid uses the treegrid role and marks matching rows with
|
|
2103
2493
|
* `aria-level` / `aria-expanded`, and ArrowRight / ArrowLeft expand / collapse
|
|
2104
|
-
* the focused group row (no app-level key handling). Pair with
|
|
2105
|
-
* + `SvGroupCell` for the visual
|
|
2494
|
+
* the focused group row (no app-level key handling). Pair with
|
|
2495
|
+
* `serverGroupRows` + `SvGroupCell` from `@svgrid/enterprise` for the visual
|
|
2496
|
+
* expander, or drive it from your own tree state. Every accessor receives the
|
|
2497
|
+
* row data.
|
|
2106
2498
|
*/
|
|
2107
2499
|
serverGroup?: {
|
|
2108
2500
|
/** Whether a row is an expandable group / branch. */
|
|
@@ -2113,6 +2505,12 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
2113
2505
|
expanded?: (row: TData) => boolean;
|
|
2114
2506
|
/** Expand / collapse a group row. Called on ArrowRight / ArrowLeft. */
|
|
2115
2507
|
onToggle: (row: TData) => void;
|
|
2508
|
+
/** Open / close the detail panel under a leaf. Called on Ctrl+Enter when `renderDetailRow` is set, and by the `showDetailToggle` chevron. */
|
|
2509
|
+
toggleDetail?: (row: TData) => void;
|
|
2510
|
+
/** Whether the detail under a leaf is open (the chevron's direction). */
|
|
2511
|
+
detailOpen?: (row: TData) => boolean;
|
|
2512
|
+
/** Whether a row can open a detail at all; a group, a placeholder or a detail row cannot. */
|
|
2513
|
+
hasDetail?: (row: TData) => boolean;
|
|
2116
2514
|
};
|
|
2117
2515
|
/**
|
|
2118
2516
|
* Server-side set-filter values. When set, a column's filter checklist is
|
|
@@ -2140,6 +2538,17 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
2140
2538
|
* skips them.
|
|
2141
2539
|
*/
|
|
2142
2540
|
frozenRows?: number;
|
|
2541
|
+
/**
|
|
2542
|
+
* Keep the group a row belongs to in view: while the rows of an open
|
|
2543
|
+
* group scroll past, the group's row (and its parents' rows) stay under
|
|
2544
|
+
* the header, the way a section heading stays put in a long list, so a
|
|
2545
|
+
* screen deep inside a 60,000-row group still says which group it is.
|
|
2546
|
+
* Works for server-side groups (`rowModel` / `serverGroup`), client
|
|
2547
|
+
* grouping and tree data. Under `virtualization` the band shows a copy
|
|
2548
|
+
* of each ancestor row; without it the rows themselves stick. Off by
|
|
2549
|
+
* default.
|
|
2550
|
+
*/
|
|
2551
|
+
stickyGroupRows?: boolean;
|
|
2143
2552
|
/**
|
|
2144
2553
|
* Merged cells: rectangles drawn as one cell, a spreadsheet's Merge &
|
|
2145
2554
|
* Center. Each entry is the top-left cell (display indices) and how many
|
|
@@ -2221,6 +2630,23 @@ export type Props<TFeatures extends TableFeatures = TableFeatures, TData extends
|
|
|
2221
2630
|
fromGridId: number;
|
|
2222
2631
|
toGridId: number;
|
|
2223
2632
|
}) => void;
|
|
2633
|
+
/**
|
|
2634
|
+
* Take the drop yourself. With this set the grid keeps the drag
|
|
2635
|
+
* affordance and the drop indicator but does not touch its data: the
|
|
2636
|
+
* handler gets the dragged row, the row it landed on (null for the
|
|
2637
|
+
* empty space below the rows) and the side - `before` / `after`, or
|
|
2638
|
+
* `into` when it landed on the middle of a group or tree row, which
|
|
2639
|
+
* makes it that row's child. The path for a `rowModel`, whose rows the
|
|
2640
|
+
* grid does not own: hand the move to the model (`moveRow`) or to your
|
|
2641
|
+
* server. Only fires within one grid; a drop from another grid stays
|
|
2642
|
+
* managed.
|
|
2643
|
+
*/
|
|
2644
|
+
onRowDrop?: (event: {
|
|
2645
|
+
row: TData;
|
|
2646
|
+
target: TData | null;
|
|
2647
|
+
targetIndex: number | null;
|
|
2648
|
+
side: "before" | "after" | "into";
|
|
2649
|
+
}) => void;
|
|
2224
2650
|
/**
|
|
2225
2651
|
* Align this grid with others that share the same non-empty
|
|
2226
2652
|
* `alignedGridGroup` string: horizontal scroll and column-resize widths are
|
|
@@ -45,6 +45,18 @@
|
|
|
45
45
|
* loading line instead of "No options", which would read as "nothing to
|
|
46
46
|
* pick" when the truth is "not here yet". */
|
|
47
47
|
loading?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* The trigger's element id, so a form's `<label for>` reaches it and
|
|
50
|
+
* clicking the label focuses it. Without one a select in a form was a
|
|
51
|
+
* button with no name.
|
|
52
|
+
*/
|
|
53
|
+
id?: string
|
|
54
|
+
/** Accessible name for the trigger when no label points at `id`. */
|
|
55
|
+
ariaLabel?: string
|
|
56
|
+
/** Marks the trigger `aria-invalid`, the way an input in the same form is. */
|
|
57
|
+
invalid?: boolean
|
|
58
|
+
/** `aria-describedby` for the trigger: the error or help text of the field. */
|
|
59
|
+
describedBy?: string
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
let {
|
|
@@ -59,6 +71,10 @@
|
|
|
59
71
|
onCommit,
|
|
60
72
|
onCancel,
|
|
61
73
|
loading = false,
|
|
74
|
+
id,
|
|
75
|
+
ariaLabel,
|
|
76
|
+
invalid = false,
|
|
77
|
+
describedBy,
|
|
62
78
|
}: Props = $props()
|
|
63
79
|
|
|
64
80
|
/** Stable per-instance id used to build option ids for
|
|
@@ -348,10 +364,14 @@
|
|
|
348
364
|
<!-- svelte-ignore a11y_role_supports_aria_props_implicit -->
|
|
349
365
|
<button
|
|
350
366
|
type="button"
|
|
367
|
+
{id}
|
|
351
368
|
class="sv-grid-dropdown-trigger"
|
|
352
369
|
class:sv-grid-dropdown-trigger-chips={renderChipsInTrigger && selectedArr.length > 0}
|
|
353
370
|
aria-haspopup="listbox"
|
|
354
371
|
aria-expanded={open}
|
|
372
|
+
aria-label={ariaLabel}
|
|
373
|
+
aria-invalid={invalid || undefined}
|
|
374
|
+
aria-describedby={describedBy}
|
|
355
375
|
aria-activedescendant={open ? optionId(highlighted) : undefined}
|
|
356
376
|
bind:this={triggerEl}
|
|
357
377
|
use:focusTrigger
|
|
@@ -42,6 +42,18 @@ type Props = {
|
|
|
42
42
|
* loading line instead of "No options", which would read as "nothing to
|
|
43
43
|
* pick" when the truth is "not here yet". */
|
|
44
44
|
loading?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The trigger's element id, so a form's `<label for>` reaches it and
|
|
47
|
+
* clicking the label focuses it. Without one a select in a form was a
|
|
48
|
+
* button with no name.
|
|
49
|
+
*/
|
|
50
|
+
id?: string;
|
|
51
|
+
/** Accessible name for the trigger when no label points at `id`. */
|
|
52
|
+
ariaLabel?: string;
|
|
53
|
+
/** Marks the trigger `aria-invalid`, the way an input in the same form is. */
|
|
54
|
+
invalid?: boolean;
|
|
55
|
+
/** `aria-describedby` for the trigger: the error or help text of the field. */
|
|
56
|
+
describedBy?: string;
|
|
45
57
|
};
|
|
46
58
|
declare const SvGridDropdown: import("svelte").Component<Props, {}, "">;
|
|
47
59
|
type SvGridDropdown = ReturnType<typeof SvGridDropdown>;
|
package/dist/SvModal.svelte
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { portalToBody } from './popover'
|
|
17
17
|
import { nextEditorId } from './editor-contract'
|
|
18
18
|
import { createOverlay } from './createOverlay.svelte'
|
|
19
|
+
import { getFocusable } from './a11y/focus-trap'
|
|
19
20
|
|
|
20
21
|
type Props = {
|
|
21
22
|
open?: boolean
|
|
@@ -33,6 +34,13 @@
|
|
|
33
34
|
closeOnEsc?: boolean
|
|
34
35
|
/** Hide the header close (x) button. */
|
|
35
36
|
hideClose?: boolean
|
|
37
|
+
/**
|
|
38
|
+
* The element to focus when the dialog opens. Defaults to the first
|
|
39
|
+
* focusable control in the body or footer - never the header Close (x),
|
|
40
|
+
* so opening a dialog lands on its content and Enter does not dismiss it.
|
|
41
|
+
* Pass a getter to target a specific field (e.g. a search input).
|
|
42
|
+
*/
|
|
43
|
+
initialFocus?: () => HTMLElement | null
|
|
36
44
|
children?: Snippet
|
|
37
45
|
footer?: Snippet
|
|
38
46
|
}
|
|
@@ -48,6 +56,7 @@
|
|
|
48
56
|
closeOnBackdrop = true,
|
|
49
57
|
closeOnEsc = true,
|
|
50
58
|
hideClose = false,
|
|
59
|
+
initialFocus,
|
|
51
60
|
children,
|
|
52
61
|
footer,
|
|
53
62
|
}: Props = $props()
|
|
@@ -69,6 +78,19 @@
|
|
|
69
78
|
closeOnEsc: () => closeOnEsc,
|
|
70
79
|
closeOnBackdrop: () => closeOnBackdrop,
|
|
71
80
|
onOpen: () => { drag = { x: 0, y: 0 }; box = null },
|
|
81
|
+
// Land focus on the dialog's content, not the header Close (x). The x is
|
|
82
|
+
// the first focusable in DOM order, so the trap's "first focusable"
|
|
83
|
+
// default sent focus there - where Enter immediately dismissed the
|
|
84
|
+
// dialog and the loud focus ring pointed at "close" over the primary
|
|
85
|
+
// action. Prefer the first focusable outside the header; fall back to the
|
|
86
|
+
// panel itself when the body has no control of its own.
|
|
87
|
+
initialFocus: () => {
|
|
88
|
+
const explicit = initialFocus?.()
|
|
89
|
+
if (explicit) return explicit
|
|
90
|
+
if (!dialogEl) return null
|
|
91
|
+
const first = getFocusable(dialogEl).find((el) => !el.closest('.sv-modal__header'))
|
|
92
|
+
return first ?? dialogEl
|
|
93
|
+
},
|
|
72
94
|
})
|
|
73
95
|
|
|
74
96
|
// --- Drag (header) ---------------------------------------------------------
|
package/dist/SvModal.svelte.d.ts
CHANGED
|
@@ -28,6 +28,13 @@ type Props = {
|
|
|
28
28
|
closeOnEsc?: boolean;
|
|
29
29
|
/** Hide the header close (x) button. */
|
|
30
30
|
hideClose?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* The element to focus when the dialog opens. Defaults to the first
|
|
33
|
+
* focusable control in the body or footer - never the header Close (x),
|
|
34
|
+
* so opening a dialog lands on its content and Enter does not dismiss it.
|
|
35
|
+
* Pass a getter to target a specific field (e.g. a search input).
|
|
36
|
+
*/
|
|
37
|
+
initialFocus?: () => HTMLElement | null;
|
|
31
38
|
children?: Snippet;
|
|
32
39
|
footer?: Snippet;
|
|
33
40
|
};
|
|
@@ -37,6 +37,16 @@ export declare function dismissableDepth(): number;
|
|
|
37
37
|
* window listener gets wrong: inner scroll containers don't bubble, so the
|
|
38
38
|
* capture listener sees them and dismisses the panel the user is scrolling.
|
|
39
39
|
*
|
|
40
|
+
* The listener arms one animation frame after it is asked for, not at once.
|
|
41
|
+
* Scroll events are queued and dispatched in the next rendering step, so a
|
|
42
|
+
* scroll that FINISHED before the click that opened the panel - the browser
|
|
43
|
+
* pulling a half-hidden funnel button into view as it focuses it, a test
|
|
44
|
+
* driver scrolling the header into place - still lands after the panel has
|
|
45
|
+
* mounted and wired this listener, and used to close it on the spot. The
|
|
46
|
+
* panel measured its anchor after that scroll, so the event carries nothing
|
|
47
|
+
* it needs to react to. Rendering runs the scroll steps before the animation
|
|
48
|
+
* frame callbacks, which is why one frame is exactly the right delay.
|
|
49
|
+
*
|
|
40
50
|
* Returns the unsubscribe function.
|
|
41
51
|
*/
|
|
42
52
|
export declare function onScrollOutside(element: () => DismissTarget, onOutside: () => void): () => void;
|