@globalbrain/sefirot 4.30.1 → 4.32.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.
Files changed (134) hide show
  1. package/client.d.ts +5 -0
  2. package/config/nuxt.d.ts +1 -0
  3. package/config/nuxt.js +8 -5
  4. package/config/vite.js +4 -13
  5. package/lib/components/SActionList.vue +2 -2
  6. package/lib/components/SActionMenu.vue +43 -7
  7. package/lib/components/SAvatar.vue +1 -1
  8. package/lib/components/SAvatarStack.vue +12 -12
  9. package/lib/components/SButton.vue +5 -7
  10. package/lib/components/SCard.vue +2 -2
  11. package/lib/components/SChartBar.vue +37 -12
  12. package/lib/components/SChartPie.vue +13 -7
  13. package/lib/components/SControlActionBarCollapse.vue +2 -4
  14. package/lib/components/SControlInputSearch.vue +7 -2
  15. package/lib/components/SDataListItem.vue +1 -3
  16. package/lib/components/SDescAvatar.vue +1 -1
  17. package/lib/components/SDescDay.vue +2 -2
  18. package/lib/components/SDescFile.vue +2 -4
  19. package/lib/components/SDescItem.vue +2 -1
  20. package/lib/components/SDescLabel.vue +1 -1
  21. package/lib/components/SDescLink.vue +2 -7
  22. package/lib/components/SDescPill.vue +2 -4
  23. package/lib/components/SDescText.vue +3 -3
  24. package/lib/components/SDropdown.vue +1 -1
  25. package/lib/components/SDropdownSectionFilter.vue +11 -11
  26. package/lib/components/SFragment.vue +1 -1
  27. package/lib/components/SInputAddon.vue +13 -11
  28. package/lib/components/SInputBase.vue +11 -11
  29. package/lib/components/SInputCheckbox.vue +6 -3
  30. package/lib/components/SInputCheckboxes.vue +7 -3
  31. package/lib/components/SInputDate.vue +3 -5
  32. package/lib/components/SInputDropdown.vue +26 -28
  33. package/lib/components/SInputDropdownItem.vue +21 -11
  34. package/lib/components/SInputFile.vue +9 -6
  35. package/lib/components/SInputFileUpload.vue +9 -11
  36. package/lib/components/SInputFileUploadItem.vue +8 -4
  37. package/lib/components/SInputHMS.vue +3 -1
  38. package/lib/components/SInputImage.vue +4 -2
  39. package/lib/components/SInputNumber.vue +9 -10
  40. package/lib/components/SInputRadio.vue +3 -2
  41. package/lib/components/SInputRadios.vue +6 -5
  42. package/lib/components/SInputSegments.vue +5 -7
  43. package/lib/components/SInputSegmentsOption.vue +1 -2
  44. package/lib/components/SInputSelect.vue +6 -4
  45. package/lib/components/SInputSwitch.vue +4 -1
  46. package/lib/components/SInputSwitches.vue +5 -3
  47. package/lib/components/SInputText.vue +16 -16
  48. package/lib/components/SInputTextarea.vue +7 -3
  49. package/lib/components/SInputYMD.vue +3 -1
  50. package/lib/components/SLink.vue +2 -2
  51. package/lib/components/SLocalNav.vue +1 -1
  52. package/lib/components/SLocalNavActions.vue +1 -1
  53. package/lib/components/SLocalNavMenu.vue +2 -2
  54. package/lib/components/SLoginPagePasswordDialog.vue +2 -2
  55. package/lib/components/SM.vue +1 -1
  56. package/lib/components/SMFade.vue +1 -1
  57. package/lib/components/SMarkdown.vue +3 -2
  58. package/lib/components/SModal.vue +2 -2
  59. package/lib/components/SSnackbar.vue +2 -2
  60. package/lib/components/SSteps.vue +6 -6
  61. package/lib/components/STable.vue +70 -27
  62. package/lib/components/STableCell.vue +14 -17
  63. package/lib/components/STableCellAvatars.vue +1 -1
  64. package/lib/components/STableCellDay.vue +12 -5
  65. package/lib/components/STableCellNumber.vue +2 -3
  66. package/lib/components/STableCellPath.vue +2 -2
  67. package/lib/components/STableCellText.vue +2 -3
  68. package/lib/components/STableColumn.vue +38 -16
  69. package/lib/components/STableFooter.vue +10 -2
  70. package/lib/components/STableHeader.vue +0 -1
  71. package/lib/components/STableHeaderMenu.vue +4 -4
  72. package/lib/components/STableHeaderMenuItem.vue +1 -1
  73. package/lib/components/STooltip.vue +3 -3
  74. package/lib/composables/Api.ts +1 -1
  75. package/lib/composables/App.ts +13 -11
  76. package/lib/composables/Dropdown.ts +10 -1
  77. package/lib/composables/Error.ts +37 -37
  78. package/lib/composables/Grid.ts +1 -4
  79. package/lib/composables/Image.ts +2 -3
  80. package/lib/composables/Lang.ts +8 -16
  81. package/lib/composables/Markdown.ts +1 -1
  82. package/lib/composables/Table.ts +0 -2
  83. package/lib/composables/Theme.ts +1 -13
  84. package/lib/composables/Utils.ts +11 -4
  85. package/lib/composables/Validation.ts +1 -4
  86. package/lib/http/Http.ts +23 -17
  87. package/lib/styles/variables-deprecated.css +0 -1
  88. package/lib/styles/variables.css +16 -16
  89. package/lib/support/Chart.ts +0 -1
  90. package/lib/support/DateRange.ts +1 -1
  91. package/lib/support/Day.ts +12 -65
  92. package/lib/support/File.ts +7 -16
  93. package/lib/support/Utils.ts +7 -40
  94. package/lib/validation/Rule.ts +6 -21
  95. package/lib/validation/rules/decimal.ts +3 -3
  96. package/lib/validation/rules/email.ts +1 -1
  97. package/lib/validation/rules/index.ts +1 -1
  98. package/lib/validation/rules/negativeInteger.ts +1 -1
  99. package/lib/validation/rules/positiveInteger.ts +1 -1
  100. package/lib/validation/rules/requiredHms.ts +2 -2
  101. package/lib/validation/rules/requiredIf.ts +1 -4
  102. package/lib/validation/rules/requiredYmd.ts +2 -2
  103. package/lib/validation/rules/slackChannelName.ts +4 -1
  104. package/lib/validation/rules/zeroOrNegativeInteger.ts +1 -1
  105. package/lib/validation/rules/zeroOrPositiveInteger.ts +1 -1
  106. package/lib/validation/validators/after.ts +1 -5
  107. package/lib/validation/validators/afterOrEqual.ts +1 -5
  108. package/lib/validation/validators/before.ts +1 -4
  109. package/lib/validation/validators/beforeOrEqual.ts +1 -5
  110. package/lib/validation/validators/decimal.ts +7 -9
  111. package/lib/validation/validators/email.ts +4 -8
  112. package/lib/validation/validators/fileExtension.ts +7 -15
  113. package/lib/validation/validators/hms.ts +26 -15
  114. package/lib/validation/validators/index.ts +0 -2
  115. package/lib/validation/validators/maxFileSize.ts +3 -13
  116. package/lib/validation/validators/maxLength.ts +1 -7
  117. package/lib/validation/validators/maxTotalFileSize.ts +3 -26
  118. package/lib/validation/validators/maxValue.ts +2 -6
  119. package/lib/validation/validators/minLength.ts +1 -7
  120. package/lib/validation/validators/minValue.ts +2 -6
  121. package/lib/validation/validators/month.ts +1 -7
  122. package/lib/validation/validators/negativeInteger.ts +1 -7
  123. package/lib/validation/validators/positiveInteger.ts +1 -7
  124. package/lib/validation/validators/required.ts +5 -28
  125. package/lib/validation/validators/requiredHmsIf.ts +11 -13
  126. package/lib/validation/validators/requiredIf.ts +5 -11
  127. package/lib/validation/validators/requiredYmdIf.ts +11 -13
  128. package/lib/validation/validators/slackChannelName.ts +11 -11
  129. package/lib/validation/validators/url.ts +7 -5
  130. package/lib/validation/validators/ymd.ts +36 -30
  131. package/package.json +44 -42
  132. package/lib/composables/Http.ts +0 -18
  133. package/lib/validation/validators/requiredHms.ts +0 -9
  134. package/lib/validation/validators/requiredYmd.ts +0 -9
