@bagelink/vue 1.5.17 → 1.5.22
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/bin/experimentalGenTypedRoutes.ts +15 -15
- package/bin/generateFormSchema.ts +12 -12
- package/bin/utils.ts +4 -4
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/calendar/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/form/BagelForm.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts +5 -4
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/CheckInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText/index.vue.d.ts +1 -0
- package/dist/components/form/inputs/RichText/index.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ToggleInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/composables/useFormField.d.ts.map +1 -1
- package/dist/composables/useSchemaField.d.ts.map +1 -1
- package/dist/index.cjs +17 -14
- package/dist/index.mjs +511 -422
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/AccordionItem.vue +2 -2
- package/src/components/AddToCalendar.vue +1 -1
- package/src/components/BglVideo.vue +8 -8
- package/src/components/Btn.vue +9 -9
- package/src/components/Card.vue +4 -4
- package/src/components/Carousel.vue +44 -44
- package/src/components/DataPreview.vue +1 -1
- package/src/components/DragOver.vue +6 -6
- package/src/components/Dropdown.vue +14 -14
- package/src/components/Flag.vue +3 -3
- package/src/components/Icon/Icon.vue +13 -13
- package/src/components/Image.vue +4 -4
- package/src/components/ImportData.vue +79 -79
- package/src/components/ListItem.vue +7 -7
- package/src/components/MapEmbed/Index.vue +6 -6
- package/src/components/Modal.vue +10 -10
- package/src/components/ModalForm.vue +4 -4
- package/src/components/NavBar.vue +2 -2
- package/src/components/Pagination.vue +9 -9
- package/src/components/Pill.vue +1 -1
- package/src/components/Rating.vue +2 -2
- package/src/components/Slider.vue +77 -77
- package/src/components/Spreadsheet/Index.vue +34 -34
- package/src/components/Spreadsheet/SpreadsheetTable.vue +3 -3
- package/src/components/Zoomer.vue +28 -28
- package/src/components/analytics/BarChart.vue +6 -6
- package/src/components/analytics/KpiCard.vue +2 -2
- package/src/components/analytics/LineChart.vue +14 -14
- package/src/components/analytics/PieChart.vue +11 -11
- package/src/components/calendar/CalendarPopover.vue +1 -1
- package/src/components/calendar/Index.vue +1 -1
- package/src/components/calendar/views/AgendaView.vue +2 -2
- package/src/components/calendar/views/DayView.vue +6 -6
- package/src/components/calendar/views/MonthView.vue +2 -2
- package/src/components/calendar/views/WeekView.vue +18 -18
- package/src/components/dataTable/DataTable.vue +3 -3
- package/src/components/dataTable/useSorting.ts +1 -1
- package/src/components/dataTable/useTableData.ts +15 -15
- package/src/components/dataTable/useTableSelection.ts +8 -8
- package/src/components/dataTable/useTableVirtualization.ts +1 -1
- package/src/components/draggable/useDraggable.ts +42 -42
- package/src/components/form/BagelForm.vue +66 -23
- package/src/components/form/BglMultiStepForm.vue +18 -18
- package/src/components/form/FieldArray.vue +177 -67
- package/src/components/form/inputs/CheckInput.vue +2 -1
- package/src/components/form/inputs/CodeEditor/Index.vue +1 -1
- package/src/components/form/inputs/CodeEditor/format.ts +7 -7
- package/src/components/form/inputs/CodeEditor/useHighlight.ts +6 -6
- package/src/components/form/inputs/DateInput.vue +6 -6
- package/src/components/form/inputs/DatePicker.vue +19 -19
- package/src/components/form/inputs/EmailInput.vue +14 -14
- package/src/components/form/inputs/NumberInput.vue +6 -6
- package/src/components/form/inputs/OTP.vue +3 -3
- package/src/components/form/inputs/RadioGroup.vue +1 -1
- package/src/components/form/inputs/RadioPillsInput.vue +8 -8
- package/src/components/form/inputs/RichText/components/EditorToolbar.vue +10 -10
- package/src/components/form/inputs/RichText/components/TableGridSelector.vue +1 -1
- package/src/components/form/inputs/RichText/composables/useCommands.ts +1 -1
- package/src/components/form/inputs/RichText/composables/useEditor.ts +12 -12
- package/src/components/form/inputs/RichText/composables/useEditorKeyboard.ts +1 -1
- package/src/components/form/inputs/RichText/index.vue +143 -134
- package/src/components/form/inputs/RichText/utils/commands.ts +69 -69
- package/src/components/form/inputs/RichText/utils/debug.ts +1 -1
- package/src/components/form/inputs/RichText/utils/formatting.ts +39 -39
- package/src/components/form/inputs/RichText/utils/media.ts +6 -6
- package/src/components/form/inputs/RichText/utils/selection.ts +28 -28
- package/src/components/form/inputs/RichText/utils/table.ts +19 -19
- package/src/components/form/inputs/SelectBtn.vue +1 -1
- package/src/components/form/inputs/SelectInput.vue +50 -26
- package/src/components/form/inputs/SignaturePad.vue +15 -15
- package/src/components/form/inputs/TableField.vue +1 -1
- package/src/components/form/inputs/TelInput.vue +6 -6
- package/src/components/form/inputs/TextInput.vue +5 -5
- package/src/components/form/inputs/ToggleInput.vue +2 -1
- package/src/components/form/inputs/Upload/UploadInput.vue +155 -102
- package/src/components/form/inputs/Upload/upload.ts +1 -1
- package/src/components/form/inputs/Upload/useFileUpload.ts +6 -6
- package/src/components/form/useBagelFormState.ts +5 -5
- package/src/components/layout/AppContent.vue +1 -1
- package/src/components/layout/AppLayout.vue +1 -1
- package/src/components/layout/Layout.vue +4 -4
- package/src/components/layout/TabbedLayout.vue +1 -1
- package/src/components/layout/Tabs.vue +2 -2
- package/src/components/layout/TabsNav.vue +7 -7
- package/src/components/lightbox/Lightbox.vue +8 -8
- package/src/components/lightbox/index.ts +8 -8
- package/src/composables/index.ts +2 -2
- package/src/composables/useAddToCalendar.ts +13 -13
- package/src/composables/useDevice.ts +2 -2
- package/src/composables/useExcel.ts +6 -6
- package/src/composables/useFormField.ts +5 -9
- package/src/composables/usePolling.ts +8 -8
- package/src/composables/useSchemaField.ts +53 -38
- package/src/composables/useTheme.ts +9 -9
- package/src/composables/useValidateFieldValue.ts +2 -2
- package/src/directives/pattern.ts +25 -25
- package/src/directives/ripple.ts +4 -4
- package/src/directives/vResize.ts +6 -6
- package/src/plugins/bagel.ts +4 -4
- package/src/plugins/useModal.ts +3 -3
- package/src/styles/layout.css +7 -1
- package/src/utils/BagelFormUtils.ts +7 -7
- package/src/utils/calendar/Helpers.ts +8 -8
- package/src/utils/calendar/dateUtils.ts +22 -22
- package/src/utils/calendar/time.ts +25 -25
- package/src/utils/calendar/week.ts +25 -25
- package/src/utils/elementUtils.ts +27 -27
- package/src/utils/index.ts +22 -22
- package/src/utils/sizeParsing.ts +2 -2
- package/src/utils/strings.ts +5 -5
- package/src/utils/tapDetector.ts +11 -11
- package/src/utils/useSearch.ts +29 -29
- package/vite.config.ts +1 -1
|
@@ -38,7 +38,7 @@ function flattenObject(obj: { [key: string]: any }, prefix = ''): { [key: string
|
|
|
38
38
|
const value = obj[key]
|
|
39
39
|
const newKey = prefix ? `${prefix}.${key}` : key
|
|
40
40
|
|
|
41
|
-
if (value && typeof value
|
|
41
|
+
if (value && 'object' === typeof value && !Array.isArray(value)) {
|
|
42
42
|
Object.assign(flattened, flattenObject(value, newKey))
|
|
43
43
|
} else {
|
|
44
44
|
flattened[newKey] = value
|
|
@@ -132,7 +132,7 @@ const columns = computed(() => {
|
|
|
132
132
|
|
|
133
133
|
// Format cell value based on column configuration
|
|
134
134
|
function formatCellValue(value: any, format?: ColumnFormat): string {
|
|
135
|
-
if (
|
|
135
|
+
if (null === value || value === undefined) {return ''}
|
|
136
136
|
|
|
137
137
|
switch (format) {
|
|
138
138
|
case 'image':
|
|
@@ -162,15 +162,15 @@ function formatCellValue(value: any, format?: ColumnFormat): string {
|
|
|
162
162
|
function parseValueForFormat(value: string | boolean, format?: ColumnFormat): any {
|
|
163
163
|
switch (format) {
|
|
164
164
|
case 'boolean':
|
|
165
|
-
return
|
|
165
|
+
return 'boolean' === typeof value ? value : 'true' === value
|
|
166
166
|
case 'number':
|
|
167
167
|
case 'percentage':
|
|
168
168
|
case 'currency':
|
|
169
|
-
if (typeof value
|
|
170
|
-
return
|
|
169
|
+
if ('boolean' === typeof value) {return null}
|
|
170
|
+
return '' === value ? null : Number(String(value).replace(/[^0-9.-]/g, ''))
|
|
171
171
|
case 'date':
|
|
172
|
-
if (typeof value
|
|
173
|
-
return
|
|
172
|
+
if ('boolean' === typeof value) {return null}
|
|
173
|
+
return '' === value ? null : new Date(String(value)).toISOString()
|
|
174
174
|
default:
|
|
175
175
|
return String(value)
|
|
176
176
|
}
|
|
@@ -185,10 +185,10 @@ function isCellEditable(columnKey: string): boolean {
|
|
|
185
185
|
// Update the sortByColumn function to preserve column visibility
|
|
186
186
|
function sortByColumn(columnKey: string) {
|
|
187
187
|
const column = columns.value.find(col => col.key === columnKey)
|
|
188
|
-
if (!column?.sortable) return
|
|
188
|
+
if (!column?.sortable) {return}
|
|
189
189
|
|
|
190
190
|
if (sortColumn.value === columnKey) {
|
|
191
|
-
sortDirection.value = sortDirection.value
|
|
191
|
+
sortDirection.value = 'desc' === sortDirection.value ? 'asc' : 'desc'
|
|
192
192
|
} else {
|
|
193
193
|
sortColumn.value = columnKey
|
|
194
194
|
sortDirection.value = 'desc'
|
|
@@ -198,11 +198,11 @@ function sortByColumn(columnKey: string) {
|
|
|
198
198
|
const aVal = a[columnKey]
|
|
199
199
|
const bVal = b[columnKey]
|
|
200
200
|
|
|
201
|
-
if (aVal === bVal) return 0
|
|
202
|
-
if (
|
|
203
|
-
if (
|
|
201
|
+
if (aVal === bVal) {return 0}
|
|
202
|
+
if (null === aVal || aVal === undefined) {return 1}
|
|
203
|
+
if (null === bVal || bVal === undefined) {return -1}
|
|
204
204
|
|
|
205
|
-
const modifier = sortDirection.value
|
|
205
|
+
const modifier = 'desc' === sortDirection.value ? 1 : -1
|
|
206
206
|
return aVal < bVal ? -modifier : modifier
|
|
207
207
|
})
|
|
208
208
|
|
|
@@ -360,12 +360,12 @@ function redo() {
|
|
|
360
360
|
// Update updateCell to use undo stack
|
|
361
361
|
function updateCell(rowIndex: number, key: string, newValue: string | boolean) {
|
|
362
362
|
const column = columns.value.find(col => col.key === key)
|
|
363
|
-
if (column?.locked) return
|
|
363
|
+
if (column?.locked) {return}
|
|
364
364
|
|
|
365
365
|
saveState('cell')
|
|
366
366
|
const parsedValue = parseValueForFormat(newValue, column?.format)
|
|
367
367
|
// If the parsed value is null/undefined, use the default value
|
|
368
|
-
localRows.value[rowIndex][key] = parsedValue ?? column?.defaultValue ?? (column?.format
|
|
368
|
+
localRows.value[rowIndex][key] = parsedValue ?? column?.defaultValue ?? ('boolean' === column?.format ? false : '')
|
|
369
369
|
emitUpdate()
|
|
370
370
|
}
|
|
371
371
|
|
|
@@ -375,7 +375,7 @@ function updateCell(rowIndex: number, key: string, newValue: string | boolean) {
|
|
|
375
375
|
// After the columns computed property
|
|
376
376
|
// Initialize visibleColumns with all columns when columns change
|
|
377
377
|
watch(() => columns.value, (newColumns) => {
|
|
378
|
-
if (newColumns.length
|
|
378
|
+
if (0 < newColumns.length && 0 === visibleColumns.value.length) {
|
|
379
379
|
visibleColumns.value = newColumns.filter(col => !col.hidden).map(col => col.key)
|
|
380
380
|
}
|
|
381
381
|
})
|
|
@@ -398,7 +398,7 @@ function createEmptyRow(): { [key: string]: any } {
|
|
|
398
398
|
if (col.defaultValue !== undefined) {
|
|
399
399
|
newRow[col.key] = col.defaultValue
|
|
400
400
|
} else {
|
|
401
|
-
newRow[col.key] = col.format
|
|
401
|
+
newRow[col.key] = 'boolean' === col.format ? false : ''
|
|
402
402
|
}
|
|
403
403
|
})
|
|
404
404
|
return newRow
|
|
@@ -415,7 +415,7 @@ function addRow() {
|
|
|
415
415
|
|
|
416
416
|
// Copy function using Navigator Clipboard API
|
|
417
417
|
async function copySelection() {
|
|
418
|
-
if (!selectionStart.value || !selectionEnd.value) return
|
|
418
|
+
if (!selectionStart.value || !selectionEnd.value) {return}
|
|
419
419
|
|
|
420
420
|
const startRow = Math.min(selectionStart.value.row, selectionEnd.value.row)
|
|
421
421
|
const endRow = Math.max(selectionStart.value.row, selectionEnd.value.row)
|
|
@@ -454,7 +454,7 @@ function isSearchFocused(): boolean {
|
|
|
454
454
|
|
|
455
455
|
// Update the pasteSelection function to handle search focus
|
|
456
456
|
async function pasteSelection() {
|
|
457
|
-
if (!selectionStart.value) return
|
|
457
|
+
if (!selectionStart.value) {return}
|
|
458
458
|
|
|
459
459
|
try {
|
|
460
460
|
const clipboardText = await navigator.clipboard.readText()
|
|
@@ -467,7 +467,7 @@ async function pasteSelection() {
|
|
|
467
467
|
|
|
468
468
|
// Calculate how many new rows we need to add
|
|
469
469
|
const neededRows = startRow + rows.length - localRows.value.length
|
|
470
|
-
if (
|
|
470
|
+
if (0 < neededRows) {
|
|
471
471
|
// Add the required number of new rows
|
|
472
472
|
for (let i = 0; i < neededRows; i++) {
|
|
473
473
|
localRows.value.push(createEmptyRow())
|
|
@@ -479,10 +479,10 @@ async function pasteSelection() {
|
|
|
479
479
|
const targetRow = startRow + rowIndex
|
|
480
480
|
rowData.forEach((cellValue, colIndex) => {
|
|
481
481
|
const targetCol = startCol + colIndex
|
|
482
|
-
if (targetCol >= columns.value.length) return
|
|
482
|
+
if (targetCol >= columns.value.length) {return}
|
|
483
483
|
|
|
484
484
|
const columnKey = columns.value[targetCol].key
|
|
485
|
-
if (!isCellEditable(columnKey)) return
|
|
485
|
+
if (!isCellEditable(columnKey)) {return}
|
|
486
486
|
|
|
487
487
|
const { format } = columns.value[targetCol]
|
|
488
488
|
localRows.value[targetRow][columnKey] = parseValueForFormat(cellValue, format)
|
|
@@ -501,10 +501,10 @@ const editingOriginalValue = ref<string | null>(null)
|
|
|
501
501
|
// Update the startEditing function to handle focus properly
|
|
502
502
|
function startEditing(row: number, col: number, initialKey?: string) {
|
|
503
503
|
const columnKey = columns.value[col]?.key
|
|
504
|
-
if (!columnKey) return
|
|
504
|
+
if (!columnKey) {return}
|
|
505
505
|
|
|
506
506
|
// Only check editability when we're actually going to edit
|
|
507
|
-
if (initialKey !== undefined && !isCellEditable(columnKey)) return
|
|
507
|
+
if (initialKey !== undefined && !isCellEditable(columnKey)) {return}
|
|
508
508
|
|
|
509
509
|
editingCell.value = { row, col }
|
|
510
510
|
editingOriginalValue.value = localRows.value[row][columnKey]?.toString() ?? ''
|
|
@@ -529,7 +529,7 @@ function startEditing(row: number, col: number, initialKey?: string) {
|
|
|
529
529
|
|
|
530
530
|
// Update the stopEditing function to handle cancellation
|
|
531
531
|
function stopEditing(cancelled = false) {
|
|
532
|
-
if (cancelled && editingCell.value && editingOriginalValue.value
|
|
532
|
+
if (cancelled && editingCell.value && null !== editingOriginalValue.value) {
|
|
533
533
|
const { row, col } = editingCell.value
|
|
534
534
|
const columnKey = columns.value[col]?.key
|
|
535
535
|
if (columnKey) {
|
|
@@ -567,9 +567,9 @@ function handleCellKeyDown(event: KeyboardEvent, row: number, col: number) {
|
|
|
567
567
|
// If this cell is not already in edit mode
|
|
568
568
|
if (!(editingCell.value && editingCell.value.row === row && editingCell.value.col === col)) {
|
|
569
569
|
// Start editing if a printable character or Enter is pressed
|
|
570
|
-
if ((event.key.length
|
|
570
|
+
if ((1 === event.key.length && !event.ctrlKey && !event.metaKey) || 'Enter' === event.key) {
|
|
571
571
|
event.preventDefault()
|
|
572
|
-
startEditing(row, col, event.key.length
|
|
572
|
+
startEditing(row, col, 1 === event.key.length ? event.key : undefined)
|
|
573
573
|
}
|
|
574
574
|
}
|
|
575
575
|
}
|
|
@@ -577,7 +577,7 @@ function handleCellKeyDown(event: KeyboardEvent, row: number, col: number) {
|
|
|
577
577
|
// Update keyboard shortcuts to include undo/redo
|
|
578
578
|
function handleSpreadsheetKeyDown(event: KeyboardEvent) {
|
|
579
579
|
// Don't intercept keyboard shortcuts when editing a cell
|
|
580
|
-
if (editingCell.value || isSearchFocused()) return
|
|
580
|
+
if (editingCell.value || isSearchFocused()) {return}
|
|
581
581
|
console.log('handleSpreadsheetKeyDown', event)
|
|
582
582
|
const isCtrlOrCmd = event.ctrlKey || event.metaKey
|
|
583
583
|
|
|
@@ -608,21 +608,21 @@ function handleSpreadsheetKeyDown(event: KeyboardEvent) {
|
|
|
608
608
|
}
|
|
609
609
|
|
|
610
610
|
// Add computed properties for undo/redo stack state
|
|
611
|
-
const canUndo = computed(() => undoStack.value.length
|
|
612
|
-
const canRedo = computed(() => redoStack.value.length
|
|
611
|
+
const canUndo = computed(() => 0 < undoStack.value.length)
|
|
612
|
+
const canRedo = computed(() => 0 < redoStack.value.length)
|
|
613
613
|
|
|
614
614
|
// Add after other ref declarations
|
|
615
615
|
const search = ref('')
|
|
616
616
|
|
|
617
617
|
// Add the filteredRows computed property after the columns computed
|
|
618
618
|
const filteredRows = computed(() => {
|
|
619
|
-
if (!search.value) return localRows.value
|
|
619
|
+
if (!search.value) {return localRows.value}
|
|
620
620
|
|
|
621
621
|
const searchTerm = search.value.toLowerCase()
|
|
622
622
|
return localRows.value.filter((row) => {
|
|
623
623
|
// Check all values in the row, including hidden columns
|
|
624
624
|
return Object.values(row).some((value) => {
|
|
625
|
-
if (
|
|
625
|
+
if (null === value || value === undefined) {return false}
|
|
626
626
|
return String(value).toLowerCase().includes(searchTerm)
|
|
627
627
|
})
|
|
628
628
|
})
|
|
@@ -643,7 +643,7 @@ function handleResizeStart(e: MouseEvent, columnKey: string) {
|
|
|
643
643
|
|
|
644
644
|
// Find the column header element
|
|
645
645
|
const columnHeader = (e.target as HTMLElement).closest('th')
|
|
646
|
-
if (!columnHeader) return
|
|
646
|
+
if (!columnHeader) {return}
|
|
647
647
|
|
|
648
648
|
// Get the actual computed width of the column
|
|
649
649
|
const computedWidth = columnHeader.getBoundingClientRect().width
|
|
@@ -656,7 +656,7 @@ function handleResizeStart(e: MouseEvent, columnKey: string) {
|
|
|
656
656
|
}
|
|
657
657
|
|
|
658
658
|
function handleResizeMove(e: MouseEvent) {
|
|
659
|
-
if (!isResizing.value || !resizingColumn.value) return
|
|
659
|
+
if (!isResizing.value || !resizingColumn.value) {return}
|
|
660
660
|
|
|
661
661
|
e.preventDefault()
|
|
662
662
|
|
|
@@ -54,7 +54,7 @@ const getActualColumnIndex = (localIndex: number) => props.baseColumnIndex + loc
|
|
|
54
54
|
|
|
55
55
|
// Determines if a cell is selected
|
|
56
56
|
function isCellSelected(row: number, localColIndex: number): boolean {
|
|
57
|
-
if (!props.selectionStart || !props.selectionEnd) return false
|
|
57
|
+
if (!props.selectionStart || !props.selectionEnd) {return false}
|
|
58
58
|
|
|
59
59
|
const colIndex = getActualColumnIndex(localColIndex)
|
|
60
60
|
const startRow = Math.min(props.selectionStart.row, props.selectionEnd.row)
|
|
@@ -73,14 +73,14 @@ function isCellEditable(columnKey: string): boolean {
|
|
|
73
73
|
|
|
74
74
|
// Check if a cell is currently being edited
|
|
75
75
|
function isEditing(row: number, localColIndex: number): boolean {
|
|
76
|
-
if (!props.editingCell) return false
|
|
76
|
+
if (!props.editingCell) {return false}
|
|
77
77
|
const colIndex = getActualColumnIndex(localColIndex)
|
|
78
78
|
return props.editingCell.row === row && props.editingCell.col === colIndex
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// Format cell value based on column configuration
|
|
82
82
|
function formatCellValue(value: any, format?: ColumnConfig['format']): string {
|
|
83
|
-
if (
|
|
83
|
+
if (null === value || value === undefined) {return ''}
|
|
84
84
|
|
|
85
85
|
switch (format) {
|
|
86
86
|
case 'image':
|
|
@@ -83,7 +83,7 @@ watch(() => scale, (newScale) => {
|
|
|
83
83
|
const { x, y } = calcTranslateLimit()
|
|
84
84
|
translateX = Math.max(-x, Math.min(x, translateX))
|
|
85
85
|
translateY = Math.max(-y, Math.min(y, translateY))
|
|
86
|
-
if (
|
|
86
|
+
if (1 !== newScale) {
|
|
87
87
|
panLocked = false
|
|
88
88
|
}
|
|
89
89
|
})
|
|
@@ -98,7 +98,7 @@ function reset() {
|
|
|
98
98
|
defineExpose({ reset })
|
|
99
99
|
|
|
100
100
|
function tryToScale(scaleDelta: number) {
|
|
101
|
-
if (disabled) return
|
|
101
|
+
if (disabled) {return}
|
|
102
102
|
let newScale = scale * scaleDelta
|
|
103
103
|
if (zoomingElastic) {
|
|
104
104
|
if (newScale < minScale! || newScale > maxScale!) {
|
|
@@ -108,12 +108,12 @@ function tryToScale(scaleDelta: number) {
|
|
|
108
108
|
newScale = scale * scaleDelta
|
|
109
109
|
}
|
|
110
110
|
} else {
|
|
111
|
-
if (newScale < minScale!) newScale = minScale!
|
|
112
|
-
else if (newScale > maxScale!) newScale = maxScale!
|
|
111
|
+
if (newScale < minScale!) {newScale = minScale!}
|
|
112
|
+
else if (newScale > maxScale!) {newScale = maxScale!}
|
|
113
113
|
}
|
|
114
114
|
scaleDelta = newScale / scale
|
|
115
115
|
scale = newScale
|
|
116
|
-
if (
|
|
116
|
+
if ('image-center' !== pivot) {
|
|
117
117
|
const normMousePosX = (pointerPosX - containerLeft) / containerWidth
|
|
118
118
|
const normMousePosY = (pointerPosY - containerTop) / containerHeight
|
|
119
119
|
translateX = (0.5 + translateX - normMousePosX) * scaleDelta + normMousePosX - 0.5
|
|
@@ -146,7 +146,7 @@ function onPointerMove(newMousePosX: number, newMousePosY: number) {
|
|
|
146
146
|
|
|
147
147
|
const onInteractionEnd = useDebounceFn(() => {
|
|
148
148
|
limit()
|
|
149
|
-
panLocked =
|
|
149
|
+
panLocked = 1 === scale
|
|
150
150
|
}, 100)
|
|
151
151
|
|
|
152
152
|
function limit() {
|
|
@@ -168,10 +168,10 @@ function limit() {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
function calcTranslateLimit() {
|
|
171
|
-
if (
|
|
171
|
+
if ('y' === getMarginDirection()) {
|
|
172
172
|
const imageToContainerRatio = containerWidth / aspectRatio / containerHeight
|
|
173
173
|
let translateLimitY = (scale * imageToContainerRatio - 1) / 2
|
|
174
|
-
if (
|
|
174
|
+
if (0 > translateLimitY) {translateLimitY = 0}
|
|
175
175
|
return {
|
|
176
176
|
x: scale - 1, // Allow full movement to edges horizontally
|
|
177
177
|
y: translateLimitY * 2 // Allow full movement to edges vertically
|
|
@@ -179,7 +179,7 @@ function calcTranslateLimit() {
|
|
|
179
179
|
}
|
|
180
180
|
const imageToContainerRatio = containerHeight * aspectRatio / containerWidth
|
|
181
181
|
let translateLimitX = (scale * imageToContainerRatio - 1) / 2
|
|
182
|
-
if (
|
|
182
|
+
if (0 > translateLimitX) {translateLimitX = 0}
|
|
183
183
|
return {
|
|
184
184
|
x: translateLimitX * 2, // Allow full movement to edges horizontally
|
|
185
185
|
y: scale - 1 // Allow full movement to edges vertically
|
|
@@ -192,18 +192,18 @@ function getMarginDirection() {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
function onMouseWheel(ev: WheelEvent) {
|
|
195
|
-
if (!mouseWheelToZoom) return
|
|
195
|
+
if (!mouseWheelToZoom) {return}
|
|
196
196
|
ev.preventDefault()
|
|
197
197
|
const currTime = Date.now()
|
|
198
|
-
if (Math.abs(ev.deltaY)
|
|
199
|
-
if (currTime - lastFullWheelTime
|
|
198
|
+
if (120 === Math.abs(ev.deltaY)) {
|
|
199
|
+
if (50 < currTime - lastFullWheelTime) {
|
|
200
200
|
onMouseWheelDo(ev.deltaY)
|
|
201
201
|
lastFullWheelTime = currTime
|
|
202
202
|
}
|
|
203
203
|
} else {
|
|
204
|
-
if (currTime - lastWheelTime
|
|
204
|
+
if (50 < currTime - lastWheelTime) {
|
|
205
205
|
lastWheelDirection = ev.deltaX > ev.deltaY ? 'x' : 'y'
|
|
206
|
-
if (
|
|
206
|
+
if ('y' === lastWheelDirection) {
|
|
207
207
|
onMouseWheelDo(ev.deltaY)
|
|
208
208
|
}
|
|
209
209
|
}
|
|
@@ -238,12 +238,12 @@ function onMouseMove(ev: MouseEvent) {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
function onTouchStart(ev: TouchEvent) {
|
|
241
|
-
if (ev.touches.length
|
|
241
|
+
if (1 === ev.touches.length) {
|
|
242
242
|
refreshContainerPos()
|
|
243
243
|
pointerPosX = ev.touches[0].clientX
|
|
244
244
|
pointerPosY = ev.touches[0].clientY
|
|
245
245
|
isPointerDown = true
|
|
246
|
-
} else if (ev.touches.length
|
|
246
|
+
} else if (2 === ev.touches.length) {
|
|
247
247
|
isPointerDown = true
|
|
248
248
|
pointerPosX = (ev.touches[0].clientX + ev.touches[1].clientX) / 2
|
|
249
249
|
pointerPosY = (ev.touches[0].clientY + ev.touches[1].clientY) / 2
|
|
@@ -255,11 +255,11 @@ function onTouchStart(ev: TouchEvent) {
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
function onTouchEnd(ev: TouchEvent) {
|
|
258
|
-
if (ev.touches.length
|
|
258
|
+
if (0 === ev.touches.length) {
|
|
259
259
|
isPointerDown = false
|
|
260
|
-
if (Math.abs(scale - 1)
|
|
260
|
+
if (0.1 > Math.abs(scale - 1)) {scale = 1}
|
|
261
261
|
onInteractionEnd()
|
|
262
|
-
} else if (ev.touches.length
|
|
262
|
+
} else if (1 === ev.touches.length) {
|
|
263
263
|
pointerPosX = ev.touches[0].clientX
|
|
264
264
|
pointerPosY = ev.touches[0].clientY
|
|
265
265
|
}
|
|
@@ -267,11 +267,11 @@ function onTouchEnd(ev: TouchEvent) {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
function onTouchMove(ev: TouchEvent) {
|
|
270
|
-
if (ev.touches.length
|
|
270
|
+
if (1 === ev.touches.length) {
|
|
271
271
|
onPointerMove(ev.touches[0].clientX, ev.touches[0].clientY)
|
|
272
|
-
} else if (
|
|
272
|
+
} else if (2
|
|
273
273
|
|
|
274
|
-
===
|
|
274
|
+
=== ev.touches.length) {
|
|
275
275
|
const distX = ev.touches[0].clientX - ev.touches[1].clientX
|
|
276
276
|
const distY = ev.touches[0].clientY - ev.touches[1].clientY
|
|
277
277
|
const newTwoFingerDist = Math.sqrt(distX * distX + distY * distY)
|
|
@@ -297,13 +297,13 @@ function loop() {
|
|
|
297
297
|
|
|
298
298
|
function gainOn(from: number, to: number) {
|
|
299
299
|
const delta = (to - from) * 0.3
|
|
300
|
-
return Math.abs(delta)
|
|
300
|
+
return 1e-5 < Math.abs(delta) ? from + delta : to
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
// Lifecycle hooks
|
|
304
304
|
onMounted(() => {
|
|
305
305
|
tapDetector = new TapDetector()
|
|
306
|
-
if (zoomElement) tapDetector.attach(zoomElement)
|
|
306
|
+
if (zoomElement) {tapDetector.attach(zoomElement)}
|
|
307
307
|
if (doubleClickToZoom) {
|
|
308
308
|
tapDetector.onDoubleTap(onDoubleTap as any)
|
|
309
309
|
}
|
|
@@ -314,14 +314,14 @@ onMounted(() => {
|
|
|
314
314
|
})
|
|
315
315
|
|
|
316
316
|
onUnmounted(() => {
|
|
317
|
-
if (zoomElement) tapDetector?.detach(zoomElement)
|
|
317
|
+
if (zoomElement) {tapDetector?.detach(zoomElement)}
|
|
318
318
|
window.removeEventListener('resize', onWindowResize)
|
|
319
|
-
if (raf) window.cancelAnimationFrame(raf)
|
|
319
|
+
if (raf) {window.cancelAnimationFrame(raf)}
|
|
320
320
|
})
|
|
321
321
|
|
|
322
322
|
function onDoubleTap(ev: MouseEvent) {
|
|
323
|
-
if (
|
|
324
|
-
if (ev.clientX
|
|
323
|
+
if (1 === scale) {
|
|
324
|
+
if (0 < ev.clientX) {
|
|
325
325
|
pointerPosX = ev.clientX
|
|
326
326
|
pointerPosY = ev.clientY
|
|
327
327
|
}
|
|
@@ -57,7 +57,7 @@ const observer = ref<IntersectionObserver | null>(null)
|
|
|
57
57
|
const chartRef = ref<HTMLElement | null>(null)
|
|
58
58
|
|
|
59
59
|
const chartData = computed(() => {
|
|
60
|
-
if (!props.data || props.data.length
|
|
60
|
+
if (!props.data || 0 === props.data.length) {return []}
|
|
61
61
|
|
|
62
62
|
// Use all data without limiting to maxBars
|
|
63
63
|
const maxValue = Math.max(...props.data.map(d => d.value), 1)
|
|
@@ -71,8 +71,8 @@ const chartData = computed(() => {
|
|
|
71
71
|
// Animation computed properties
|
|
72
72
|
const getBarOpacity = computed(() => {
|
|
73
73
|
return (index: number) => {
|
|
74
|
-
if (!props.animated) return 1
|
|
75
|
-
if (!isInView.value) return 0
|
|
74
|
+
if (!props.animated) {return 1}
|
|
75
|
+
if (!isInView.value) {return 0}
|
|
76
76
|
|
|
77
77
|
const totalBars = chartData.value.length
|
|
78
78
|
|
|
@@ -90,7 +90,7 @@ function easeOutCubic(t: number): number {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
function startAnimation() {
|
|
93
|
-
if (isAnimating.value || !props.animated) return
|
|
93
|
+
if (isAnimating.value || !props.animated) {return}
|
|
94
94
|
|
|
95
95
|
console.log(`🎯 TrendChart: Starting animation with ${props.animationDuration}ms duration`)
|
|
96
96
|
isAnimating.value = true
|
|
@@ -105,7 +105,7 @@ function startAnimation() {
|
|
|
105
105
|
|
|
106
106
|
animatedProgress.value = easedProgress
|
|
107
107
|
|
|
108
|
-
if (
|
|
108
|
+
if (1 > progress) {
|
|
109
109
|
requestAnimationFrame(animate)
|
|
110
110
|
} else {
|
|
111
111
|
isAnimating.value = false
|
|
@@ -117,7 +117,7 @@ function startAnimation() {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
function setupIntersectionObserver() {
|
|
120
|
-
if (!chartRef.value || observer.value) return
|
|
120
|
+
if (!chartRef.value || observer.value) {return}
|
|
121
121
|
|
|
122
122
|
observer.value = new IntersectionObserver(
|
|
123
123
|
(entries) => {
|
|
@@ -27,10 +27,10 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
27
27
|
subtitle: ''
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
-
const isIncreasing = computed(() => props.percentageChange
|
|
30
|
+
const isIncreasing = computed(() => 0 <= props.percentageChange)
|
|
31
31
|
|
|
32
32
|
const formattedValue = computed(() => {
|
|
33
|
-
if (typeof props.value
|
|
33
|
+
if ('string' === typeof props.value) {return props.value}
|
|
34
34
|
|
|
35
35
|
if (props.currency) {
|
|
36
36
|
return new Intl.NumberFormat('he-IL', {
|
|
@@ -54,21 +54,21 @@ const chartHeight = computed(() => height.value - padding.top - padding.bottom)
|
|
|
54
54
|
|
|
55
55
|
// RTL-aware padding calculations
|
|
56
56
|
const paddingLeft = computed(() => {
|
|
57
|
-
const isRTL = document.documentElement.dir
|
|
58
|
-
|
|
57
|
+
const isRTL = 'rtl' === document.documentElement.dir ||
|
|
58
|
+
'he' === document.documentElement.getAttribute('lang')
|
|
59
59
|
return isRTL ? padding.inline_end : padding.inline_start
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
// RTL-aware label positioning
|
|
63
63
|
const labelXPosition = computed(() => {
|
|
64
|
-
const isRTL = document.documentElement.dir
|
|
65
|
-
|
|
64
|
+
const isRTL = 'rtl' === document.documentElement.dir ||
|
|
65
|
+
'he' === document.documentElement.getAttribute('lang')
|
|
66
66
|
return isRTL ? paddingLeft.value + chartWidth.value + 10 : paddingLeft.value - 10
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
const labelTextAnchor = computed(() => {
|
|
70
|
-
const isRTL = document.documentElement.dir
|
|
71
|
-
|
|
70
|
+
const isRTL = 'rtl' === document.documentElement.dir ||
|
|
71
|
+
'he' === document.documentElement.getAttribute('lang')
|
|
72
72
|
return isRTL ? 'start' : 'end'
|
|
73
73
|
})
|
|
74
74
|
|
|
@@ -76,8 +76,8 @@ const maxValue = computed(() => Math.max(...props.data.map(d => d.value), 0))
|
|
|
76
76
|
const minValue = computed(() => Math.min(...props.data.map(d => d.value), 0))
|
|
77
77
|
|
|
78
78
|
const xScale = computed(() => {
|
|
79
|
-
const isRTL = document.documentElement.dir
|
|
80
|
-
|
|
79
|
+
const isRTL = 'rtl' === document.documentElement.dir ||
|
|
80
|
+
'he' === document.documentElement.getAttribute('lang')
|
|
81
81
|
const domain = props.data.length - 1
|
|
82
82
|
|
|
83
83
|
return (index: number) => {
|
|
@@ -93,7 +93,7 @@ const yScale = computed(() => {
|
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
const pathData = computed(() => {
|
|
96
|
-
if (props.data.length
|
|
96
|
+
if (0 === props.data.length) {return ''}
|
|
97
97
|
|
|
98
98
|
// Calculate how many points to show based on animation progress
|
|
99
99
|
const totalPoints = props.data.length
|
|
@@ -104,14 +104,14 @@ const pathData = computed(() => {
|
|
|
104
104
|
const dataToShow = props.data.slice(0, Math.max(1, visiblePoints))
|
|
105
105
|
|
|
106
106
|
const points = dataToShow.map((d, i) =>
|
|
107
|
-
`${
|
|
107
|
+
`${ 0 === i ? 'M' : 'L'} ${paddingLeft.value + xScale.value(i)} ${padding.top + yScale.value(d.value)}`
|
|
108
108
|
).join(' ')
|
|
109
109
|
|
|
110
110
|
return points
|
|
111
111
|
})
|
|
112
112
|
|
|
113
113
|
const visiblePoints = computed(() => {
|
|
114
|
-
if (!props.animated) return props.data
|
|
114
|
+
if (!props.animated) {return props.data}
|
|
115
115
|
|
|
116
116
|
const totalPoints = props.data.length
|
|
117
117
|
const pointsToShow = Math.ceil(totalPoints * animatedProgress.value)
|
|
@@ -121,7 +121,7 @@ const visiblePoints = computed(() => {
|
|
|
121
121
|
const gridLines = computed(() => {
|
|
122
122
|
const lines = []
|
|
123
123
|
const step = chartHeight.value / 4
|
|
124
|
-
for (let i = 0;
|
|
124
|
+
for (let i = 0; 4 >= i; i++) {
|
|
125
125
|
const y = i * step
|
|
126
126
|
const value = maxValue.value - (i / 4) * (maxValue.value - minValue.value)
|
|
127
127
|
lines.push({ y, value })
|
|
@@ -157,7 +157,7 @@ function formatTooltip(point: any): string {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
const setupIntersectionObserver = () => {
|
|
160
|
-
if (typeof window
|
|
160
|
+
if ('undefined' === typeof window) {return}
|
|
161
161
|
|
|
162
162
|
observer = new IntersectionObserver(
|
|
163
163
|
(entries) => {
|
|
@@ -200,7 +200,7 @@ const startAnimation = () => {
|
|
|
200
200
|
|
|
201
201
|
animatedProgress.value = easeOutCubic(progress)
|
|
202
202
|
|
|
203
|
-
if (
|
|
203
|
+
if (1 > progress) {
|
|
204
204
|
requestAnimationFrame(animate)
|
|
205
205
|
} else {
|
|
206
206
|
isAnimating.value = false
|
|
@@ -54,7 +54,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
54
54
|
// Generate colors with different opacity based on the main color OR use custom colors
|
|
55
55
|
const colors = computed(() => {
|
|
56
56
|
// If custom colors array is provided, use it
|
|
57
|
-
if (props.colors && props.colors.length
|
|
57
|
+
if (props.colors && 0 < props.colors.length) {
|
|
58
58
|
return props.colors
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -96,7 +96,7 @@ onUnmounted(() => {
|
|
|
96
96
|
let observer: IntersectionObserver | null = null
|
|
97
97
|
|
|
98
98
|
const setupIntersectionObserver = () => {
|
|
99
|
-
if (typeof window
|
|
99
|
+
if ('undefined' === typeof window) {return}
|
|
100
100
|
|
|
101
101
|
observer = new IntersectionObserver(
|
|
102
102
|
(entries) => {
|
|
@@ -130,7 +130,7 @@ const setupIntersectionObserver = () => {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
const startAnimation = () => {
|
|
133
|
-
const delayType = props.animationDelay
|
|
133
|
+
const delayType = 0 < props.animationDelay ? "staggered with delay" : "quick stagger"
|
|
134
134
|
console.log(`Starting animation for "${props.title}" - ${delayType} mode (duration: ${props.animationDuration}ms, start delay: ${props.animationStartDelay}ms)`)
|
|
135
135
|
isAnimating.value = true
|
|
136
136
|
animatedProgress.value = 0
|
|
@@ -144,7 +144,7 @@ const startAnimation = () => {
|
|
|
144
144
|
// Easing function for smooth animation
|
|
145
145
|
animatedProgress.value = easeOutCubic(progress)
|
|
146
146
|
|
|
147
|
-
if (
|
|
147
|
+
if (1 > progress) {
|
|
148
148
|
requestAnimationFrame(animate)
|
|
149
149
|
} else {
|
|
150
150
|
isAnimating.value = false
|
|
@@ -229,7 +229,7 @@ const getConnectorLine = (segment: any) => {
|
|
|
229
229
|
const outerY = Math.sin(midAngleRad) * outerRadius
|
|
230
230
|
|
|
231
231
|
// Extended line for label - reduced extension
|
|
232
|
-
const labelX = outerX + (
|
|
232
|
+
const labelX = outerX + (0 < outerX ? 8 : -8) // Reduced from 10 to 8
|
|
233
233
|
const labelY = outerY
|
|
234
234
|
|
|
235
235
|
return {
|
|
@@ -239,7 +239,7 @@ const getConnectorLine = (segment: any) => {
|
|
|
239
239
|
outerY,
|
|
240
240
|
labelX,
|
|
241
241
|
labelY,
|
|
242
|
-
textAnchor:
|
|
242
|
+
textAnchor: 0 < outerX ? 'start' : 'end'
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
|
|
@@ -263,19 +263,19 @@ const pieSegments = computed(() => {
|
|
|
263
263
|
// Calculate if this segment should be visible based on animation progress
|
|
264
264
|
// Add a small delay even for the first segment to avoid immediate appearance
|
|
265
265
|
const baseDelay = 100 // 100ms delay for the first segment
|
|
266
|
-
const segmentDelay = props.animationDelay
|
|
266
|
+
const segmentDelay = 0 < props.animationDelay ?
|
|
267
267
|
baseDelay + (index * props.animationDelay) :
|
|
268
268
|
baseDelay + (index * 50) // Small stagger even when animationDelay is 0
|
|
269
269
|
const totalElapsedTime = animatedProgress.value * props.animationDuration
|
|
270
270
|
const isVisible = !props.animated || totalElapsedTime >= segmentDelay
|
|
271
271
|
|
|
272
272
|
// Debug log for animation
|
|
273
|
-
if (props.animated &&
|
|
273
|
+
if (props.animated && 0 === index) {
|
|
274
274
|
console.log(`Animation progress: ${(animatedProgress.value * 100).toFixed(1)}%, elapsed: ${totalElapsedTime.toFixed(0)}ms`)
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
if (!isVisible) {
|
|
278
|
-
if (
|
|
278
|
+
if (3 > index) {
|
|
279
279
|
console.log(`Segment ${index} waiting - needs ${segmentDelay}ms, current: ${totalElapsedTime.toFixed(0)}ms`)
|
|
280
280
|
}
|
|
281
281
|
return {
|
|
@@ -288,7 +288,7 @@ const pieSegments = computed(() => {
|
|
|
288
288
|
color: item.color || colors.value[index % colors.value.length],
|
|
289
289
|
visible: false
|
|
290
290
|
}
|
|
291
|
-
}
|
|
291
|
+
}if (index < 3) {
|
|
292
292
|
console.log(`Segment ${index} visible! - delay: ${segmentDelay}ms, elapsed: ${totalElapsedTime.toFixed(0)}ms`)
|
|
293
293
|
}
|
|
294
294
|
|
|
@@ -299,7 +299,7 @@ const pieSegments = computed(() => {
|
|
|
299
299
|
const innerRadius = props.donut ? radius * props.thickness : 0
|
|
300
300
|
|
|
301
301
|
const segmentAngle = endAngle - startAngle
|
|
302
|
-
const largeArcFlag =
|
|
302
|
+
const largeArcFlag = 180 < segmentAngle ? 1 : 0
|
|
303
303
|
|
|
304
304
|
const pathData = props.donut
|
|
305
305
|
? createDonutPath(startAngleRad, endAngleRad, radius, innerRadius, largeArcFlag)
|
|
@@ -31,7 +31,7 @@ const popoverPosition = computed(() => {
|
|
|
31
31
|
left = Math.max(scrollX.value + margin, Math.min(left, innerWidth.value + scrollX.value - popoverWidth - margin))
|
|
32
32
|
|
|
33
33
|
return { top, left, width: popoverWidth, height: 150 }
|
|
34
|
-
}
|
|
34
|
+
}if (props.targetElement && props.show) {
|
|
35
35
|
// Position relative to target element
|
|
36
36
|
const target = props.targetElement
|
|
37
37
|
const rect = target.getBoundingClientRect()
|