@alaarab/ogrid-vue-vuetify 2.4.2 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1 @@
1
- @import "@alaarab/ogrid-vue/styles/ogrid-theme.css";
2
- @import "@alaarab/ogrid-vue/styles/ogrid-layout.css";
3
-
4
- /* src/DataGridTable/DataGridTable.css */
5
- .v-table th:focus-visible,
6
- .v-table td:focus-visible {
7
- outline: 2px solid rgb(var(--v-theme-primary));
8
- outline-offset: -2px;
9
- z-index: 11;
10
- }
11
- .v-btn:focus-visible {
12
- outline: 2px solid rgb(var(--v-theme-primary));
13
- outline-offset: 2px;
14
- }
15
- .v-checkbox:focus-visible {
16
- outline: 2px solid rgb(var(--v-theme-primary));
17
- outline-offset: 2px;
18
- }
19
- .ogrid-cell-content:focus-visible {
20
- outline: 2px solid rgb(var(--v-theme-primary));
21
- outline-offset: -2px;
22
- z-index: 3;
23
- }
1
+ @import"@alaarab/ogrid-vue/styles/ogrid-theme.css";@import"@alaarab/ogrid-vue/styles/ogrid-layout.css";.v-table th:focus-visible,.v-table td:focus-visible{outline:2px solid rgb(var(--v-theme-primary));outline-offset:-2px;z-index:11}.v-btn:focus-visible{outline:2px solid rgb(var(--v-theme-primary));outline-offset:2px}.v-checkbox:focus-visible{outline:2px solid rgb(var(--v-theme-primary));outline-offset:2px}.ogrid-cell-content:focus-visible{outline:2px solid rgb(var(--v-theme-primary));outline-offset:-2px;z-index:3}
package/dist/esm/index.js CHANGED
@@ -1,872 +1 @@
1
- import { useColumnHeaderFilterState, getColumnHeaderMenuItems, createInlineCellEditor, getContextMenuHandlers, GRID_CONTEXT_MENU_ITEMS, formatShortcut, createDataGridTable, useColumnChooserState, getPaginationViewModel, createOGrid } from '@alaarab/ogrid-vue';
2
- export { AUTOSIZE_EXTRA_PX, AUTOSIZE_MAX_PX, CELL_PADDING, CHECKBOX_COLUMN_WIDTH, COLUMN_HEADER_MENU_ITEMS, DEFAULT_DEBOUNCE_MS, DEFAULT_MIN_COLUMN_WIDTH, GRID_BORDER_RADIUS, GRID_CONTEXT_MENU_ITEMS, MAX_PAGE_BUTTONS, MarchingAntsOverlay, PAGE_SIZE_OPTIONS, PEOPLE_SEARCH_DEBOUNCE_MS, ROW_NUMBER_COLUMN_WIDTH, SIDEBAR_TRANSITION_MS, StatusBar, UndoRedoStack, Z_INDEX, applyCellDeletion, applyCutClear, applyFillValues, applyPastedValues, applyRangeRowSelection, areGridRowPropsEqual, booleanParser, buildCsvHeader, buildCsvRows, buildHeaderRows, buildInlineEditorProps, buildPopoverEditorProps, calculateDropTarget, clampSelectionToBounds, computeAggregations, computeArrowNavigation, computeAutoScrollSpeed, computeNextSortState, computeRowSelectionState, computeTabNavigation, computeTotalHeight, computeVisibleRange, createDataGridTable, createInlineCellEditor, createOGrid, currencyParser, dateParser, debounce, deriveFilterOptionsFromData, emailParser, escapeCsvValue, exportToCsv, findCtrlArrowTarget, flattenColumns, formatCellValueForTsv, formatSelectionAsTsv, formatShortcut, getCellInteractionProps, getCellRenderDescriptor, getCellValue, getColumnHeaderMenuItems, getContextMenuHandlers, getDataGridStatusBarConfig, getFilterField, getHeaderFilterConfig, getMultiSelectFilterFields, getPaginationViewModel, getPinStateForColumn, getScrollTopForRow, getStatusBarParts, injectGlobalStyles, isFilterConfig, isInSelectionRange, isRowInRange, measureColumnContentWidth, measureRange, mergeFilter, normalizeSelectionRange, numberParser, parseTsvClipboard, parseValue, processClientSideData, rangesEqual, reorderColumnArray, resolveCellDisplayContent, resolveCellStyle, toUserLike, triggerCsvDownload, useActiveCell, useCellEditing, useCellSelection, useClipboard, useColumnChooserState, useColumnHeaderFilterState, useColumnHeaderMenuState, useColumnPinning, useColumnReorder, useColumnResize, useContextMenu, useDataGridState, useDataGridTableSetup, useDateFilterState, useDebounce, useDebouncedCallback, useFillHandle, useFilterOptions, useInlineCellEditorState, useKeyboardNavigation, useMultiSelectFilterState, useOGrid, usePeopleFilterState, useRichSelectState, useRowSelection, useSideBarState, useTableLayout, useTextFilterState, useUndoRedo, useVirtualScroll, validateColumns, validateRowIds } from '@alaarab/ogrid-vue';
3
- import { defineComponent, h, computed } from 'vue';
4
- import { VTextField, VBtn, VProgressCircular, VCheckbox, VDivider, VAvatar, VIcon, VTooltip, VMenu, VCard, VList, VListItem, VSelect } from 'vuetify/components';
5
-
6
- // src/index.ts
7
- var _VBtn = VBtn;
8
- var _VTextField = VTextField;
9
- var TextFilterPopover = defineComponent({
10
- name: "TextFilterPopover",
11
- props: {
12
- value: { type: String, required: true },
13
- onValueChange: { type: Function, required: true },
14
- onApply: { type: Function, required: true },
15
- onClear: { type: Function, required: true }
16
- },
17
- setup(props) {
18
- return () => h("div", { style: { width: "260px" } }, [
19
- h(
20
- "div",
21
- { style: { padding: "12px" } },
22
- h(_VTextField, {
23
- modelValue: props.value,
24
- "onUpdate:modelValue": (v) => props.onValueChange(v),
25
- placeholder: "Enter search term...",
26
- density: "compact",
27
- variant: "outlined",
28
- hideDetails: true,
29
- autocomplete: "off",
30
- prependInnerIcon: "mdi-magnify",
31
- onKeydown: (e) => {
32
- e.stopPropagation();
33
- if (e.key === "Enter") {
34
- e.preventDefault();
35
- props.onApply();
36
- }
37
- }
38
- })
39
- ),
40
- h("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px", padding: "0 12px 12px" } }, [
41
- h(_VBtn, { size: "small", variant: "text", disabled: !props.value, onClick: props.onClear }, () => "Clear"),
42
- h(_VBtn, { size: "small", variant: "flat", color: "primary", onClick: props.onApply }, () => "Apply")
43
- ])
44
- ]);
45
- }
46
- });
47
- var _VBtn2 = VBtn;
48
- var _VTextField2 = VTextField;
49
- var _VCheckbox = VCheckbox;
50
- var _VProgressCircular = VProgressCircular;
51
- var _VDivider = VDivider;
52
- var MultiSelectFilterPopover = defineComponent({
53
- name: "MultiSelectFilterPopover",
54
- props: {
55
- searchText: { type: String, required: true },
56
- onSearchChange: { type: Function, required: true },
57
- options: { type: Array, required: true },
58
- filteredOptions: { type: Array, required: true },
59
- selected: { type: Object, required: true },
60
- onOptionToggle: { type: Function, required: true },
61
- onSelectAll: { type: Function, required: true },
62
- onClearSelection: { type: Function, required: true },
63
- onApply: { type: Function, required: true },
64
- isLoading: { type: Boolean, default: false }
65
- },
66
- setup(props) {
67
- return () => h("div", { style: { width: "280px" } }, [
68
- // Search
69
- h("div", { style: { padding: "12px 12px 4px" } }, [
70
- h(_VTextField2, {
71
- modelValue: props.searchText,
72
- "onUpdate:modelValue": (v) => props.onSearchChange(v),
73
- placeholder: "Search...",
74
- density: "compact",
75
- variant: "outlined",
76
- hideDetails: true,
77
- autocomplete: "off",
78
- prependInnerIcon: "mdi-magnify",
79
- onKeydown: (e) => e.stopPropagation()
80
- }),
81
- h("span", {
82
- style: { display: "block", marginTop: "4px", fontSize: "0.75rem", color: "rgba(0,0,0,0.6)" }
83
- }, `${props.filteredOptions.length} of ${props.options.length} options`)
84
- ]),
85
- // Select all / clear
86
- h("div", { style: { display: "flex", justifyContent: "space-between", padding: "4px 12px" } }, [
87
- h(
88
- _VBtn2,
89
- { size: "small", variant: "text", onClick: props.onSelectAll },
90
- () => `Select All (${props.filteredOptions.length})`
91
- ),
92
- h(_VBtn2, { size: "small", variant: "text", onClick: props.onClearSelection }, () => "Clear")
93
- ]),
94
- // Options list
95
- h(
96
- "div",
97
- { style: { maxHeight: "240px", overflowY: "auto", padding: "0 4px" } },
98
- props.isLoading ? h(
99
- "div",
100
- { style: { display: "flex", justifyContent: "center", padding: "16px 0" } },
101
- h(_VProgressCircular, { size: 24, indeterminate: true })
102
- ) : props.filteredOptions.length === 0 ? h("div", { style: { padding: "16px 0", textAlign: "center", fontSize: "0.875rem", color: "rgba(0,0,0,0.6)" } }, "No options found") : props.filteredOptions.map(
103
- (option) => h(
104
- "div",
105
- { key: option, style: { display: "flex", alignItems: "center", minHeight: "32px" } },
106
- h(_VCheckbox, {
107
- modelValue: props.selected.has(option),
108
- label: option,
109
- density: "compact",
110
- hideDetails: true,
111
- "onUpdate:modelValue": (checked) => props.onOptionToggle(option, checked)
112
- })
113
- )
114
- )
115
- ),
116
- // Footer
117
- h(_VDivider),
118
- h("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px", padding: "8px 12px" } }, [
119
- h(_VBtn2, { size: "small", variant: "text", onClick: props.onClearSelection }, () => "Clear"),
120
- h(_VBtn2, { size: "small", variant: "flat", color: "primary", onClick: props.onApply }, () => "Apply")
121
- ])
122
- ]);
123
- }
124
- });
125
- var _VBtn3 = VBtn;
126
- var _VTextField3 = VTextField;
127
- var _VProgressCircular2 = VProgressCircular;
128
- var _VAvatar = VAvatar;
129
- var _VIcon = VIcon;
130
- var _VDivider2 = VDivider;
131
- var PeopleFilterPopover = defineComponent({
132
- name: "PeopleFilterPopover",
133
- props: {
134
- selectedUser: { type: Object, default: void 0 },
135
- searchText: { type: String, required: true },
136
- onSearchChange: { type: Function, required: true },
137
- suggestions: { type: Array, required: true },
138
- isLoading: { type: Boolean, default: false },
139
- onUserSelect: { type: Function, required: true },
140
- onClearUser: { type: Function, required: true }
141
- },
142
- setup(props) {
143
- return () => h("div", { style: { width: "300px" } }, [
144
- // Selected user display
145
- ...props.selectedUser ? [
146
- h("div", { style: { padding: "12px 12px 8px", borderBottom: "1px solid rgba(0,0,0,0.12)" } }, [
147
- h("span", { style: { fontSize: "0.75rem", color: "rgba(0,0,0,0.6)" } }, "Currently filtered by:"),
148
- h("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginTop: "4px" } }, [
149
- h(
150
- _VAvatar,
151
- { size: 32, image: props.selectedUser.photo },
152
- () => props.selectedUser?.displayName?.[0] ?? ""
153
- ),
154
- h("div", { style: { flex: "1", minWidth: "0" } }, [
155
- h("div", { style: { fontSize: "0.875rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, props.selectedUser?.displayName),
156
- h("div", { style: { fontSize: "0.75rem", color: "rgba(0,0,0,0.6)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, props.selectedUser?.email)
157
- ]),
158
- h(_VBtn3, {
159
- icon: true,
160
- size: "x-small",
161
- variant: "text",
162
- "aria-label": "Remove filter",
163
- onClick: props.onClearUser
164
- }, () => h(_VIcon, { size: "16" }, () => "mdi-close"))
165
- ])
166
- ])
167
- ] : [],
168
- // Search input
169
- h(
170
- "div",
171
- { style: { padding: "12px 12px 4px" } },
172
- h(_VTextField3, {
173
- modelValue: props.searchText,
174
- "onUpdate:modelValue": (v) => props.onSearchChange(v),
175
- placeholder: "Search for a person...",
176
- density: "compact",
177
- variant: "outlined",
178
- hideDetails: true,
179
- autocomplete: "off",
180
- prependInnerIcon: "mdi-magnify",
181
- onKeydown: (e) => e.stopPropagation()
182
- })
183
- ),
184
- // Suggestions list
185
- h(
186
- "div",
187
- { style: { maxHeight: "240px", overflowY: "auto" } },
188
- props.isLoading && props.searchText.trim() ? h(
189
- "div",
190
- { style: { display: "flex", justifyContent: "center", padding: "16px 0" } },
191
- h(_VProgressCircular2, { size: 24, indeterminate: true })
192
- ) : props.suggestions.length === 0 && props.searchText.trim() ? h("div", { style: { padding: "16px 0", textAlign: "center", fontSize: "0.875rem", color: "rgba(0,0,0,0.6)" } }, "No results found") : props.searchText.trim() ? props.suggestions.map(
193
- (user) => h("div", {
194
- key: user.id || user.email || user.displayName,
195
- style: { display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", cursor: "pointer" },
196
- onClick: () => props.onUserSelect(user),
197
- onMouseenter: (e) => {
198
- e.currentTarget.style.backgroundColor = "rgba(0,0,0,0.04)";
199
- },
200
- onMouseleave: (e) => {
201
- e.currentTarget.style.backgroundColor = "";
202
- }
203
- }, [
204
- h(
205
- _VAvatar,
206
- { size: 32, image: user.photo },
207
- () => user.displayName?.[0] ?? ""
208
- ),
209
- h("div", { style: { flex: "1", minWidth: "0" } }, [
210
- h("div", { style: { fontSize: "0.875rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, user.displayName),
211
- h("div", { style: { fontSize: "0.75rem", color: "rgba(0,0,0,0.6)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, user.email)
212
- ])
213
- ])
214
- ) : h("div", { style: { padding: "16px 0", textAlign: "center", fontSize: "0.875rem", color: "rgba(0,0,0,0.6)" } }, "Type to search...")
215
- ),
216
- // Clear filter button
217
- ...props.selectedUser ? [
218
- h(_VDivider2),
219
- h(
220
- "div",
221
- { style: { padding: "8px 12px" } },
222
- h(_VBtn3, { size: "small", variant: "text", block: true, onClick: props.onClearUser }, () => "Clear Filter")
223
- )
224
- ] : []
225
- ]);
226
- }
227
- });
228
-
229
- // src/ColumnHeaderFilter/ColumnHeaderFilter.ts
230
- var _VBtn4 = VBtn;
231
- var _VIcon2 = VIcon;
232
- var _VMenu = VMenu;
233
- var _VTooltip = VTooltip;
234
- var _VCard = VCard;
235
- var ColumnHeaderFilter = defineComponent({
236
- name: "ColumnHeaderFilter",
237
- props: {
238
- columnKey: { type: String, required: true },
239
- columnName: { type: String, required: true },
240
- filterType: { type: String, required: true },
241
- isSorted: { type: Boolean, default: false },
242
- isSortedDescending: { type: Boolean, default: false },
243
- onSort: { type: Function, default: void 0 },
244
- selectedValues: { type: Array, default: void 0 },
245
- onFilterChange: { type: Function, default: void 0 },
246
- options: { type: Array, default: () => [] },
247
- isLoadingOptions: { type: Boolean, default: false },
248
- textValue: { type: String, default: "" },
249
- onTextChange: { type: Function, default: void 0 },
250
- selectedUser: { type: Object, default: void 0 },
251
- onUserChange: { type: Function, default: void 0 },
252
- peopleSearch: { type: Function, default: void 0 },
253
- dateValue: { type: Object, default: void 0 },
254
- onDateChange: { type: Function, default: void 0 }
255
- },
256
- setup(props) {
257
- const state = useColumnHeaderFilterState(props);
258
- const renderPopoverContent = () => {
259
- if (props.filterType === "multiSelect") {
260
- return h(MultiSelectFilterPopover, {
261
- searchText: state.searchText.value,
262
- onSearchChange: state.setSearchText,
263
- options: props.options ?? [],
264
- filteredOptions: state.filteredOptions.value,
265
- selected: state.tempSelected.value,
266
- onOptionToggle: state.handlers.handleCheckboxChange,
267
- onSelectAll: state.handlers.handleSelectAll,
268
- onClearSelection: state.handlers.handleClearSelection,
269
- onApply: state.handlers.handleApplyMultiSelect,
270
- isLoading: props.isLoadingOptions
271
- });
272
- }
273
- if (props.filterType === "text") {
274
- return h(TextFilterPopover, {
275
- value: state.tempTextValue.value ?? "",
276
- onValueChange: state.setTempTextValue,
277
- onApply: state.handlers.handleTextApply,
278
- onClear: state.handlers.handleTextClear
279
- });
280
- }
281
- if (props.filterType === "people") {
282
- return h(PeopleFilterPopover, {
283
- selectedUser: props.selectedUser,
284
- searchText: state.peopleSearchText.value,
285
- onSearchChange: state.setPeopleSearchText,
286
- suggestions: state.peopleSuggestions.value,
287
- isLoading: state.isPeopleLoading.value,
288
- onUserSelect: state.handlers.handleUserSelect,
289
- onClearUser: state.handlers.handleClearUser
290
- });
291
- }
292
- if (props.filterType === "date") {
293
- return h("div", { style: { padding: "12px", display: "flex", flexDirection: "column", gap: "8px" } }, [
294
- h("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, [
295
- h("span", { style: { minWidth: "36px", fontSize: "0.75rem" } }, "From:"),
296
- h("input", {
297
- type: "date",
298
- value: state.tempDateFrom.value ?? "",
299
- onInput: (e) => state.setTempDateFrom(e.target.value),
300
- style: { flex: "1", padding: "4px 6px" }
301
- })
302
- ]),
303
- h("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, [
304
- h("span", { style: { minWidth: "36px", fontSize: "0.75rem" } }, "To:"),
305
- h("input", {
306
- type: "date",
307
- value: state.tempDateTo.value ?? "",
308
- onInput: (e) => state.setTempDateTo(e.target.value),
309
- style: { flex: "1", padding: "4px 6px" }
310
- })
311
- ]),
312
- h("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px", marginTop: "4px" } }, [
313
- h("button", {
314
- onClick: state.handlers.handleDateClear,
315
- disabled: !state.tempDateFrom.value && !state.tempDateTo.value,
316
- style: { padding: "4px 12px", cursor: "pointer" }
317
- }, "Clear"),
318
- h("button", {
319
- onClick: state.handlers.handleDateApply,
320
- style: { padding: "4px 12px", cursor: "pointer" }
321
- }, "Apply")
322
- ])
323
- ]);
324
- }
325
- return null;
326
- };
327
- return () => {
328
- return h("div", {
329
- ref: (el) => {
330
- state.headerRef.value = el;
331
- },
332
- style: { display: "flex", alignItems: "center", width: "100%", minWidth: "0" }
333
- }, [
334
- // Column name with tooltip
335
- h(
336
- "div",
337
- { style: { flex: "1", minWidth: "0", overflow: "hidden" } },
338
- h(_VTooltip, { text: props.columnName, location: "top" }, {
339
- activator: ({ props: tipProps }) => h("span", {
340
- ...tipProps,
341
- "data-header-label": "",
342
- style: {
343
- fontWeight: "600",
344
- fontSize: "0.875rem",
345
- lineHeight: "1.4",
346
- whiteSpace: "nowrap",
347
- overflow: "hidden",
348
- textOverflow: "ellipsis",
349
- display: "block"
350
- }
351
- }, props.columnName)
352
- })
353
- ),
354
- // Sort + filter buttons
355
- h("div", { style: { display: "flex", alignItems: "center", marginLeft: "4px", flexShrink: "0" } }, [
356
- // Filter icon + menu
357
- ...props.filterType !== "none" ? [
358
- h(_VMenu, {
359
- modelValue: state.isFilterOpen.value,
360
- "onUpdate:modelValue": (v) => state.setFilterOpen(v),
361
- closeOnContentClick: false,
362
- location: "bottom start"
363
- }, {
364
- activator: ({ props: menuProps }) => h("div", { style: { position: "relative" } }, [
365
- h(_VBtn4, {
366
- ...menuProps,
367
- icon: true,
368
- size: "x-small",
369
- variant: state.hasActiveFilter.value || state.isFilterOpen.value ? "tonal" : "text",
370
- color: state.hasActiveFilter.value || state.isFilterOpen.value ? "primary" : "default",
371
- "aria-label": `Filter ${props.columnName}`,
372
- "aria-expanded": state.isFilterOpen.value,
373
- "aria-haspopup": "dialog",
374
- title: `Filter ${props.columnName}`,
375
- style: {
376
- opacity: state.hasActiveFilter.value || state.isFilterOpen.value ? "1" : "0.7"
377
- }
378
- }, () => h(_VIcon2, { size: "16" }, () => "mdi-filter-variant")),
379
- ...state.hasActiveFilter.value ? [
380
- h("div", {
381
- style: {
382
- position: "absolute",
383
- top: "2px",
384
- right: "2px",
385
- width: "6px",
386
- height: "6px",
387
- borderRadius: "50%",
388
- backgroundColor: "rgb(var(--v-theme-primary))",
389
- zIndex: "1"
390
- }
391
- })
392
- ] : []
393
- ]),
394
- default: () => h(_VCard, {
395
- elevation: 8,
396
- ref: (el) => {
397
- state.popoverRef.value = el;
398
- },
399
- onClick: (e) => e.stopPropagation()
400
- }, () => [
401
- h("div", {
402
- style: {
403
- borderBottom: "1px solid rgba(0,0,0,0.12)",
404
- padding: "8px 12px",
405
- fontWeight: "600",
406
- fontSize: "0.875rem",
407
- backgroundColor: "rgb(var(--v-theme-surface))"
408
- }
409
- }, `Filter: ${props.columnName}`),
410
- renderPopoverContent()
411
- ])
412
- })
413
- ] : []
414
- ])
415
- ]);
416
- };
417
- }
418
- });
419
- var ColumnHeaderMenu = defineComponent({
420
- name: "ColumnHeaderMenu",
421
- props: {
422
- isOpen: { type: Boolean, required: true },
423
- anchorElement: { type: Object, default: null },
424
- onClose: { type: Function, required: true },
425
- onPinLeft: { type: Function, required: true },
426
- onPinRight: { type: Function, required: true },
427
- onUnpin: { type: Function, required: true },
428
- onSortAsc: { type: Function, required: true },
429
- onSortDesc: { type: Function, required: true },
430
- onClearSort: { type: Function, required: true },
431
- onAutosizeThis: { type: Function, required: true },
432
- onAutosizeAll: { type: Function, required: true },
433
- canPinLeft: { type: Boolean, required: true },
434
- canPinRight: { type: Boolean, required: true },
435
- canUnpin: { type: Boolean, required: true },
436
- currentSort: { type: String, default: null },
437
- isSortable: { type: Boolean, default: true },
438
- isResizable: { type: Boolean, default: true }
439
- },
440
- setup(props) {
441
- const handleOpenChange = (open) => {
442
- if (!open) {
443
- props.onClose();
444
- }
445
- };
446
- const items = computed(
447
- () => getColumnHeaderMenuItems({
448
- canPinLeft: props.canPinLeft,
449
- canPinRight: props.canPinRight,
450
- canUnpin: props.canUnpin,
451
- currentSort: props.currentSort,
452
- isSortable: props.isSortable,
453
- isResizable: props.isResizable
454
- })
455
- );
456
- const handlers = {
457
- pinLeft: props.onPinLeft,
458
- pinRight: props.onPinRight,
459
- unpin: props.onUnpin,
460
- sortAsc: props.onSortAsc,
461
- sortDesc: props.onSortDesc,
462
- clearSort: props.onClearSort,
463
- autosizeThis: props.onAutosizeThis,
464
- autosizeAll: props.onAutosizeAll
465
- };
466
- const getHandler = (itemId) => handlers[itemId] || (() => {
467
- });
468
- return () => {
469
- if (!props.anchorElement) return null;
470
- return h(VMenu, {
471
- modelValue: props.isOpen,
472
- "onUpdate:modelValue": handleOpenChange,
473
- location: "bottom start",
474
- // Use target prop instead of activator for programmatic positioning
475
- target: props.anchorElement
476
- }, {
477
- default: () => h(VList, { density: "compact", "aria-label": "Column options" }, () => {
478
- const children = [];
479
- items.value.forEach((item) => {
480
- children.push(
481
- h(VListItem, {
482
- key: item.id,
483
- disabled: item.disabled,
484
- onClick: () => {
485
- getHandler(item.id)();
486
- }
487
- }, () => item.label)
488
- );
489
- if (item.divider) {
490
- children.push(h(VDivider, { key: `divider-${item.id}` }));
491
- }
492
- });
493
- return children;
494
- })
495
- });
496
- };
497
- }
498
- });
499
- var InlineCellEditor = createInlineCellEditor({
500
- renderCheckbox: ({ checked, onChange, onCancel }) => h(VCheckbox, {
501
- modelValue: checked,
502
- hideDetails: true,
503
- density: "compact",
504
- "onUpdate:modelValue": (c) => onChange(c),
505
- onKeydown: (e) => {
506
- if (e.key === "Escape") {
507
- e.preventDefault();
508
- onCancel();
509
- }
510
- }
511
- }),
512
- renderDatePicker: ({ value, onChange, onCancel }) => h("input", {
513
- type: "date",
514
- value,
515
- style: { width: "100%", height: "100%", border: "none", outline: "none", padding: "0 4px", fontSize: "inherit" },
516
- onVnodeMounted: (vnode) => {
517
- const el = vnode.el;
518
- if (el) {
519
- el.focus();
520
- try {
521
- el.showPicker();
522
- } catch {
523
- }
524
- }
525
- },
526
- onKeydown: (e) => {
527
- if (e.key === "Enter") {
528
- e.preventDefault();
529
- onChange(e.target.value);
530
- }
531
- if (e.key === "Escape") {
532
- e.preventDefault();
533
- onCancel();
534
- }
535
- if (e.key === "Tab") {
536
- e.preventDefault();
537
- onChange(e.target.value);
538
- }
539
- },
540
- onBlur: (e) => onChange(e.target.value)
541
- })
542
- });
543
- var GridContextMenu = defineComponent({
544
- name: "GridContextMenu",
545
- props: {
546
- x: { type: Number, required: true },
547
- y: { type: Number, required: true },
548
- hasSelection: { type: Boolean, required: true },
549
- canUndo: { type: Boolean, required: true },
550
- canRedo: { type: Boolean, required: true },
551
- onUndo: { type: Function, required: true },
552
- onRedo: { type: Function, required: true },
553
- onCopy: { type: Function, required: true },
554
- onCut: { type: Function, required: true },
555
- onPaste: { type: Function, required: true },
556
- onSelectAll: { type: Function, required: true },
557
- onClose: { type: Function, required: true }
558
- },
559
- setup(props) {
560
- const handlers = getContextMenuHandlers(props);
561
- const isDisabled = (item) => {
562
- if (item.disabledWhenNoSelection && !props.hasSelection) return true;
563
- if (item.id === "undo" && !props.canUndo) return true;
564
- if (item.id === "redo" && !props.canRedo) return true;
565
- return false;
566
- };
567
- return () => h(VMenu, {
568
- modelValue: true,
569
- "onUpdate:modelValue": (v) => {
570
- if (!v) props.onClose();
571
- },
572
- target: [props.x, props.y],
573
- location: "bottom start"
574
- }, {
575
- default: () => h(
576
- VList,
577
- { density: "compact", "aria-label": "Grid context menu" },
578
- () => GRID_CONTEXT_MENU_ITEMS.map((item) => [
579
- ...item.dividerBefore ? [h(VDivider, { key: `${item.id}-div` })] : [],
580
- h(
581
- VListItem,
582
- {
583
- key: item.id,
584
- disabled: isDisabled(item),
585
- onClick: () => {
586
- handlers[item.id]();
587
- }
588
- },
589
- () => h("div", { style: { display: "flex", alignItems: "center", width: "100%" } }, [
590
- h("span", { style: { flex: "1" } }, item.label),
591
- ...item.shortcut ? [
592
- h("span", {
593
- style: { marginLeft: "24px", color: "rgba(0,0,0,0.4)", fontSize: "0.8em" }
594
- }, formatShortcut(item.shortcut))
595
- ] : []
596
- ])
597
- )
598
- ]).flat()
599
- )
600
- });
601
- }
602
- });
603
- function renderEmptyState({ emptyState }) {
604
- return h(
605
- "div",
606
- { class: "ogrid-empty-state" },
607
- emptyState.render ? [emptyState.render()] : [
608
- h("div", { class: "ogrid-empty-state-title" }, "No results found"),
609
- h(
610
- "div",
611
- { class: "ogrid-empty-state-message" },
612
- emptyState.message != null ? String(emptyState.message) : emptyState.hasActiveFilters ? [
613
- "No items match your current filters. Try adjusting your search or ",
614
- h(VBtn, {
615
- variant: "text",
616
- size: "small",
617
- onClick: emptyState.onClearAll
618
- }, () => "clear all filters"),
619
- " to see all items."
620
- ] : "There are no items available at this time."
621
- )
622
- ]
623
- );
624
- }
625
-
626
- // src/DataGridTable/DataGridTable.ts
627
- var DataGridTable = createDataGridTable({
628
- renderCheckbox: ({ modelValue, indeterminate, ariaLabel, onChange }) => h(VCheckbox, {
629
- modelValue,
630
- indeterminate,
631
- hideDetails: true,
632
- density: "compact",
633
- "aria-label": ariaLabel,
634
- "onUpdate:modelValue": (c) => onChange(!!c)
635
- }),
636
- renderSpinner: (message) => h("div", { class: "ogrid-loading-inner" }, [
637
- h(VProgressCircular, { size: 24, indeterminate: true }),
638
- h("span", { class: "ogrid-loading-message" }, message)
639
- ]),
640
- ColumnHeaderFilter,
641
- ColumnHeaderMenu,
642
- InlineCellEditor,
643
- GridContextMenu,
644
- renderEmptyState: (emptyState) => renderEmptyState({ emptyState })
645
- });
646
- var ColumnChooser = defineComponent({
647
- name: "ColumnChooser",
648
- props: {
649
- columns: { type: Array, required: true },
650
- visibleColumns: { type: Object, required: true },
651
- onVisibilityChange: { type: Function, required: true }
652
- },
653
- setup(props) {
654
- const columnsRef = computed(() => props.columns);
655
- const visibleColumnsRef = computed(() => props.visibleColumns);
656
- const state = useColumnChooserState({
657
- columns: columnsRef,
658
- visibleColumns: visibleColumnsRef,
659
- onVisibilityChange: props.onVisibilityChange
660
- });
661
- return () => {
662
- return h(VMenu, {
663
- modelValue: state.open.value,
664
- "onUpdate:modelValue": (v) => {
665
- state.setOpen(v);
666
- },
667
- closeOnContentClick: false,
668
- location: "bottom end"
669
- }, {
670
- activator: ({ props: activatorProps }) => h(VBtn, {
671
- ...activatorProps,
672
- variant: "outlined",
673
- size: "small",
674
- prependIcon: "mdi-view-column",
675
- appendIcon: state.open.value ? "mdi-chevron-up" : "mdi-chevron-down"
676
- }, () => `Column Visibility (${state.visibleCount.value} of ${state.totalCount.value})`),
677
- default: () => h("div", { style: { minWidth: "220px" } }, [
678
- // Header
679
- h("div", {
680
- style: {
681
- padding: "8px 12px",
682
- borderBottom: "1px solid rgba(0,0,0,0.12)",
683
- backgroundColor: "rgba(0,0,0,0.04)",
684
- fontWeight: "600",
685
- fontSize: "0.875rem"
686
- }
687
- }, `Select Columns (${state.visibleCount.value} of ${state.totalCount.value})`),
688
- // Column list
689
- h(
690
- VList,
691
- { density: "compact", style: { maxHeight: "320px", overflowY: "auto" } },
692
- () => props.columns.map(
693
- (column) => h(
694
- VListItem,
695
- { key: column.columnId, style: { minHeight: "32px" } },
696
- () => h("label", {
697
- style: { display: "flex", alignItems: "center", gap: "8px", cursor: "pointer", width: "100%" }
698
- }, [
699
- h("input", {
700
- type: "checkbox",
701
- checked: props.visibleColumns.has(column.columnId),
702
- onChange: (e) => state.handleCheckboxChange(column.columnId)(e.target.checked)
703
- }),
704
- h("span", { style: { fontSize: "0.875rem" } }, column.name)
705
- ])
706
- )
707
- )
708
- ),
709
- // Footer with actions
710
- h(VDivider),
711
- h("div", {
712
- style: {
713
- display: "flex",
714
- justifyContent: "flex-end",
715
- gap: "8px",
716
- padding: "8px 12px",
717
- backgroundColor: "rgba(0,0,0,0.04)"
718
- }
719
- }, [
720
- h(VBtn, { size: "small", variant: "text", onClick: state.handleClearAll }, () => "Clear All"),
721
- h(VBtn, { size: "small", variant: "flat", color: "primary", onClick: state.handleSelectAll }, () => "Select All")
722
- ])
723
- ])
724
- });
725
- };
726
- }
727
- });
728
- var PaginationControls = defineComponent({
729
- name: "PaginationControls",
730
- props: {
731
- currentPage: { type: Number, required: true },
732
- pageSize: { type: Number, required: true },
733
- totalCount: { type: Number, required: true },
734
- onPageChange: { type: Function, required: true },
735
- onPageSizeChange: { type: Function, required: true },
736
- pageSizeOptions: { type: Array, default: void 0 },
737
- entityLabelPlural: { type: String, default: "items" }
738
- },
739
- setup(props) {
740
- const vm = computed(
741
- () => getPaginationViewModel(
742
- props.currentPage,
743
- props.pageSize,
744
- props.totalCount,
745
- props.pageSizeOptions ? { pageSizeOptions: props.pageSizeOptions } : void 0
746
- )
747
- );
748
- return () => {
749
- const v = vm.value;
750
- if (!v) return null;
751
- const { pageNumbers, showStartEllipsis, showEndEllipsis, totalPages, startItem, endItem } = v;
752
- const label = props.entityLabelPlural ?? "items";
753
- return h("div", {
754
- role: "navigation",
755
- "aria-label": "Pagination",
756
- style: {
757
- display: "flex",
758
- alignItems: "center",
759
- justifyContent: "space-between",
760
- flexWrap: "wrap",
761
- gap: "16px",
762
- padding: "0 12px",
763
- width: "100%",
764
- minWidth: "0",
765
- boxSizing: "border-box"
766
- }
767
- }, [
768
- // Summary text
769
- h("span", {
770
- style: { fontSize: "0.875rem", color: "var(--ogrid-fg-secondary, rgba(0,0,0,0.6))" }
771
- }, `Showing ${startItem} to ${endItem} of ${props.totalCount.toLocaleString()} ${label}`),
772
- // Page buttons
773
- h("div", { style: { display: "flex", alignItems: "center", gap: "4px" } }, [
774
- // First page
775
- h(VBtn, {
776
- icon: "mdi-page-first",
777
- size: "small",
778
- variant: "text",
779
- disabled: props.currentPage === 1,
780
- "aria-label": "First page",
781
- onClick: () => props.onPageChange(1)
782
- }),
783
- // Previous
784
- h(VBtn, {
785
- icon: "mdi-chevron-left",
786
- size: "small",
787
- variant: "text",
788
- disabled: props.currentPage === 1,
789
- "aria-label": "Previous page",
790
- onClick: () => props.onPageChange(props.currentPage - 1)
791
- }),
792
- // Start ellipsis
793
- ...showStartEllipsis ? [
794
- h(VBtn, {
795
- size: "small",
796
- variant: "outlined",
797
- "aria-label": "Page 1",
798
- style: { minWidth: "32px" },
799
- onClick: () => props.onPageChange(1)
800
- }, () => "1"),
801
- h("span", { style: { margin: "0 4px", color: "var(--ogrid-fg-secondary, rgba(0,0,0,0.6))" }, "aria-hidden": "true" }, "\u2026")
802
- ] : [],
803
- // Page numbers
804
- ...pageNumbers.map(
805
- (pageNum) => h(VBtn, {
806
- key: pageNum,
807
- size: "small",
808
- variant: props.currentPage === pageNum ? "flat" : "outlined",
809
- color: props.currentPage === pageNum ? "primary" : void 0,
810
- "aria-label": `Page ${pageNum}`,
811
- "aria-current": props.currentPage === pageNum ? "page" : void 0,
812
- style: { minWidth: "32px" },
813
- onClick: () => props.onPageChange(pageNum)
814
- }, () => String(pageNum))
815
- ),
816
- // End ellipsis
817
- ...showEndEllipsis ? [
818
- h("span", { style: { margin: "0 4px", color: "var(--ogrid-fg-secondary, rgba(0,0,0,0.6))" }, "aria-hidden": "true" }, "\u2026"),
819
- h(VBtn, {
820
- size: "small",
821
- variant: "outlined",
822
- "aria-label": `Page ${totalPages}`,
823
- style: { minWidth: "32px" },
824
- onClick: () => props.onPageChange(totalPages)
825
- }, () => String(totalPages))
826
- ] : [],
827
- // Next
828
- h(VBtn, {
829
- icon: "mdi-chevron-right",
830
- size: "small",
831
- variant: "text",
832
- disabled: props.currentPage >= totalPages,
833
- "aria-label": "Next page",
834
- onClick: () => props.onPageChange(props.currentPage + 1)
835
- }),
836
- // Last page
837
- h(VBtn, {
838
- icon: "mdi-page-last",
839
- size: "small",
840
- variant: "text",
841
- disabled: props.currentPage >= totalPages,
842
- "aria-label": "Last page",
843
- onClick: () => props.onPageChange(totalPages)
844
- })
845
- ]),
846
- // Page size selector
847
- h("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, [
848
- h("span", { style: { fontSize: "0.875rem", color: "var(--ogrid-fg-secondary, rgba(0,0,0,0.6))" } }, "Rows"),
849
- h(VSelect, {
850
- modelValue: props.pageSize,
851
- items: v.pageSizeOptions,
852
- density: "compact",
853
- hideDetails: true,
854
- variant: "outlined",
855
- "aria-label": "Rows per page",
856
- style: { minWidth: "70px", maxWidth: "90px" },
857
- "onUpdate:modelValue": (val) => props.onPageSizeChange(Number(val))
858
- })
859
- ])
860
- ]);
861
- };
862
- }
863
- });
864
-
865
- // src/OGrid/OGrid.ts
866
- var OGrid = createOGrid({
867
- DataGridTable,
868
- ColumnChooser,
869
- PaginationControls
870
- });
871
-
872
- export { ColumnChooser, ColumnHeaderFilter, ColumnHeaderMenu, DataGridTable, GridContextMenu, InlineCellEditor, OGrid, PaginationControls };
1
+ import {useColumnHeaderFilterState,getColumnHeaderMenuItems,createInlineCellEditor,getContextMenuHandlers,GRID_CONTEXT_MENU_ITEMS,formatShortcut,createDataGridTable,useColumnChooserState,getPaginationViewModel,createOGrid}from'@alaarab/ogrid-vue';export{AUTOSIZE_EXTRA_PX,AUTOSIZE_MAX_PX,CELL_PADDING,CHECKBOX_COLUMN_WIDTH,COLUMN_HEADER_MENU_ITEMS,DEFAULT_DEBOUNCE_MS,DEFAULT_MIN_COLUMN_WIDTH,GRID_BORDER_RADIUS,GRID_CONTEXT_MENU_ITEMS,MAX_PAGE_BUTTONS,MarchingAntsOverlay,PAGE_SIZE_OPTIONS,PEOPLE_SEARCH_DEBOUNCE_MS,ROW_NUMBER_COLUMN_WIDTH,SIDEBAR_TRANSITION_MS,StatusBar,UndoRedoStack,Z_INDEX,applyCellDeletion,applyCutClear,applyFillValues,applyPastedValues,applyRangeRowSelection,areGridRowPropsEqual,booleanParser,buildCsvHeader,buildCsvRows,buildHeaderRows,buildInlineEditorProps,buildPopoverEditorProps,calculateDropTarget,clampSelectionToBounds,computeAggregations,computeArrowNavigation,computeAutoScrollSpeed,computeNextSortState,computeRowSelectionState,computeTabNavigation,computeTotalHeight,computeVisibleRange,createDataGridTable,createInlineCellEditor,createOGrid,currencyParser,dateParser,debounce,deriveFilterOptionsFromData,emailParser,escapeCsvValue,exportToCsv,findCtrlArrowTarget,flattenColumns,formatCellValueForTsv,formatSelectionAsTsv,formatShortcut,getCellInteractionProps,getCellRenderDescriptor,getCellValue,getColumnHeaderMenuItems,getContextMenuHandlers,getDataGridStatusBarConfig,getFilterField,getHeaderFilterConfig,getMultiSelectFilterFields,getPaginationViewModel,getPinStateForColumn,getScrollTopForRow,getStatusBarParts,injectGlobalStyles,isFilterConfig,isInSelectionRange,isRowInRange,measureColumnContentWidth,measureRange,mergeFilter,normalizeSelectionRange,numberParser,parseTsvClipboard,parseValue,processClientSideData,rangesEqual,reorderColumnArray,resolveCellDisplayContent,resolveCellStyle,toUserLike,triggerCsvDownload,useActiveCell,useCellEditing,useCellSelection,useClipboard,useColumnChooserState,useColumnHeaderFilterState,useColumnHeaderMenuState,useColumnPinning,useColumnReorder,useColumnResize,useContextMenu,useDataGridState,useDataGridTableSetup,useDateFilterState,useDebounce,useDebouncedCallback,useFillHandle,useFilterOptions,useInlineCellEditorState,useKeyboardNavigation,useMultiSelectFilterState,useOGrid,usePeopleFilterState,useRichSelectState,useRowSelection,useSideBarState,useTableLayout,useTextFilterState,useUndoRedo,useVirtualScroll,validateColumns,validateRowIds}from'@alaarab/ogrid-vue';import {defineComponent,h,computed}from'vue';import {VTextField,VBtn,VProgressCircular,VCheckbox,VDivider,VAvatar,VIcon,VTooltip,VMenu,VCard,VList,VListItem,VSelect}from'vuetify/components';var V=VBtn,B=VTextField,R=defineComponent({name:"TextFilterPopover",props:{value:{type:String,required:true},onValueChange:{type:Function,required:true},onApply:{type:Function,required:true},onClear:{type:Function,required:true}},setup(e){return ()=>h("div",{style:{width:"260px"}},[h("div",{style:{padding:"12px"}},h(B,{modelValue:e.value,"onUpdate:modelValue":t=>e.onValueChange(t),placeholder:"Enter search term...",density:"compact",variant:"outlined",hideDetails:true,autocomplete:"off",prependInnerIcon:"mdi-magnify",onKeydown:t=>{t.stopPropagation(),t.key==="Enter"&&(t.preventDefault(),e.onApply());}})),h("div",{style:{display:"flex",justifyContent:"flex-end",gap:"8px",padding:"0 12px 12px"}},[h(V,{size:"small",variant:"text",disabled:!e.value,onClick:e.onClear},()=>"Clear"),h(V,{size:"small",variant:"flat",color:"primary",onClick:e.onApply},()=>"Apply")])])}});var C=VBtn,Z=VTextField,Y=VCheckbox,J=VProgressCircular,Q=VDivider,D=defineComponent({name:"MultiSelectFilterPopover",props:{searchText:{type:String,required:true},onSearchChange:{type:Function,required:true},options:{type:Array,required:true},filteredOptions:{type:Array,required:true},selected:{type:Object,required:true},onOptionToggle:{type:Function,required:true},onSelectAll:{type:Function,required:true},onClearSelection:{type:Function,required:true},onApply:{type:Function,required:true},isLoading:{type:Boolean,default:false}},setup(e){return ()=>h("div",{style:{width:"280px"}},[h("div",{style:{padding:"12px 12px 4px"}},[h(Z,{modelValue:e.searchText,"onUpdate:modelValue":t=>e.onSearchChange(t),placeholder:"Search...",density:"compact",variant:"outlined",hideDetails:true,autocomplete:"off",prependInnerIcon:"mdi-magnify",onKeydown:t=>t.stopPropagation()}),h("span",{style:{display:"block",marginTop:"4px",fontSize:"0.75rem",color:"rgba(0,0,0,0.6)"}},`${e.filteredOptions.length} of ${e.options.length} options`)]),h("div",{style:{display:"flex",justifyContent:"space-between",padding:"4px 12px"}},[h(C,{size:"small",variant:"text",onClick:e.onSelectAll},()=>`Select All (${e.filteredOptions.length})`),h(C,{size:"small",variant:"text",onClick:e.onClearSelection},()=>"Clear")]),h("div",{style:{maxHeight:"240px",overflowY:"auto",padding:"0 4px"}},e.isLoading?h("div",{style:{display:"flex",justifyContent:"center",padding:"16px 0"}},h(J,{size:24,indeterminate:true})):e.filteredOptions.length===0?h("div",{style:{padding:"16px 0",textAlign:"center",fontSize:"0.875rem",color:"rgba(0,0,0,0.6)"}},"No options found"):e.filteredOptions.map(t=>h("div",{key:t,style:{display:"flex",alignItems:"center",minHeight:"32px"}},h(Y,{modelValue:e.selected.has(t),label:t,density:"compact",hideDetails:true,"onUpdate:modelValue":a=>e.onOptionToggle(t,a)})))),h(Q),h("div",{style:{display:"flex",justifyContent:"flex-end",gap:"8px",padding:"8px 12px"}},[h(C,{size:"small",variant:"text",onClick:e.onClearSelection},()=>"Clear"),h(C,{size:"small",variant:"flat",color:"primary",onClick:e.onApply},()=>"Apply")])])}});var E=VBtn,le=VTextField,se=VProgressCircular,M=VAvatar,de=VIcon,ue=VDivider,k=defineComponent({name:"PeopleFilterPopover",props:{selectedUser:{type:Object,default:void 0},searchText:{type:String,required:true},onSearchChange:{type:Function,required:true},suggestions:{type:Array,required:true},isLoading:{type:Boolean,default:false},onUserSelect:{type:Function,required:true},onClearUser:{type:Function,required:true}},setup(e){return ()=>h("div",{style:{width:"300px"}},[...e.selectedUser?[h("div",{style:{padding:"12px 12px 8px",borderBottom:"1px solid rgba(0,0,0,0.12)"}},[h("span",{style:{fontSize:"0.75rem",color:"rgba(0,0,0,0.6)"}},"Currently filtered by:"),h("div",{style:{display:"flex",alignItems:"center",gap:"8px",marginTop:"4px"}},[h(M,{size:32,image:e.selectedUser.photo},()=>e.selectedUser?.displayName?.[0]??""),h("div",{style:{flex:"1",minWidth:"0"}},[h("div",{style:{fontSize:"0.875rem",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},e.selectedUser?.displayName),h("div",{style:{fontSize:"0.75rem",color:"rgba(0,0,0,0.6)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},e.selectedUser?.email)]),h(E,{icon:true,size:"x-small",variant:"text","aria-label":"Remove filter",onClick:e.onClearUser},()=>h(de,{size:"16"},()=>"mdi-close"))])])]:[],h("div",{style:{padding:"12px 12px 4px"}},h(le,{modelValue:e.searchText,"onUpdate:modelValue":t=>e.onSearchChange(t),placeholder:"Search for a person...",density:"compact",variant:"outlined",hideDetails:true,autocomplete:"off",prependInnerIcon:"mdi-magnify",onKeydown:t=>t.stopPropagation()})),h("div",{style:{maxHeight:"240px",overflowY:"auto"}},e.isLoading&&e.searchText.trim()?h("div",{style:{display:"flex",justifyContent:"center",padding:"16px 0"}},h(se,{size:24,indeterminate:true})):e.suggestions.length===0&&e.searchText.trim()?h("div",{style:{padding:"16px 0",textAlign:"center",fontSize:"0.875rem",color:"rgba(0,0,0,0.6)"}},"No results found"):e.searchText.trim()?e.suggestions.map(t=>h("div",{key:t.id||t.email||t.displayName,style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 12px",cursor:"pointer"},onClick:()=>e.onUserSelect(t),onMouseenter:a=>{a.currentTarget.style.backgroundColor="rgba(0,0,0,0.04)";},onMouseleave:a=>{a.currentTarget.style.backgroundColor="";}},[h(M,{size:32,image:t.photo},()=>t.displayName?.[0]??""),h("div",{style:{flex:"1",minWidth:"0"}},[h("div",{style:{fontSize:"0.875rem",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},t.displayName),h("div",{style:{fontSize:"0.75rem",color:"rgba(0,0,0,0.6)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},t.email)])])):h("div",{style:{padding:"16px 0",textAlign:"center",fontSize:"0.875rem",color:"rgba(0,0,0,0.6)"}},"Type to search...")),...e.selectedUser?[h(ue),h("div",{style:{padding:"8px 12px"}},h(E,{size:"small",variant:"text",block:true,onClick:e.onClearUser},()=>"Clear Filter"))]:[]])}});var ve=VBtn,xe=VIcon,he=VMenu,Se=VTooltip,Pe=VCard,f=defineComponent({name:"ColumnHeaderFilter",props:{columnKey:{type:String,required:true},columnName:{type:String,required:true},filterType:{type:String,required:true},isSorted:{type:Boolean,default:false},isSortedDescending:{type:Boolean,default:false},onSort:{type:Function,default:void 0},selectedValues:{type:Array,default:void 0},onFilterChange:{type:Function,default:void 0},options:{type:Array,default:()=>[]},isLoadingOptions:{type:Boolean,default:false},textValue:{type:String,default:""},onTextChange:{type:Function,default:void 0},selectedUser:{type:Object,default:void 0},onUserChange:{type:Function,default:void 0},peopleSearch:{type:Function,default:void 0},dateValue:{type:Object,default:void 0},onDateChange:{type:Function,default:void 0}},setup(e){let t=useColumnHeaderFilterState(e),a=()=>e.filterType==="multiSelect"?h(D,{searchText:t.searchText.value,onSearchChange:t.setSearchText,options:e.options??[],filteredOptions:t.filteredOptions.value,selected:t.tempSelected.value,onOptionToggle:t.handlers.handleCheckboxChange,onSelectAll:t.handlers.handleSelectAll,onClearSelection:t.handlers.handleClearSelection,onApply:t.handlers.handleApplyMultiSelect,isLoading:e.isLoadingOptions}):e.filterType==="text"?h(R,{value:t.tempTextValue.value??"",onValueChange:t.setTempTextValue,onApply:t.handlers.handleTextApply,onClear:t.handlers.handleTextClear}):e.filterType==="people"?h(k,{selectedUser:e.selectedUser,searchText:t.peopleSearchText.value,onSearchChange:t.setPeopleSearchText,suggestions:t.peopleSuggestions.value,isLoading:t.isPeopleLoading.value,onUserSelect:t.handlers.handleUserSelect,onClearUser:t.handlers.handleClearUser}):e.filterType==="date"?h("div",{style:{padding:"12px",display:"flex",flexDirection:"column",gap:"8px"}},[h("div",{style:{display:"flex",alignItems:"center",gap:"8px"}},[h("span",{style:{minWidth:"36px",fontSize:"0.75rem"}},"From:"),h("input",{type:"date",value:t.tempDateFrom.value??"",onInput:o=>t.setTempDateFrom(o.target.value),style:{flex:"1",padding:"4px 6px"}})]),h("div",{style:{display:"flex",alignItems:"center",gap:"8px"}},[h("span",{style:{minWidth:"36px",fontSize:"0.75rem"}},"To:"),h("input",{type:"date",value:t.tempDateTo.value??"",onInput:o=>t.setTempDateTo(o.target.value),style:{flex:"1",padding:"4px 6px"}})]),h("div",{style:{display:"flex",justifyContent:"flex-end",gap:"8px",marginTop:"4px"}},[h("button",{onClick:t.handlers.handleDateClear,disabled:!t.tempDateFrom.value&&!t.tempDateTo.value,style:{padding:"4px 12px",cursor:"pointer"}},"Clear"),h("button",{onClick:t.handlers.handleDateApply,style:{padding:"4px 12px",cursor:"pointer"}},"Apply")])]):null;return ()=>h("div",{ref:o=>{t.headerRef.value=o;},style:{display:"flex",alignItems:"center",width:"100%",minWidth:"0"}},[h("div",{style:{flex:"1",minWidth:"0",overflow:"hidden"}},h(Se,{text:e.columnName,location:"top"},{activator:({props:o})=>h("span",{...o,"data-header-label":"",style:{fontWeight:"600",fontSize:"0.875rem",lineHeight:"1.4",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",display:"block"}},e.columnName)})),h("div",{style:{display:"flex",alignItems:"center",marginLeft:"4px",flexShrink:"0"}},[...e.filterType!=="none"?[h(he,{modelValue:t.isFilterOpen.value,"onUpdate:modelValue":o=>t.setFilterOpen(o),closeOnContentClick:false,location:"bottom start"},{activator:({props:o})=>h("div",{style:{position:"relative"}},[h(ve,{...o,icon:true,size:"x-small",variant:t.hasActiveFilter.value||t.isFilterOpen.value?"tonal":"text",color:t.hasActiveFilter.value||t.isFilterOpen.value?"primary":"default","aria-label":`Filter ${e.columnName}`,"aria-expanded":t.isFilterOpen.value,"aria-haspopup":"dialog",title:`Filter ${e.columnName}`,style:{opacity:t.hasActiveFilter.value||t.isFilterOpen.value?"1":"0.7"}},()=>h(xe,{size:"16"},()=>"mdi-filter-variant")),...t.hasActiveFilter.value?[h("div",{style:{position:"absolute",top:"2px",right:"2px",width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"rgb(var(--v-theme-primary))",zIndex:"1"}})]:[]]),default:()=>h(Pe,{elevation:8,ref:o=>{t.popoverRef.value=o;},onClick:o=>o.stopPropagation()},()=>[h("div",{style:{borderBottom:"1px solid rgba(0,0,0,0.12)",padding:"8px 12px",fontWeight:"600",fontSize:"0.875rem",backgroundColor:"rgb(var(--v-theme-surface))"}},`Filter: ${e.columnName}`),a()])})]:[]])])}});var S=defineComponent({name:"ColumnHeaderMenu",props:{isOpen:{type:Boolean,required:true},anchorElement:{type:Object,default:null},onClose:{type:Function,required:true},onPinLeft:{type:Function,required:true},onPinRight:{type:Function,required:true},onUnpin:{type:Function,required:true},onSortAsc:{type:Function,required:true},onSortDesc:{type:Function,required:true},onClearSort:{type:Function,required:true},onAutosizeThis:{type:Function,required:true},onAutosizeAll:{type:Function,required:true},canPinLeft:{type:Boolean,required:true},canPinRight:{type:Boolean,required:true},canUnpin:{type:Boolean,required:true},currentSort:{type:String,default:null},isSortable:{type:Boolean,default:true},isResizable:{type:Boolean,default:true}},setup(e){let t=p=>{p||e.onClose();},a=computed(()=>getColumnHeaderMenuItems({canPinLeft:e.canPinLeft,canPinRight:e.canPinRight,canUnpin:e.canUnpin,currentSort:e.currentSort,isSortable:e.isSortable,isResizable:e.isResizable})),o={pinLeft:e.onPinLeft,pinRight:e.onPinRight,unpin:e.onUnpin,sortAsc:e.onSortAsc,sortDesc:e.onSortDesc,clearSort:e.onClearSort,autosizeThis:e.onAutosizeThis,autosizeAll:e.onAutosizeAll},i=p=>o[p]||(()=>{});return ()=>e.anchorElement?h(VMenu,{modelValue:e.isOpen,"onUpdate:modelValue":t,location:"bottom start",target:e.anchorElement},{default:()=>h(VList,{density:"compact","aria-label":"Column options"},()=>{let p=[];return a.value.forEach(d=>{p.push(h(VListItem,{key:d.id,disabled:d.disabled,onClick:()=>{i(d.id)();}},()=>d.label)),d.divider&&p.push(h(VDivider,{key:`divider-${d.id}`}));}),p})}):null}});var P=createInlineCellEditor({renderCheckbox:({checked:e,onChange:t,onCancel:a})=>h(VCheckbox,{modelValue:e,hideDetails:true,density:"compact","onUpdate:modelValue":o=>t(o),onKeydown:o=>{o.key==="Escape"&&(o.preventDefault(),a());}}),renderDatePicker:({value:e,onChange:t,onCancel:a})=>h("input",{type:"date",value:e,style:{width:"100%",height:"100%",border:"none",outline:"none",padding:"0 4px",fontSize:"inherit"},onVnodeMounted:o=>{let i=o.el;if(i){i.focus();try{i.showPicker();}catch{}}},onKeydown:o=>{o.key==="Enter"&&(o.preventDefault(),t(o.target.value)),o.key==="Escape"&&(o.preventDefault(),a()),o.key==="Tab"&&(o.preventDefault(),t(o.target.value));},onBlur:o=>t(o.target.value)})});var b=defineComponent({name:"GridContextMenu",props:{x:{type:Number,required:true},y:{type:Number,required:true},hasSelection:{type:Boolean,required:true},canUndo:{type:Boolean,required:true},canRedo:{type:Boolean,required:true},onUndo:{type:Function,required:true},onRedo:{type:Function,required:true},onCopy:{type:Function,required:true},onCut:{type:Function,required:true},onPaste:{type:Function,required:true},onSelectAll:{type:Function,required:true},onClose:{type:Function,required:true}},setup(e){let t=getContextMenuHandlers(e),a=o=>!!(o.disabledWhenNoSelection&&!e.hasSelection||o.id==="undo"&&!e.canUndo||o.id==="redo"&&!e.canRedo);return ()=>h(VMenu,{modelValue:true,"onUpdate:modelValue":o=>{o||e.onClose();},target:[e.x,e.y],location:"bottom start"},{default:()=>h(VList,{density:"compact","aria-label":"Grid context menu"},()=>GRID_CONTEXT_MENU_ITEMS.map(o=>[...o.dividerBefore?[h(VDivider,{key:`${o.id}-div`})]:[],h(VListItem,{key:o.id,disabled:a(o),onClick:()=>{t[o.id]();}},()=>h("div",{style:{display:"flex",alignItems:"center",width:"100%"}},[h("span",{style:{flex:"1"}},o.label),...o.shortcut?[h("span",{style:{marginLeft:"24px",color:"rgba(0,0,0,0.4)",fontSize:"0.8em"}},formatShortcut(o.shortcut))]:[]]))]).flat())})}});function O({emptyState:e}){return h("div",{class:"ogrid-empty-state"},e.render?[e.render()]:[h("div",{class:"ogrid-empty-state-title"},"No results found"),h("div",{class:"ogrid-empty-state-message"},e.message!=null?String(e.message):e.hasActiveFilters?["No items match your current filters. Try adjusting your search or ",h(VBtn,{variant:"text",size:"small",onClick:e.onClearAll},()=>"clear all filters")," to see all items."]:"There are no items available at this time.")])}var T=createDataGridTable({renderCheckbox:({modelValue:e,indeterminate:t,ariaLabel:a,onChange:o})=>h(VCheckbox,{modelValue:e,indeterminate:t,hideDetails:true,density:"compact","aria-label":a,"onUpdate:modelValue":i=>o(!!i)}),renderSpinner:e=>h("div",{class:"ogrid-loading-inner"},[h(VProgressCircular,{size:24,indeterminate:true}),h("span",{class:"ogrid-loading-message"},e)]),ColumnHeaderFilter:f,ColumnHeaderMenu:S,InlineCellEditor:P,GridContextMenu:b,renderEmptyState:e=>O({emptyState:e})});var F=defineComponent({name:"ColumnChooser",props:{columns:{type:Array,required:true},visibleColumns:{type:Object,required:true},onVisibilityChange:{type:Function,required:true}},setup(e){let t=computed(()=>e.columns),a=computed(()=>e.visibleColumns),o=useColumnChooserState({columns:t,visibleColumns:a,onVisibilityChange:e.onVisibilityChange});return ()=>h(VMenu,{modelValue:o.open.value,"onUpdate:modelValue":i=>{o.setOpen(i);},closeOnContentClick:false,location:"bottom end"},{activator:({props:i})=>h(VBtn,{...i,variant:"outlined",size:"small",prependIcon:"mdi-view-column",appendIcon:o.open.value?"mdi-chevron-up":"mdi-chevron-down"},()=>`Column Visibility (${o.visibleCount.value} of ${o.totalCount.value})`),default:()=>h("div",{style:{minWidth:"220px"}},[h("div",{style:{padding:"8px 12px",borderBottom:"1px solid rgba(0,0,0,0.12)",backgroundColor:"rgba(0,0,0,0.04)",fontWeight:"600",fontSize:"0.875rem"}},`Select Columns (${o.visibleCount.value} of ${o.totalCount.value})`),h(VList,{density:"compact",style:{maxHeight:"320px",overflowY:"auto"}},()=>e.columns.map(i=>h(VListItem,{key:i.columnId,style:{minHeight:"32px"}},()=>h("label",{style:{display:"flex",alignItems:"center",gap:"8px",cursor:"pointer",width:"100%"}},[h("input",{type:"checkbox",checked:e.visibleColumns.has(i.columnId),onChange:p=>o.handleCheckboxChange(i.columnId)(p.target.checked)}),h("span",{style:{fontSize:"0.875rem"}},i.name)])))),h(VDivider),h("div",{style:{display:"flex",justifyContent:"flex-end",gap:"8px",padding:"8px 12px",backgroundColor:"rgba(0,0,0,0.04)"}},[h(VBtn,{size:"small",variant:"text",onClick:o.handleClearAll},()=>"Clear All"),h(VBtn,{size:"small",variant:"flat",color:"primary",onClick:o.handleSelectAll},()=>"Select All")])])})}});var U=defineComponent({name:"PaginationControls",props:{currentPage:{type:Number,required:true},pageSize:{type:Number,required:true},totalCount:{type:Number,required:true},onPageChange:{type:Function,required:true},onPageSizeChange:{type:Function,required:true},pageSizeOptions:{type:Array,default:void 0},entityLabelPlural:{type:String,default:"items"}},setup(e){let t=computed(()=>getPaginationViewModel(e.currentPage,e.pageSize,e.totalCount,e.pageSizeOptions?{pageSizeOptions:e.pageSizeOptions}:void 0));return ()=>{let a=t.value;if(!a)return null;let{pageNumbers:o,showStartEllipsis:i,showEndEllipsis:p,totalPages:d,startItem:z,endItem:H}=a,L=e.entityLabelPlural??"items";return h("div",{role:"navigation","aria-label":"Pagination",style:{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:"16px",padding:"0 12px",width:"100%",minWidth:"0",boxSizing:"border-box"}},[h("span",{style:{fontSize:"0.875rem",color:"var(--ogrid-fg-secondary, rgba(0,0,0,0.6))"}},`Showing ${z} to ${H} of ${e.totalCount.toLocaleString()} ${L}`),h("div",{style:{display:"flex",alignItems:"center",gap:"4px"}},[h(VBtn,{icon:"mdi-page-first",size:"small",variant:"text",disabled:e.currentPage===1,"aria-label":"First page",onClick:()=>e.onPageChange(1)}),h(VBtn,{icon:"mdi-chevron-left",size:"small",variant:"text",disabled:e.currentPage===1,"aria-label":"Previous page",onClick:()=>e.onPageChange(e.currentPage-1)}),...i?[h(VBtn,{size:"small",variant:"outlined","aria-label":"Page 1",style:{minWidth:"32px"},onClick:()=>e.onPageChange(1)},()=>"1"),h("span",{style:{margin:"0 4px",color:"var(--ogrid-fg-secondary, rgba(0,0,0,0.6))"},"aria-hidden":"true"},"\u2026")]:[],...o.map(m=>h(VBtn,{key:m,size:"small",variant:e.currentPage===m?"flat":"outlined",color:e.currentPage===m?"primary":void 0,"aria-label":`Page ${m}`,"aria-current":e.currentPage===m?"page":void 0,style:{minWidth:"32px"},onClick:()=>e.onPageChange(m)},()=>String(m))),...p?[h("span",{style:{margin:"0 4px",color:"var(--ogrid-fg-secondary, rgba(0,0,0,0.6))"},"aria-hidden":"true"},"\u2026"),h(VBtn,{size:"small",variant:"outlined","aria-label":`Page ${d}`,style:{minWidth:"32px"},onClick:()=>e.onPageChange(d)},()=>String(d))]:[],h(VBtn,{icon:"mdi-chevron-right",size:"small",variant:"text",disabled:e.currentPage>=d,"aria-label":"Next page",onClick:()=>e.onPageChange(e.currentPage+1)}),h(VBtn,{icon:"mdi-page-last",size:"small",variant:"text",disabled:e.currentPage>=d,"aria-label":"Last page",onClick:()=>e.onPageChange(d)})]),h("div",{style:{display:"flex",alignItems:"center",gap:"8px"}},[h("span",{style:{fontSize:"0.875rem",color:"var(--ogrid-fg-secondary, rgba(0,0,0,0.6))"}},"Rows"),h(VSelect,{modelValue:e.pageSize,items:a.pageSizeOptions,density:"compact",hideDetails:true,variant:"outlined","aria-label":"Rows per page",style:{minWidth:"70px",maxWidth:"90px"},"onUpdate:modelValue":m=>e.onPageSizeChange(Number(m))})])])}}});var tt=createOGrid({DataGridTable:T,ColumnChooser:F,PaginationControls:U});export{F as ColumnChooser,f as ColumnHeaderFilter,S as ColumnHeaderMenu,T as DataGridTable,b as GridContextMenu,P as InlineCellEditor,tt as OGrid,U as PaginationControls};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alaarab/ogrid-vue-vuetify",
3
- "version": "2.4.2",
3
+ "version": "2.5.0",
4
4
  "description": "OGrid Vuetify – Vuetify-based data grid with sorting, filtering, pagination, column chooser, and CSV export.",
5
5
  "main": "dist/esm/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -38,7 +38,7 @@
38
38
  "node": ">=18"
39
39
  },
40
40
  "dependencies": {
41
- "@alaarab/ogrid-vue": "2.4.2"
41
+ "@alaarab/ogrid-vue": "2.5.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "vue": "^3.3.0",