@@ -22,6 +22,7 @@ const head = shallowRef<HTMLElement | null>(null)
22
22
  const body = shallowRef<HTMLElement | null>(null)
23
23
  const block = shallowRef<HTMLElement | null>(null)
24
24
  const row = shallowRef<HTMLElement | null>(null)
25
+ const table = shallowRef<HTMLElement | null>(null)
25
26
 
26
27
  const ordersToShow = smartComputed(() => {
27
28
  const orders = unref(props.options.orders).filter((key) => {
@@ -36,7 +37,7 @@ const ordersToShow = smartComputed(() => {
36
37
  return ['__select', ...orders]
37
38
  })
38
39
 
39
- watch(() => ordersToShow.value, handleResize)
40
+ watch(() => ordersToShow.value, onResize)
40
41
 
41
42
  const colToGrowAdjusted = ref(false)
42
43
 
@@ -61,6 +62,12 @@ const cellOfColToGrow = computed(() => {
61
62
  const colWidths = reactive<Record<string, string>>({})
62
63
  const blockWidth = ref<number | undefined>()
63
64
 
65
+ const resizeState = ref<{
66
+ columnName: string
67
+ startX: number
68
+ indicatorX: number
69
+ } | null>(null)
70
+
64
71
  watch(() => unref(props.options.columns), (columns) => {
65
72
  Object.keys(columns).forEach((key) => {
66
73
  const width = columns[key]?.width
@@ -77,7 +84,6 @@ const showHeader = computed(() => {
77
84
 
78
85
  return (
79
86
  unref(props.options.total) != null
80
- || !!unref(props.options.reset)
81
87
  || !!unref(props.options.menu)
82
88
  )
83
89
  })
@@ -201,7 +207,6 @@ const frozenColumns = smartComputed(() => {
201
207
  })
202
208
 
203
209
  const frozenColWidths = smartComputed(() => {
204
- // eslint-disable-next-line no-void
205
210
  void blockWidth.value
206
211
  return frozenColumns.value.map((key) => getColWidth(key))
207
212
  })
@@ -210,7 +215,7 @@ useResizeObserver(block, ([entry]) => {
210
215
  blockWidth.value = entry.contentRect.width
211
216
  })
212
217
 
213
- const resizeObserver = useResizeObserver(head, handleResize)
218
+ const resizeObserver = useResizeObserver(head, onResize)
214
219
 
215
220
  const font = typeof document !== 'undefined'
216
221
  ? `500 12px ${getComputedStyle(document.body).fontFamily}`
@@ -267,7 +272,7 @@ function stopObserving() {
267
272
  resizeObserver.stop()
268
273
  }
269
274
 
270
- async function handleResize() {
275
+ async function onResize() {
271
276
  if (colToGrow.value < 0 || !cellOfColToGrow.value || !row.value) {
272
277
  stopObserving()
273
278
  return
@@ -387,6 +392,29 @@ function getStyles(key: string) {
387
392
  '--table-col-left': widthSum ? `calc(${widthSum})` : '0px'
388
393
  }
389
394
  }
395
+
396
+ function onResizeStart(data: { columnName: string; startX: number; initialX: number }) {
397
+ const tableRect = table.value?.getBoundingClientRect()
398
+ const tableLeft = tableRect?.left ?? 0
399
+ const indicatorX = data.initialX - tableLeft
400
+
401
+ resizeState.value = {
402
+ columnName: data.columnName,
403
+ startX: indicatorX,
404
+ indicatorX
405
+ }
406
+ }
407
+
408
+ function onResizeMove(data: { deltaX: number }) {
409
+ if (resizeState.value) {
410
+ resizeState.value.indicatorX = resizeState.value.startX + data.deltaX
411
+ }
412
+ }
413
+
414
+ function onResizeEnd(data: { columnName: string; finalWidth: string }) {
415
+ updateColWidth(data.columnName, data.finalWidth, true)
416
+ resizeState.value = null
417
+ }
390
418
  </script>
391
419
 
392
420
  <template>
@@ -395,17 +423,21 @@ function getStyles(key: string) {
395
423
  <STableHeader
396
424
  v-if="showHeader"
397
425
  :total="unref(options.total)"
398
- :reset="unref(options.reset)"
399
426
  :menu="unref(options.menu)"
400
427
  :borderless="unref(options.borderless)"
401
- :on-reset="options.onReset"
402
428
  :selected="Array.isArray(selected) ? selected : undefined"
403
429
  />
404
430
 
405
- <div class="table" role="grid">
406
- <div class="container head" ref="head" @scroll="syncHeadScroll">
407
- <div class="block" ref="block">
408
- <div class="row" ref="row">
431
+ <div ref="table" class="table" role="grid">
432
+ <div
433
+ v-if="resizeState"
434
+ class="resize-indicator"
435
+ :style="{ left: `${resizeState.indicatorX}px` }"
436
+ />
437
+
438
+ <div ref="head" class="container head" @scroll="syncHeadScroll">
439
+ <div ref="block" class="block">
440
+ <div ref="row" class="row">
409
441
  <STableItem
410
442
  v-for="key in ordersToShow"
411
443
  :key
@@ -421,7 +453,9 @@ function getStyles(key: string) {
421
453
  :dropdown="unref(options.columns)[key]?.dropdown"
422
454
  :has-header="showHeader"
423
455
  :resizable="unref(options.columns)[key]?.resizable"
424
- @resize="(value) => updateColWidth(key, value, true)"
456
+ @resize-start="onResizeStart"
457
+ @resize-move="onResizeMove"
458
+ @resize-end="onResizeEnd"
425
459
  >
426
460
  <SInputCheckbox
427
461
  v-if="
@@ -440,8 +474,8 @@ function getStyles(key: string) {
440
474
 
441
475
  <div
442
476
  v-if="!unref(options.loading) && unref(options.records)?.length"
443
- class="container body"
444
477
  ref="body"
478
+ class="container body"
445
479
  @scroll="syncBodyScroll"
446
480
  >
447
481
  <div
@@ -452,10 +486,10 @@ function getStyles(key: string) {
452
486
  position: 'relative'
453
487
  }"
454
488
  >
455
- <div v-for="{ index, key: __key, size, start } in virtualItems" :key="__key">
489
+ <div v-for="{ index: i, key: __key, size, start } in virtualItems" :key="__key">
456
490
  <div
457
491
  class="row"
458
- :class="isSummaryOrLastClass(index)"
492
+ :class="isSummaryOrLastClass(i)"
459
493
  :style="{
460
494
  position: 'absolute',
461
495
  top: 0,
@@ -475,25 +509,24 @@ function getStyles(key: string) {
475
509
  >
476
510
  <STableCell
477
511
  :name="key"
478
- :class="isSummary(index) && 'summary'"
512
+ :class="isSummary(i) && 'summary'"
479
513
  :class-name="unref(options.columns)[key]?.className"
480
- :cell="getCell(key, index)"
481
- :value="recordsWithSummary[index][key]"
482
- :record="recordsWithSummary[index]"
483
- :records="unref(options.records)!"
514
+ :cell="getCell(key, i)"
515
+ :value="recordsWithSummary[i][key]"
516
+ :record="recordsWithSummary[i]"
484
517
  >
485
- <template v-if="key === '__select' && !isSummary(index)">
518
+ <template v-if="key === '__select' && !isSummary(i)">
486
519
  <SInputCheckbox
487
520
  v-if="Array.isArray(selected)"
488
- :model-value="selected.includes(indexes[index])"
489
- @update:model-value="(c) => (c ? addSelected : removeSelected)(indexes[index])"
490
- :disabled="options.disableSelection?.(recordsWithSummary[index]) === true"
521
+ :model-value="selected.includes(indexes[i])"
522
+ :disabled="options.disableSelection?.(recordsWithSummary[i]) === true"
523
+ @update:model-value="(c) => (c ? addSelected : removeSelected)(indexes[i])"
491
524
  />
492
525
  <SInputRadio
493
526
  v-else
494
- :model-value="selected === indexes[index]"
495
- @update:model-value="(c) => updateSelected(c ? indexes[index] : null)"
496
- :disabled="options.disableSelection?.(recordsWithSummary[index]) === true"
527
+ :model-value="selected === indexes[i]"
528
+ :disabled="options.disableSelection?.(recordsWithSummary[i]) === true"
529
+ @update:model-value="(c) => updateSelected(c ? indexes[i] : null)"
497
530
  />
498
531
  </template>
499
532
  </STableCell>
@@ -637,6 +670,16 @@ function getStyles(key: string) {
637
670
  color: var(--c-text-1);
638
671
  }
639
672
 
673
+ .resize-indicator {
674
+ position: absolute;
675
+ top: 0;
676
+ bottom: 0;
677
+ width: 1px;
678
+ background-color: var(--c-border-info-1);
679
+ z-index: 200;
680
+ pointer-events: none;
681
+ }
682
+
640
683
  .STable .col-__select {
641
684
  --table-col-width: calc(48px + var(--table-padding-left));
642
685
 
@@ -21,13 +21,10 @@ const props = defineProps<{
21
21
  cell?: any
22
22
  value: any
23
23
  record: any
24
- records: Record<string, any>
25
24
  }>()
26
25
 
27
26
  const computedCell = computed<TableCell | undefined>(() =>
28
- typeof props.cell === 'function'
29
- ? props.cell(props.value, props.record)
30
- : props.cell
27
+ typeof props.cell === 'function' ? props.cell(props.value, props.record) : props.cell
31
28
  )
32
29
  </script>
33
30
 
@@ -39,7 +36,7 @@ const computedCell = computed<TableCell | undefined>(() =>
39
36
  :record
40
37
  :align="computedCell?.align"
41
38
  :icon="computedCell?.icon"
42
- :text="computedCell?.value"
39
+ :text="computedCell?.value ?? value"
43
40
  :link="computedCell?.link"
44
41
  :color="computedCell?.color"
45
42
  :icon-color="computedCell?.iconColor"
@@ -51,7 +48,7 @@ const computedCell = computed<TableCell | undefined>(() =>
51
48
  :record
52
49
  :align="computedCell.align"
53
50
  :icon="computedCell.icon"
54
- :number="computedCell.value"
51
+ :number="computedCell.value ?? value"
55
52
  :separator="computedCell.separator"
56
53
  :link="computedCell.link"
57
54
  :color="computedCell.color"
@@ -60,47 +57,47 @@ const computedCell = computed<TableCell | undefined>(() =>
60
57
  />
61
58
  <STableCellPath
62
59
  v-else-if="computedCell.type === 'path'"
63
- :segments="computedCell.segments"
60
+ :segments="computedCell.segments ?? value"
64
61
  />
65
62
  <STableCellDay
66
63
  v-else-if="computedCell.type === 'day'"
67
64
  :align="computedCell.align"
68
- :day="computedCell.value"
65
+ :day="computedCell.value ?? value"
69
66
  :format="computedCell.format"
70
67
  :color="computedCell.color"
71
68
  />
72
69
  <STableCellPill
73
70
  v-else-if="computedCell.type === 'pill'"
74
- :pill="computedCell.value"
71
+ :pill="computedCell.value ?? value"
75
72
  :color="computedCell.color"
76
73
  />
77
74
  <STableCellPills
78
75
  v-else-if="computedCell.type === 'pills'"
79
- :pills="computedCell.pills"
76
+ :pills="computedCell.pills ?? value"
80
77
  />
81
78
  <STableCellState
82
79
  v-else-if="computedCell.type === 'state'"
83
- :state="computedCell.label"
80
+ :state="computedCell.label ?? value"
84
81
  :mode="computedCell.mode"
85
82
  />
86
83
  <STableCellIndicator
87
84
  v-else-if="computedCell.type === 'indicator'"
88
- :state="computedCell.state"
85
+ :state="computedCell.state ?? value"
89
86
  :label="computedCell.label"
90
87
  />
91
88
  <STableCellAvatar
92
89
  v-else-if="computedCell.type === 'avatar'"
93
90
  :value
94
91
  :record
95
- :image="computedCell.image"
96
- :name="computedCell.name"
92
+ :image="computedCell.image ?? (value as string).includes('/') ? value : null"
93
+ :name="computedCell.name ?? (value as string).includes('/') ? null : value"
97
94
  :link="computedCell.link"
98
95
  :color="computedCell.color"
99
96
  :on-click="computedCell.onClick"
100
97
  />
101
98
  <STableCellAvatars
102
99
  v-else-if="computedCell.type === 'avatars'"
103
- :avatars="computedCell.avatars"
100
+ :avatars="computedCell.avatars ?? value"
104
101
  :color="computedCell.color"
105
102
  :avatar-count="computedCell.avatarCount"
106
103
  :name-count="computedCell.nameCount"
@@ -109,7 +106,7 @@ const computedCell = computed<TableCell | undefined>(() =>
109
106
  <STableCellActions
110
107
  v-else-if="computedCell.type === 'actions'"
111
108
  :record
112
- :actions="computedCell.actions"
109
+ :actions="computedCell.actions ?? value"
113
110
  />
114
111
  <STableCellCustom
115
112
  v-else-if="computedCell.type === 'custom'"
@@ -120,8 +117,8 @@ const computedCell = computed<TableCell | undefined>(() =>
120
117
  v-else-if="computedCell.type === 'empty'"
121
118
  />
122
119
  <component
123
- v-else-if="computedCell.type === 'component'"
124
120
  :is="computedCell.component"
121
+ v-else-if="computedCell.type === 'component'"
125
122
  :value
126
123
  :record
127
124
  v-bind="computedCell.props"
@@ -48,7 +48,7 @@ const displayNames = computed(() => {
48
48
  <div class="STableCellAvatars" :class="[color]">
49
49
  <div class="container">
50
50
  <div v-if="displayAvatars.length" class="avatars">
51
- <div v-for="(avatar, index) in displayAvatars" :key="index" class="avatar">
51
+ <div v-for="(avatar, i) in displayAvatars" :key="i" class="avatar">
52
52
  <div class="avatar-box">
53
53
  <SAvatar size="mini" :avatar="avatar.image" :name="avatar.name" :tooltip />
54
54
  </div>
@@ -1,19 +1,26 @@
1
1
  <script setup lang="ts">
2
- import { type Day } from '../support/Day'
2
+ import { computed } from 'vue'
3
+ import { type Day, day } from '../support/Day'
3
4
 
4
- defineProps<{
5
+ const props = defineProps<{
5
6
  day?: Day | null
6
7
  align?: 'left' | 'center' | 'right'
7
8
  format?: string
8
9
  color?: 'neutral' | 'soft' | 'mute'
9
10
  }>()
11
+
12
+ const formatted = computed(() => {
13
+ if (props.day) {
14
+ return day(props.day).format(props.format ?? 'YYYY-MM-DD HH:mm:ss')
15
+ }
16
+
17
+ return null
18
+ })
10
19
  </script>
11
20
 
12
21
  <template>
13
22
  <div class="STableCellDay" :class="[align ?? 'left', color ?? 'neutral']">
14
- <div v-if="day" class="value">
15
- {{ day.format(format ?? 'YYYY-MM-DD HH:mm:ss') }}
16
- </div>
23
+ <div v-if="formatted" class="value">{{ formatted }}</div>
17
24
  </div>
18
25
  </template>
19
26
 
@@ -17,7 +17,6 @@ const props = defineProps<{
17
17
  onClick?(value: any, record: any): void
18
18
  }>()
19
19
 
20
- const _value = computed(() => props.number ?? props.value)
21
20
  const _color = computed(() => props.color ?? 'neutral')
22
21
  const _iconColor = computed(() => props.iconColor ?? _color.value)
23
22
 
@@ -31,7 +30,7 @@ const classes = computed(() => [
31
30
  <template>
32
31
  <div class="STableCellNumber" :class="classes">
33
32
  <SLink
34
- v-if="_value != null"
33
+ v-if="number != null"
35
34
  class="container"
36
35
  :href="link"
37
36
  :role="onClick ? 'button' : null"
@@ -41,7 +40,7 @@ const classes = computed(() => [
41
40
  <component :is="icon" class="svg" />
42
41
  </div>
43
42
  <div class="value" :class="_color">
44
- {{ separator ? format(_value) : _value }}
43
+ {{ separator ? format(number) : number }}
45
44
  </div>
46
45
  </SLink>
47
46
  </div>
@@ -16,8 +16,8 @@ function classes(item: TableCellPathSegment) {
16
16
 
17
17
  <template>
18
18
  <div class="STableCellPath">
19
- <template v-for="segment, index in segments" :key="index">
20
- <div v-if="index > 0" class="divider">/</div>
19
+ <template v-for="(segment, i) in segments" :key="i">
20
+ <div v-if="i > 0" class="divider">/</div>
21
21
  <SLink
22
22
  class="text"
23
23
  :class="classes(segment)"
@@ -15,7 +15,6 @@ const props = defineProps<{
15
15
  onClick?(value: any, record: any): void
16
16
  }>()
17
17
 
18
- const _value = computed(() => props.text ?? props.value)
19
18
  const _color = computed(() => props.color ?? 'neutral')
20
19
  const _iconColor = computed(() => props.iconColor ?? _color.value)
21
20
 
@@ -29,7 +28,7 @@ const classes = computed(() => [
29
28
  <template>
30
29
  <div class="STableCellText" :class="classes">
31
30
  <SLink
32
- v-if="_value != null"
31
+ v-if="text != null"
33
32
  class="container"
34
33
  :href="link"
35
34
  :role="onClick ? 'button' : null"
@@ -39,7 +38,7 @@ const classes = computed(() => [
39
38
  <component :is="icon" class="svg" />
40
39
  </div>
41
40
  <div class="text" :class="_color">
42
- {{ _value }}
41
+ {{ text }}
43
42
  </div>
44
43
  </SLink>
45
44
  </div>
@@ -17,13 +17,16 @@ const props = withDefaults(defineProps<{
17
17
  })
18
18
 
19
19
  const emit = defineEmits<{
20
- resize: [value: string]
20
+ 'resize-start': [data: { columnName: string; startX: number; initialX: number }]
21
+ 'resize-move': [data: { deltaX: number }]
22
+ 'resize-end': [data: { columnName: string; finalWidth: string }]
21
23
  }>()
22
24
 
23
25
  const { container, isOpen, toggle } = useFlyout()
24
26
 
25
27
  let startWidth = 0
26
28
  let startPoint = 0
29
+ let originalUserSelect = ''; let originalPointerEvents = ''
27
30
 
28
31
  const column = ref<HTMLElement | null>(null)
29
32
  const dialog = ref<HTMLElement | null>(null)
@@ -67,24 +70,43 @@ watch(isOpen, (value) => {
67
70
  value ? adjustDialogPosition() : stopDialogPositionListener()
68
71
  })
69
72
 
70
- function grip(e: any) {
73
+ function grip(e: MouseEvent) {
71
74
  startWidth = column.value?.offsetWidth ?? 0
72
75
  startPoint = e.pageX
73
76
 
77
+ emit('resize-start', {
78
+ columnName: props.name,
79
+ startX: e.pageX,
80
+ initialX: e.pageX
81
+ })
82
+
83
+ originalUserSelect = document.body.style.userSelect
84
+ originalPointerEvents = document.body.style.pointerEvents
85
+ document.body.style.userSelect = 'none'
86
+ document.body.style.pointerEvents = 'none'
74
87
  document.addEventListener('mousemove', resize)
75
88
  document.addEventListener('mouseup', stopResizeListener)
76
89
  }
77
90
 
78
91
  function resize(e: MouseEvent) {
79
- const movedWidth = e.pageX - startPoint
80
- const resized = startWidth + movedWidth
81
-
82
- emit('resize', resized > -1 ? `${resized}px` : 'var(--table-col-width)')
92
+ const deltaX = e.pageX - startPoint
93
+ emit('resize-move', { deltaX })
83
94
  }
84
95
 
85
- function stopResizeListener() {
96
+ function stopResizeListener(e: MouseEvent) {
86
97
  document.removeEventListener('mousemove', resize)
87
98
  document.removeEventListener('mouseup', stopResizeListener)
99
+ document.body.style.userSelect = originalUserSelect
100
+ document.body.style.pointerEvents = originalPointerEvents
101
+
102
+ const movedWidth = e.pageX - startPoint
103
+ const resized = startWidth + movedWidth
104
+ const finalWidth = resized > -1 ? `${resized}px` : 'var(--table-col-width)'
105
+
106
+ emit('resize-end', {
107
+ columnName: props.name,
108
+ finalWidth
109
+ })
88
110
  }
89
111
 
90
112
  async function adjustDialogPosition() {
@@ -99,14 +121,13 @@ async function adjustDialogPosition() {
99
121
  await nextTick()
100
122
 
101
123
  const dialogWidth = dialog.value?.offsetWidth ?? 0
102
- const position = (window.innerWidth - rect.right) > dialogWidth ? 'right' : 'left'
124
+ const position = window.innerWidth - rect.right > dialogWidth ? 'right' : 'left'
103
125
 
104
126
  top.value = `${rect.top + rect.height - 8}px`
105
- left.value
106
- = `${Math.max(
107
- 16,
108
- position === 'right' ? rect.left - 4 : rect.right - dialogWidth - 4
109
- )}px`
127
+ left.value = `${Math.max(
128
+ 16,
129
+ position === 'right' ? rect.left - 4 : rect.right - dialogWidth - 4
130
+ )}px`
110
131
  }
111
132
 
112
133
  function startDialogPositionListener() {
@@ -121,24 +142,25 @@ function stopDialogPositionListener() {
121
142
  </script>
122
143
 
123
144
  <template>
124
- <div class="STableColumn STableCell" :class="classes" ref="column">
145
+ <div ref="column" class="STableColumn STableCell" :class="classes">
125
146
  <div class="container">
126
147
  <slot>
127
148
  <p class="label">{{ label }}</p>
128
149
 
129
- <div v-if="dropdown" class="action" ref="container">
150
+ <div v-if="dropdown" ref="container" class="action">
130
151
  <button class="button" :class="{ active: buttonActive }" @click="toggle">
131
152
  <IconDotsThree class="icon" />
132
153
  </button>
133
154
 
134
155
  <transition name="fade">
135
- <div v-if="isOpen" class="dialog" :style="{ top, left }" ref="dialog">
156
+ <div v-if="isOpen" ref="dialog" class="dialog" :style="{ top, left }">
136
157
  <SDropdown :sections="dropdown" />
137
158
  </div>
138
159
  </transition>
139
160
  </div>
140
161
 
141
162
  <div v-if="resizable" class="grip" @mousedown="grip" />
163
+ <div v-if="resizable" class="resize-indicator" />
142
164
  </slot>
143
165
  </div>
144
166
  </div>
@@ -42,10 +42,18 @@ const hasNext = computed(() => {
42
42
  <p class="info">{{ format(from) }}–{{ format(to) }} of {{ format(_total) }}</p>
43
43
 
44
44
  <div v-if="onPrev && onNext" class="actions">
45
- <button class="button prev" :class="{ active: hasPrev }" @click="() => hasPrev && onPrev?.()">
45
+ <button
46
+ class="button prev"
47
+ :class="{ active: hasPrev }"
48
+ @click="() => hasPrev && onPrev?.()"
49
+ >
46
50
  <IconCaretLeft class="icon" />
47
51
  </button>
48
- <button class="button next" :class="{ active: hasNext }" @click="() => hasNext && onNext?.()">
52
+ <button
53
+ class="button next"
54
+ :class="{ active: hasNext }"
55
+ @click="() => hasNext && onNext?.()"
56
+ >
49
57
  <IconCaretRight class="icon" />
50
58
  </button>
51
59
  </div>
@@ -8,7 +8,6 @@ const props = defineProps<{
8
8
  total?: number | null
9
9
  menu?: TableMenu[] | TableMenu[][]
10
10
  borderless?: boolean
11
- onReset?(): void
12
11
  selected?: unknown[]
13
12
  }>()
14
13
 
@@ -9,15 +9,15 @@ const props = defineProps<{
9
9
 
10
10
  const normalizedMenu = computed(() => {
11
11
  return Array.isArray(props.menu[0])
12
- ? props.menu as TableMenu[][]
13
- : [props.menu] as TableMenu[][]
12
+ ? (props.menu as TableMenu[][])
13
+ : ([props.menu] as TableMenu[][])
14
14
  })
15
15
  </script>
16
16
 
17
17
  <template>
18
18
  <div class="STableHeaderMenu">
19
- <div v-for="items, index in normalizedMenu" :key="index" class="group">
20
- <div v-if="index > 0" class="divider" />
19
+ <div v-for="(items, i) in normalizedMenu" :key="i" class="group">
20
+ <div v-if="i > 0" class="divider" />
21
21
  <div v-for="item in items" :key="item.label" class="item">
22
22
  <STableHeaderMenuItem
23
23
  :label="item.label"
@@ -14,7 +14,7 @@ const { container, isOpen, toggle } = useFlyout()
14
14
  </script>
15
15
 
16
16
  <template>
17
- <div class="STableHeaderMenuItem" ref="container">
17
+ <div ref="container" class="STableHeaderMenuItem">
18
18
  <button class="button" :class="[state]" @click="toggle">
19
19
  <span class="label">{{ label }}</span>
20
20
  <span v-if="state !== 'indicate'" class="caret">
@@ -97,14 +97,14 @@ onBeforeUnmount(() => {
97
97
  </script>
98
98
 
99
99
  <template>
100
- <component ref="root" :is="tag" class="STooltip" :class="rootClasses" :tabindex>
101
- <component :is="triggerTag" class="trigger" ref="trigger">
100
+ <component :is="tag" ref="root" class="STooltip" :class="rootClasses" :tabindex>
101
+ <component :is="triggerTag" ref="trigger" class="trigger">
102
102
  <slot />
103
103
  </component>
104
104
 
105
105
  <Teleport to="#sefirot-modals">
106
106
  <Transition name="fade">
107
- <div v-show="on" class="container" :class="containerClasses" ref="content">
107
+ <div v-show="on" ref="content" class="container" :class="containerClasses">
108
108
  <div v-if="$slots.text" class="tip"><slot name="text" /></div>
109
109
  <div v-else-if="text" class="tip" v-html="text" />
110
110
  </div>
@@ -1,6 +1,6 @@
1
- import { useHttpConfig } from 'sefirot/stores/HttpConfig'
2
1
  import { type Ref, type WatchSource, ref, watch } from 'vue'
3
2
  import { Http } from '../http/Http'
3
+ import { useHttpConfig } from '../stores/HttpConfig'
4
4
  import { tryOnMounted } from './Utils'
5
5
 
6
6
  export interface Query<Data = any> {
@@ -1,22 +1,24 @@
1
- import { type HttpOptions } from 'sefirot/stores/HttpConfig'
2
- import { useSetupHttp } from './Http'
3
- import { type HasLang, useSetupLang } from './Lang'
4
- import { type HasTheme, useSetupTheme } from './Theme'
1
+ import { type HttpOptions, useHttpConfig } from '../stores/HttpConfig'
2
+ import { type Lang, getBrowserLang, provideLang } from './Lang'
3
+ import { type Theme, useTheme } from './Theme'
5
4
 
6
- export interface SetupAppUser extends HasLang, HasTheme {}
5
+ export interface SetupAppUser {
6
+ lang?: Lang
7
+ theme?: Theme
8
+ }
7
9
 
8
10
  export interface SetupAppOptions {
9
11
  http?: HttpOptions
10
12
  }
11
13
 
12
14
  export function useSetupApp(): (user?: SetupAppUser | null, options?: SetupAppOptions) => void {
13
- const setupLang = useSetupLang()
14
- const setupTheme = useSetupTheme()
15
- const setupHttp = useSetupHttp()
15
+ const theme = useTheme()
16
+ const httpConfig = useHttpConfig()
16
17
 
17
18
  return (user, options) => {
18
- setupLang(user)
19
- setupTheme(user)
20
- setupHttp(user, options?.http)
19
+ const lang = user?.lang ?? getBrowserLang()
20
+ provideLang(lang)
21
+ if (user?.theme) { theme.value = user.theme }
22
+ httpConfig.apply({ lang, ...options?.http })
21
23
  }
22
24
  }