@wishbone-media/spark 0.46.0 → 0.48.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wishbone-media/spark",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -37,7 +37,8 @@
37
37
  }
38
38
 
39
39
  td {
40
- @apply px-6 py-4 whitespace-nowrap text-gray-500 text-sm align-middle h-auto;
40
+ @apply whitespace-nowrap text-gray-500 text-sm align-middle h-auto;
41
+ padding: var(--spark-table-cell-py, 16px) var(--spark-table-cell-px, 24px);
41
42
  @apply !border-l-0 !border-r-0 !border-gray-200;
42
43
 
43
44
  &:not(.read-only) {
@@ -48,6 +49,18 @@
48
49
  td:not(:last-child) {
49
50
  @apply !border-r-0;
50
51
  }
52
+
53
+ td.spark-table-word-wrap {
54
+ @apply whitespace-normal break-words;
55
+ }
56
+
57
+ td.spark-table-align-center {
58
+ @apply text-center;
59
+ }
60
+
61
+ td.spark-table-align-right {
62
+ @apply text-right;
63
+ }
51
64
  }
52
65
  }
53
66
 
@@ -66,7 +79,7 @@
66
79
  @apply text-left text-xs font-semibold bg-gray-50 text-gray-800 whitespace-normal
67
80
  tracking-wider focus:outline-hidden filter flex items-center;
68
81
 
69
- @apply !px-5 !py-3;
82
+ padding: var(--spark-table-header-py, 12px) var(--spark-table-header-px, 20px) !important;
70
83
 
71
84
  .fa-sort-up,
72
85
  .fa-sort-down {
@@ -119,7 +132,8 @@
119
132
  }
120
133
 
121
134
  .spark-table-head-sorting {
122
- @apply absolute right-5 w-5 h-5 border border-gray-200 rounded-md grid place-items-center;
135
+ @apply absolute w-5 h-5 border border-gray-200 rounded-md grid place-items-center;
136
+ right: var(--spark-table-header-px, 20px);
123
137
  }
124
138
 
125
139
  .spark-table-head-title-wrapper {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="spark-table">
2
+ <div class="spark-table" :style="spacingStyles">
3
3
  <!-- Header Toolbar: All plugins flow left to right -->
4
4
  <SparkTableToolbar
5
5
  v-if="sparkTable.computed.ready && headerPlugins && headerPlugins.length"
@@ -75,6 +75,12 @@ const defaultTableSettings = {
75
75
  readOnlyCellClassName: 'read-only',
76
76
  licenseKey: 'non-commercial-and-evaluation',
77
77
  }
78
+
79
+ const spacingPresets = {
80
+ sm: { cellPx: 12, cellPy: 8, headerPx: 12, headerPy: 12 },
81
+ base: { cellPx: 24, cellPy: 16, headerPx: 20, headerPy: 12 },
82
+ lg: { cellPx: 32, cellPy: 20, headerPx: 24, headerPy: 16 },
83
+ }
78
84
  </script>
79
85
  <script setup>
80
86
  import { computed, onMounted, onUnmounted, ref, reactive, inject, watch } from 'vue'
@@ -178,6 +184,23 @@ const props = defineProps({
178
184
  type: Boolean,
179
185
  default: false,
180
186
  },
187
+
188
+ spacing: {
189
+ type: [String, Object],
190
+ default: null,
191
+ },
192
+ })
193
+
194
+ const spacingStyles = computed(() => {
195
+ if (!props.spacing) return {}
196
+ const values = typeof props.spacing === 'string' ? spacingPresets[props.spacing] : props.spacing
197
+ if (!values) return {}
198
+ const styles = {}
199
+ if (values.cellPx !== undefined) styles['--spark-table-cell-px'] = `${values.cellPx}px`
200
+ if (values.cellPy !== undefined) styles['--spark-table-cell-py'] = `${values.cellPy}px`
201
+ if (values.headerPx !== undefined) styles['--spark-table-header-px'] = `${values.headerPx}px`
202
+ if (values.headerPy !== undefined) styles['--spark-table-header-py'] = `${values.headerPy}px`
203
+ return styles
181
204
  })
182
205
 
183
206
  registerAllCellTypes()
@@ -356,40 +379,76 @@ const sparkTable = reactive({
356
379
  ...props.options,
357
380
  })),
358
381
 
359
- tableSettings: computed(() => ({
360
- ...defaultTableSettings,
361
- nestedHeaders: get(props.settings, 'nestedHeaders', []),
362
- ...(!get(props.settings, 'nestedHeaders') && {
363
- afterGetColHeader: (col, th) => customiseHeader(col, th, sparkTable),
364
- }),
365
- afterChange: (changes, source) => updateRow(changes, source, sparkTable),
366
- afterRender: () => syncSortClasses(sparkTable),
367
- beforeStretchingColumnWidth: (stretchedWidth, column) => {
368
- const columns = get(props.settings, 'columns', [])
369
- const columnSettings = columns[column]
370
- if (columnSettings && columnSettings.width !== undefined) {
371
- return columnSettings.width
372
- }
373
- return stretchedWidth
374
- },
375
- beforeCopy: (data, coords) => {
376
- const hot = table.value?.hotInstance
377
- if (!hot) return
378
- coords.forEach((range) => {
379
- for (let row = range.startRow; row <= range.endRow; row++) {
380
- for (let col = range.startCol; col <= range.endCol; col++) {
381
- const td = hot.getCell(row, col)
382
- if (td) {
383
- const dataRow = row - coords[0].startRow
384
- const dataCol = col - coords[0].startCol
385
- data[dataRow][dataCol] = td.dataset.copyValue ?? td.textContent ?? ''
382
+ tableSettings: computed(() => {
383
+ const columns = get(props.settings, 'columns', [])
384
+
385
+ const transformedColumns = columns.map((col) => {
386
+ if (!col.wordWrap && !col.align) return col
387
+ const classes = [col.className]
388
+ if (col.wordWrap) classes.push('spark-table-word-wrap')
389
+ if (col.align === 'center') classes.push('spark-table-align-center')
390
+ if (col.align === 'right') classes.push('spark-table-align-right')
391
+ return { ...col, className: classes.filter(Boolean).join(' ') }
392
+ })
393
+
394
+ const hasClampedColumns = columns.some(
395
+ (col) => typeof col.wordWrap === 'object' && col.wordWrap?.maxLines,
396
+ )
397
+
398
+ const userAfterRenderer = props.settings.afterRenderer
399
+
400
+ return {
401
+ ...defaultTableSettings,
402
+ nestedHeaders: get(props.settings, 'nestedHeaders', []),
403
+ ...(!get(props.settings, 'nestedHeaders') && {
404
+ afterGetColHeader: (col, th) => customiseHeader(col, th, sparkTable),
405
+ }),
406
+ afterChange: (changes, source) => updateRow(changes, source, sparkTable),
407
+ afterRender: () => syncSortClasses(sparkTable),
408
+ beforeStretchingColumnWidth: (stretchedWidth, column) => {
409
+ const columnSettings = columns[column]
410
+ if (columnSettings && columnSettings.width !== undefined) {
411
+ return columnSettings.width
412
+ }
413
+ return stretchedWidth
414
+ },
415
+ beforeCopy: (data, coords) => {
416
+ const hot = table.value?.hotInstance
417
+ if (!hot) return
418
+ coords.forEach((range) => {
419
+ for (let row = range.startRow; row <= range.endRow; row++) {
420
+ for (let col = range.startCol; col <= range.endCol; col++) {
421
+ const td = hot.getCell(row, col)
422
+ if (td) {
423
+ const dataRow = row - coords[0].startRow
424
+ const dataCol = col - coords[0].startCol
425
+ data[dataRow][dataCol] = td.dataset.copyValue ?? td.textContent ?? ''
426
+ }
386
427
  }
387
428
  }
388
- }
389
- })
390
- },
391
- ...props.settings,
392
- })),
429
+ })
430
+ },
431
+ ...props.settings,
432
+ columns: transformedColumns,
433
+ ...(hasClampedColumns && {
434
+ afterRenderer: (td, row, col) => {
435
+ userAfterRenderer?.(td, row, col)
436
+ const colConfig = columns[col]
437
+ const wordWrap = colConfig?.wordWrap
438
+ if (!wordWrap || wordWrap === true || !wordWrap.maxLines) return
439
+
440
+ const wrapper = document.createElement('div')
441
+ wrapper.style.display = '-webkit-box'
442
+ wrapper.style.webkitBoxOrient = 'vertical'
443
+ wrapper.style.webkitLineClamp = wordWrap.maxLines
444
+ wrapper.style.overflow = 'hidden'
445
+
446
+ while (td.firstChild) wrapper.appendChild(td.firstChild)
447
+ td.appendChild(wrapper)
448
+ },
449
+ }),
450
+ }
451
+ }),
393
452
  })
394
453
 
395
454
  // Empty state detection - true when data has loaded but contains no records