@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
package/client.d.ts CHANGED
@@ -7,3 +7,8 @@ declare module 'v-calendar' {
7
7
  export * from 'v-calendar/dist/types/src/index.d.ts'
8
8
  export { default } from 'v-calendar/dist/types/src/index.d.ts'
9
9
  }
10
+
11
+ interface NumberConstructor {
12
+ isFinite(value: unknown): value is number
13
+ isInteger(value: unknown): value is number
14
+ }
package/config/nuxt.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ // eslint-disable-next-line ts/ban-ts-comment
1
2
  // @ts-ignore
2
3
  declare const defineConfig: import('nuxt/config').DefineNuxtConfig
3
4
 
package/config/nuxt.js CHANGED
@@ -5,25 +5,28 @@ import icons from 'unplugin-icons/nuxt'
5
5
  import { mergeConfig } from 'vite'
6
6
  import { baseConfig as baseViteConfig } from './vite.js'
7
7
 
8
- delete baseViteConfig.plugins
9
- delete baseViteConfig.resolve?.alias
10
-
11
8
  export const baseConfig = {
12
9
  alias: { sefirot: fileURLToPath(new URL('../lib', import.meta.url)) },
13
10
  app: { teleportId: 'sefirot-modals' },
14
11
  modules: [
15
12
  /**
13
+ * @this {any}
16
14
  * @param {any} _
17
15
  * @param {any} nuxt
18
16
  */
19
17
  function (_, nuxt) {
20
- // eslint-disable-next-line @typescript-eslint/no-invalid-this
21
18
  return icons.bind(this, { scale: 1 }, nuxt)()
22
19
  }
23
20
  ],
24
21
  postcss: { plugins: { 'postcss-nested': {} } },
25
22
  telemetry: false,
26
- vite: baseViteConfig
23
+ vite: {
24
+ ...baseViteConfig,
25
+ resolve: { ...baseViteConfig.resolve, alias: {} },
26
+ plugins: baseViteConfig.plugins?.filter(
27
+ (plugin) => plugin && 'name' in plugin && plugin.name !== 'unplugin-icons'
28
+ )
29
+ }
27
30
  }
28
31
 
29
32
  export function defineConfig(config = {}) {
package/config/vite.js CHANGED
@@ -1,16 +1,5 @@
1
1
  // @ts-check
2
2
 
3
- /**
4
- * Adapted from
5
- * @see https://github.com/unplugin/unplugin-icons/blob/67fd9b7791dc1754cb8dc46b854b22c8bb4cf380/src/core/compilers/vue3.ts
6
- * @see https://github.com/unplugin/unplugin-icons/blob/639ec9691e022e52c641d0f96f585dbf04dab095/src/core/svgId.ts
7
- *
8
- * Original licenses:
9
- *
10
- * Copyright (c) 2020 Anthony Fu <https://github.com/antfu>
11
- * @license MIT
12
- */
13
-
14
3
  import { fileURLToPath } from 'node:url'
15
4
  import MagicString from 'magic-string'
16
5
  import icons from 'unplugin-icons/vite'
@@ -48,6 +37,7 @@ export const baseConfig = {
48
37
 
49
38
  // list the client-side direct dependencies/peerDependencies which get bundled
50
39
  dedupe: [
40
+ '@popperjs/core',
51
41
  '@sentry/browser',
52
42
  '@sentry/vue',
53
43
  '@tanstack/vue-virtual',
@@ -84,9 +74,10 @@ export const baseConfig = {
84
74
  'dayjs/plugin/relativeTime',
85
75
  'dayjs/plugin/timezone',
86
76
  'dayjs/plugin/utc',
77
+ 'file-saver',
78
+ 'isomorphic-dompurify',
87
79
  'markdown-it > argparse',
88
- 'markdown-it > entities',
89
- 'file-saver'
80
+ 'markdown-it > entities'
90
81
  ],
91
82
  exclude: [
92
83
  'markdown-it'
@@ -12,8 +12,8 @@ defineProps<{
12
12
  <template>
13
13
  <div class="SActionList">
14
14
  <SActionListItem
15
- v-for="item, index in list"
16
- :key="index"
15
+ v-for="(item, i) in list"
16
+ :key="i"
17
17
  :lead-icon="item.leadIcon"
18
18
  :label="item.label"
19
19
  :link="item.link"
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { type Component, ref } from 'vue'
2
+ import { type Component, ref, useTemplateRef } from 'vue'
3
3
  import { type DropdownSection, useManualDropdownPosition } from '../composables/Dropdown'
4
4
  import { useFlyout } from '../composables/Flyout'
5
5
  import SButton, { type Mode, type Size, type Tooltip, type Type } from './SButton.vue'
@@ -29,21 +29,52 @@ const props = withDefaults(defineProps<{
29
29
  dropdownAlign: 'left'
30
30
  })
31
31
 
32
- const container = ref<any>(null)
32
+ const containerRef = useTemplateRef('container')
33
+ const dropdownRef = useTemplateRef('dropdown')
33
34
 
34
- const { isOpen, toggle } = useFlyout(container)
35
- const { position, update: updatePosition } = useManualDropdownPosition(container)
35
+ const { isOpen, toggle } = useFlyout(containerRef)
36
+ const { position: verticalPlacement, update: updateVerticalPlacement } =
37
+ useManualDropdownPosition(containerRef)
38
+
39
+ const actualAlign = ref(props.dropdownAlign)
40
+
41
+ function calculateOptimalAlign(dropdownElement: HTMLElement): 'left' | 'right' {
42
+ // Temporarily show the dropdown to measure it (similar to tooltip approach)
43
+ const originalDisplay = dropdownElement.style.display
44
+ dropdownElement.style.display = 'block'
45
+ const dropdownRect = dropdownElement.getBoundingClientRect()
46
+ dropdownElement.style.display = originalDisplay
47
+
48
+ const dropdownWidth = dropdownRect.width
49
+
50
+ const viewportWidth = window.innerWidth
51
+ const containerRect = containerRef.value!.getBoundingClientRect()
52
+
53
+ const spaceOnRight = viewportWidth - containerRect.left
54
+ const spaceOnLeft = containerRect.right
55
+
56
+ if (props.dropdownAlign === 'left') {
57
+ return spaceOnRight >= dropdownWidth ? 'left' : 'right'
58
+ }
59
+
60
+ return spaceOnLeft >= dropdownWidth ? 'right' : 'left'
61
+ }
36
62
 
37
63
  async function onOpen() {
38
64
  if (!props.disabled) {
39
- updatePosition()
65
+ updateVerticalPlacement()
66
+
67
+ if (dropdownRef.value) {
68
+ actualAlign.value = calculateOptimalAlign(dropdownRef.value)
69
+ }
70
+
40
71
  toggle()
41
72
  }
42
73
  }
43
74
  </script>
44
75
 
45
76
  <template>
46
- <div class="SActionMenu" :class="[{ block }, dropdownAlign]" ref="container">
77
+ <div ref="container" class="SActionMenu" :class="[{ block }, actualAlign]">
47
78
  <div class="button">
48
79
  <SButton
49
80
  :tag
@@ -64,7 +95,12 @@ async function onOpen() {
64
95
  @click="onOpen"
65
96
  />
66
97
  </div>
67
- <div v-if="isOpen" class="dropdown" :class="position">
98
+ <div
99
+ ref="dropdown"
100
+ class="dropdown"
101
+ :class="verticalPlacement"
102
+ :style="{ display: isOpen ? 'block' : 'none' }"
103
+ >
68
104
  <SDropdown :sections="options" />
69
105
  </div>
70
106
  </div>
@@ -28,7 +28,7 @@ const classes = computed(() => [
28
28
  const initial = computed(() => props.name?.charAt(0).toUpperCase())
29
29
 
30
30
  const tooltipPosition = computed(() => {
31
- return (props.tooltip && typeof props.tooltip === 'object')
31
+ return props.tooltip && typeof props.tooltip === 'object'
32
32
  ? props.tooltip.position || 'top'
33
33
  : 'top'
34
34
  })
@@ -27,8 +27,8 @@ const count = computed(() => {
27
27
  <template>
28
28
  <div class="SAvatarStack" :class="size">
29
29
  <SAvatar
30
- v-for="(avatar, index) in avatars"
31
- :key="index"
30
+ v-for="(avatar, i) in avatars"
31
+ :key="i"
32
32
  :size
33
33
  :avatar="avatar.image"
34
34
  :name="avatar.name"
@@ -49,11 +49,11 @@ const count = computed(() => {
49
49
  overflow: hidden;
50
50
  }
51
51
 
52
- &.mini > :deep(*):not(:last-child) { margin-right: -6px }
53
- &.small > :deep(*):not(:last-child) { margin-right: -8px }
54
- &.medium > :deep(*):not(:last-child) { margin-right: -8px }
55
- &.large > :deep(*):not(:last-child) { margin-right: -12px }
56
- &.jumbo > :deep(*):not(:last-child) { margin-right: -16px }
52
+ &.mini > :deep(*):not(:last-child) { margin-right: -6px; }
53
+ &.small > :deep(*):not(:last-child) { margin-right: -8px; }
54
+ &.medium > :deep(*):not(:last-child) { margin-right: -8px; }
55
+ &.large > :deep(*):not(:last-child) { margin-right: -12px; }
56
+ &.jumbo > :deep(*):not(:last-child) { margin-right: -16px; }
57
57
  }
58
58
 
59
59
  .more {
@@ -69,10 +69,10 @@ const count = computed(() => {
69
69
  z-index: 1;
70
70
  height: 100%;
71
71
 
72
- .mini & { font-size: 10px }
73
- .small & { font-size: 10px }
74
- .medium & { font-size: 12px }
75
- .large & { font-size: 12px }
76
- .jumbo & { font-size: 14px }
72
+ .mini & { font-size: 10px; }
73
+ .small & { font-size: 10px; }
74
+ .medium & { font-size: 12px; }
75
+ .large & { font-size: 12px; }
76
+ .jumbo & { font-size: 14px; }
77
77
  }
78
78
  </style>
@@ -82,9 +82,7 @@ const classes = computed(() => [
82
82
  ])
83
83
 
84
84
  const computedTag = computed(() => {
85
- return props.tag
86
- ? props.tag
87
- : props.href ? SLink : 'button'
85
+ return props.tag ? props.tag : props.href ? SLink : 'button'
88
86
  })
89
87
 
90
88
  const slots = useSlots()
@@ -96,7 +94,7 @@ const hasTooltip = computed(() => {
96
94
  )
97
95
  })
98
96
 
99
- function handleClick(): void {
97
+ function onClick(): void {
100
98
  if (!props.loading) {
101
99
  props.disabled ? emit('disabled-click') : emit('click')
102
100
  }
@@ -109,8 +107,8 @@ function handleClick(): void {
109
107
  :tag="typeof tooltip === 'object' ? tooltip.tag : undefined"
110
108
  :text="typeof tooltip === 'object' ? unref(tooltip.text) : tooltip"
111
109
  :position="typeof tooltip === 'object' ? tooltip.position : undefined"
112
- :display="typeof tooltip === 'object' ? tooltip.display ?? 'inline-block' : 'inline-block'"
113
- :trigger="typeof tooltip === 'object' ? tooltip.trigger ?? 'both' : 'both'"
110
+ :display="typeof tooltip === 'object' ? (tooltip.display ?? 'inline-block') : 'inline-block'"
111
+ :trigger="typeof tooltip === 'object' ? (tooltip.trigger ?? 'both') : 'both'"
114
112
  :timeout="typeof tooltip === 'object' ? tooltip.timeout : undefined"
115
113
  :tabindex="-1"
116
114
  >
@@ -121,7 +119,7 @@ function handleClick(): void {
121
119
  :class="classes"
122
120
  :href
123
121
  role="button"
124
- @click="handleClick"
122
+ @click="onClick"
125
123
  >
126
124
  <span class="content">
127
125
  <span v-if="_leadIcon" class="icon" :class="iconMode">
@@ -10,13 +10,13 @@ const props = defineProps<{
10
10
  mode?: Mode
11
11
  }>()
12
12
 
13
+ const { isCollapsed } = provideCardState()
14
+
13
15
  const classes = computed(() => [
14
16
  props.size,
15
17
  props.mode ?? 'neutral',
16
18
  { collapsed: isCollapsed.value }
17
19
  ])
18
-
19
- const { isCollapsed } = provideCardState()
20
20
  </script>
21
21
 
22
22
  <template>
@@ -83,26 +83,51 @@ function renderChart({
83
83
  // Set dimensions and margins
84
84
  const vertical = props.type === 'vertical'
85
85
 
86
- const maxKeyLength = props.data.reduce((a, b) => Math.max(a, b.key.length), Number.NEGATIVE_INFINITY)
87
- const maxValueLength = props.data.reduce((a, b) => Math.max(a, b.value.toLocaleString().length), Number.NEGATIVE_INFINITY)
86
+ const maxKeyLength = props.data.reduce(
87
+ (a, b) => Math.max(a, b.key.length),
88
+ Number.NEGATIVE_INFINITY
89
+ )
90
+ const maxValueLength = props.data.reduce(
91
+ (a, b) => Math.max(a, b.value.toLocaleString().length),
92
+ Number.NEGATIVE_INFINITY
93
+ )
88
94
 
89
95
  const maxVerticalTickWidthInCh = vertical ? maxValueLength : maxKeyLength
90
- const maxVerticalTickWidthInPx = getTextSize('0'.repeat(maxVerticalTickWidthInCh), `400 ${props.tickFontSize} ${font}`).width
91
- const verticalLabelWidthInPx = props.yLabel ? getTextSize(props.yLabel, `400 ${props.yLabelFontSize} ${font}`).height : 0
96
+ const maxVerticalTickWidthInPx = getTextSize(
97
+ '0'.repeat(maxVerticalTickWidthInCh),
98
+ `400 ${props.tickFontSize} ${font}`
99
+ ).width
100
+ const verticalLabelWidthInPx = props.yLabel
101
+ ? getTextSize(props.yLabel, `400 ${props.yLabelFontSize} ${font}`).height
102
+ : 0
92
103
  const gapBetweenVerticalLabelAndTicks = props.yLabel ? props.yLabelTickGap : 0
93
104
 
94
- const maxHorizontalTickHeightInPx = getTextSize('0', `400 ${props.tickFontSize} ${font}`).height // wrapping isn't supported
95
- const horizontalLabelHeightInPx = props.xLabel ? getTextSize(props.xLabel, `400 ${props.xLabelFontSize} ${font}`).height : 0
105
+ const maxHorizontalTickHeightInPx = getTextSize(
106
+ '0',
107
+ `400 ${props.tickFontSize} ${font}`
108
+ ).height // wrapping isn't supported
109
+ const horizontalLabelHeightInPx = props.xLabel
110
+ ? getTextSize(props.xLabel, `400 ${props.xLabelFontSize} ${font}`).height
111
+ : 0
96
112
  const gapBetweenHorizontalLabelAndTicks = props.xLabel ? props.xLabelTickGap : 0
97
113
 
98
- const xLabelOffset = props.xLabelOffset ?? horizontalLabelHeightInPx + 9 + maxHorizontalTickHeightInPx + gapBetweenHorizontalLabelAndTicks
99
- const yLabelOffset = props.yLabelOffset ?? 9 + maxVerticalTickWidthInPx + gapBetweenVerticalLabelAndTicks
114
+ const xLabelOffset = props.xLabelOffset
115
+ ?? horizontalLabelHeightInPx + 9 + maxHorizontalTickHeightInPx + gapBetweenHorizontalLabelAndTicks
116
+ const yLabelOffset = props.yLabelOffset
117
+ ?? 9 + maxVerticalTickWidthInPx + gapBetweenVerticalLabelAndTicks
100
118
 
101
119
  const margin = {
102
120
  top: props.margins?.top ?? 30,
103
121
  right: props.margins?.right ?? 30,
104
- bottom: (props.margins?.bottom ?? 30) + horizontalLabelHeightInPx + xLabelOffset - (props.xLabel ? 9 : 0),
105
- left: (props.margins?.left ?? 30) + verticalLabelWidthInPx + yLabelOffset
122
+ bottom:
123
+ (props.margins?.bottom ?? 30)
124
+ + horizontalLabelHeightInPx
125
+ + xLabelOffset
126
+ - (props.xLabel ? 9 : 0),
127
+ left:
128
+ (props.margins?.left ?? 30)
129
+ + verticalLabelWidthInPx
130
+ + yLabelOffset
106
131
  }
107
132
 
108
133
  const width = clientWidth - margin.left - margin.right
@@ -224,8 +249,8 @@ function renderChart({
224
249
  .append('g')
225
250
  .attr('transform', (d) =>
226
251
  vertical
227
- ? `translate(${(paddedScale(d.key)! - groupOffset)},0)`
228
- : `translate(0,${(paddedScale(d.key)! - groupOffset)})`
252
+ ? `translate(${paddedScale(d.key)! - groupOffset},0)`
253
+ : `translate(0,${paddedScale(d.key)! - groupOffset})`
229
254
  )
230
255
 
231
256
  // Each group gets a transparent rect covering the full band (using paddedScale.step())
@@ -180,12 +180,18 @@ function renderChart({
180
180
  // Calculate radius and center the chart
181
181
  const r_k = props.half ? 0.25 : 0.5
182
182
  const radius = Math.min(height_2, (width - legendWidth) / (2 + (props.legend ? r_k : 0)))
183
- const innerRadius = props.innerRadius?.(radius) ?? (props.type === 'pie' ? 6 : Math.max(radius / 1.5, radius - 50))
184
-
185
- legendGroup
186
- ?.attr('transform', `translate(${radius * (1 + r_k)},${-(props.half ? height_2 : 0) / 2 - legendHeight / 2})`)
187
- svg
188
- .attr('transform', `translate(${margin.left + width_2 - (props.legend ? radius * r_k + legendWidth : 0) / 2},${margin.top + height_2})`)
183
+ const innerRadius = props.innerRadius?.(radius)
184
+ ?? (props.type === 'pie' ? 6 : Math.max(radius / 1.5, radius - 50))
185
+
186
+ legendGroup?.attr(
187
+ 'transform',
188
+ `translate(${radius * (1 + r_k)},${-(props.half ? height_2 : 0) / 2 - legendHeight / 2})`
189
+ )
190
+ svg.attr(
191
+ 'transform',
192
+ `translate(${margin.left + width_2 - (props.legend ? radius * r_k + legendWidth : 0) / 2}`
193
+ + `,${margin.top + height_2})`
194
+ )
189
195
 
190
196
  // Create arc generator
191
197
  const arc = d3
@@ -275,7 +281,7 @@ function renderChart({
275
281
  })
276
282
  .attr('dy', '0.35em')
277
283
  .attr('fill', c.text2)
278
- .attr('text-anchor', (d) => leftOrRight(d) === 1 ? 'start' : 'end')
284
+ .attr('text-anchor', (d) => (leftOrRight(d) === 1 ? 'start' : 'end'))
279
285
  .style('font-size', props.labelFontSize)
280
286
  .html((d) => props.labelFormat(d.data))
281
287
 
@@ -21,14 +21,12 @@ setCollapse(props.collapsed)
21
21
  const el = shallowRef<HTMLElement | null>(null)
22
22
 
23
23
  const icon = computed(() => {
24
- return isCollapsed.value
25
- ? IconArrowsOutLineVertical
26
- : IconArrowsInLineVertical
24
+ return isCollapsed.value ? IconArrowsOutLineVertical : IconArrowsInLineVertical
27
25
  })
28
26
  </script>
29
27
 
30
28
  <template>
31
- <div class="SControlActionBarCollapse" ref="el">
29
+ <div ref="el" class="SControlActionBarCollapse">
32
30
  <SControlActionBarButton
33
31
  :as
34
32
  :icon
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import IconMagnifyingGlass from '~icons/ph/magnifying-glass-bold'
3
- import { computed } from 'vue'
3
+ import { type Component, computed } from 'vue'
4
4
  import { useControlSize } from '../composables/Control'
5
5
  import { useTrans } from '../composables/Lang'
6
6
  import { type Validatable } from '../composables/Validation'
@@ -8,7 +8,7 @@ import SInputText, { type Align, type TextColor } from './SInputText.vue'
8
8
 
9
9
  const props = defineProps<{
10
10
  placeholder?: string
11
- unitAfter?: any
11
+ unitAfter?: Component | string
12
12
  textColor?: TextColor | ((value: string | null) => TextColor)
13
13
  align?: Align
14
14
  disabled?: boolean
@@ -52,7 +52,12 @@ const _value = computed(() => {
52
52
  type="search"
53
53
  :placeholder="placeholder ?? t.placeholder"
54
54
  :unit-before="IconMagnifyingGlass"
55
+ :unit-after
56
+ :text-color
57
+ :align
58
+ :disabled
55
59
  :model-value="_value"
60
+ :display-value
56
61
  :validation
57
62
  hide-error
58
63
  @update:model-value="$emit('update:model-value', $event)"
@@ -14,9 +14,7 @@ const props = withDefaults(defineProps<{
14
14
  maxWidth: '100%'
15
15
  })
16
16
 
17
- const {
18
- labelWidth
19
- } = useDataListState()
17
+ const { labelWidth } = useDataListState()
20
18
 
21
19
  const slots = useSlots()
22
20
 
@@ -26,7 +26,7 @@ const _avatar = computed(() => {
26
26
 
27
27
  <template>
28
28
  <div v-if="_avatar?.length" class="SDescAvatar" :class="[dir]">
29
- <div v-for="a, i in _avatar" :key="i" class="value">
29
+ <div v-for="(a, i) in _avatar" :key="i" class="value">
30
30
  <SAvatar
31
31
  size="nano"
32
32
  :avatar="a.avatar"
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
3
  import { useSlotValue } from '../composables/Utils'
4
- import { type Day } from '../support/Day'
4
+ import { type Day, day } from '../support/Day'
5
5
  import SDescEmpty from './SDescEmpty.vue'
6
6
 
7
7
  const props = defineProps<{
@@ -17,7 +17,7 @@ const _value = computed(() => {
17
17
  }
18
18
 
19
19
  if (props.value) {
20
- return props.value.format(props.format ?? 'YYYY-MM-DD HH:mm:ss')
20
+ return day(props.value).format(props.format ?? 'YYYY-MM-DD HH:mm:ss')
21
21
  }
22
22
 
23
23
  return null
@@ -15,16 +15,14 @@ const props = defineProps<{
15
15
  }>()
16
16
 
17
17
  const items = computed(() => {
18
- return props.item
19
- ? Array.isArray(props.item) ? props.item : [props.item]
20
- : null
18
+ return props.item ? (Array.isArray(props.item) ? props.item : [props.item]) : null
21
19
  })
22
20
  </script>
23
21
 
24
22
  <template>
25
23
  <div v-if="items && items.length" class="SDescFile">
26
24
  <div class="value">
27
- <div v-for="item, index in items" :key="index" class="item">
25
+ <div v-for="(item, i) in items" :key="i" class="item">
28
26
  <div class="data">
29
27
  <div class="icon"><IconFileText class="icon-svg" /></div>
30
28
  <div class="name">{{ item.name }}</div>
@@ -7,7 +7,8 @@ defineProps<{
7
7
  }>()
8
8
 
9
9
  const labelWidthProp = inject<() => string | number | undefined>(
10
- 'sefirot-desc-label-width', () => undefined
10
+ 'sefirot-desc-label-width',
11
+ () => undefined
11
12
  )
12
13
 
13
14
  const labelWidth = computed(() => {
@@ -44,7 +44,7 @@ function isActionButton(action: Action): action is ActionButton {
44
44
  <template v-else>{{ value }}</template>
45
45
  </div>
46
46
  <div v-if="actions?.length" class="actions">
47
- <template v-for="action, index in actions" :key="index">
47
+ <template v-for="(action, i) in actions" :key="i">
48
48
  <SButton
49
49
  v-if="isActionButton(action)"
50
50
  type="text"
@@ -12,13 +12,8 @@ const props = defineProps<{
12
12
  const slotValue = useSlotValue()
13
13
 
14
14
  const link = computed(() => {
15
- if (props.href) {
16
- return props.href
17
- }
18
-
19
- return slotValue.value
20
- ? slotValue.value
21
- : props.value
15
+ if (props.href) { return props.href }
16
+ return slotValue.value ? slotValue.value : props.value
22
17
  })
23
18
  </script>
24
19
 
@@ -13,16 +13,14 @@ const props = defineProps<{
13
13
  }>()
14
14
 
15
15
  const pills = computed(() => {
16
- return props.pill
17
- ? Array.isArray(props.pill) ? props.pill : [props.pill]
18
- : null
16
+ return props.pill ? (Array.isArray(props.pill) ? props.pill : [props.pill]) : null
19
17
  })
20
18
  </script>
21
19
 
22
20
  <template>
23
21
  <div v-if="pills && pills.length" class="SDescPill">
24
22
  <div class="value">
25
- <div v-for="pill, index in pills" :key="index" class="pill">
23
+ <div v-for="(pill, i) in pills" :key="i" class="pill">
26
24
  <SPill tag="div" size="mini" :mode="pill.mode" :label="pill.label" />
27
25
  </div>
28
26
  </div>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { useLinkifyIt } from 'sefirot/composables/Markdown'
3
2
  import { computed } from 'vue'
3
+ import { useLinkifyIt } from '../composables/Markdown'
4
4
  import { useHasSlotContent } from '../composables/Utils'
5
5
  import SDescEmpty from './SDescEmpty.vue'
6
6
 
@@ -32,10 +32,10 @@ const _value = computed(() => {
32
32
 
33
33
  <template>
34
34
  <div v-if="hasSlot || _value" class="SDescText" :class="classes">
35
- <div class="value" v-if="hasSlot">
35
+ <div v-if="hasSlot" class="value">
36
36
  <slot />
37
37
  </div>
38
- <div class="value" v-else v-html="_value" />
38
+ <div v-else class="value" v-html="_value" />
39
39
  </div>
40
40
  <SDescEmpty v-else />
41
41
  </template>
@@ -10,7 +10,7 @@ defineProps<{
10
10
  <template>
11
11
  <div class="SDropdown">
12
12
  <div class="container">
13
- <div v-for="(section, index) in sections" :key="index" class="section">
13
+ <div v-for="(section, i) in sections" :key="i" class="section">
14
14
  <SDropdownSection :section />
15
15
  </div>
16
16
  </div>
@@ -2,7 +2,10 @@
2
2
  import IconCheck from '~icons/ph/check'
3
3
  import Fuse from 'fuse.js'
4
4
  import { type MaybeRef, computed, onMounted, ref, unref } from 'vue'
5
- import { type DropdownSectionFilterOption, type DropdownSectionFilterSelectedValue } from '../composables/Dropdown'
5
+ import {
6
+ type DropdownSectionFilterOption,
7
+ type DropdownSectionFilterSelectedValue
8
+ } from '../composables/Dropdown'
6
9
  import { useTrans } from '../composables/Lang'
7
10
  import SDropdownSectionFilterItem from './SDropdownSectionFilterItem.vue'
8
11
 
@@ -36,7 +39,7 @@ const fuse = computed(() => {
36
39
  })
37
40
 
38
41
  const filteredOptions = computed(() => {
39
- return (!props.search || !query.value)
42
+ return !props.search || !query.value
40
43
  ? unref(enabledOptions)
41
44
  : fuse.value.search(query.value).map((r) => r.item)
42
45
  })
@@ -47,10 +50,7 @@ onMounted(() => {
47
50
 
48
51
  function isActive(value: any) {
49
52
  const selected = unref(props.selected)
50
-
51
- return Array.isArray(selected)
52
- ? selected.includes(value)
53
- : selected === value
53
+ return Array.isArray(selected) ? selected.includes(value) : selected === value
54
54
  }
55
55
 
56
56
  function focusPrev(event: any) {
@@ -61,16 +61,16 @@ function focusNext(event: any) {
61
61
  event.target.parentNode.nextElementSibling?.firstElementChild?.focus()
62
62
  }
63
63
 
64
- function handleClick(option: DropdownSectionFilterOption, value: any) {
65
- option.onClick && option.onClick(value)
66
- props.onClick && props.onClick(value)
64
+ function onClick(option: DropdownSectionFilterOption, value: any) {
65
+ option.onClick?.(value)
66
+ props.onClick?.(value)
67
67
  }
68
68
  </script>
69
69
 
70
70
  <template>
71
71
  <div class="SDropdownSectionFilter">
72
72
  <div v-if="search" class="search">
73
- <input class="input" :placeholder="t.i_ph" ref="input" v-model="query">
73
+ <input ref="input" v-model="query" class="input" :placeholder="t.i_ph">
74
74
  </div>
75
75
 
76
76
  <ul v-if="filteredOptions.length" class="list">
@@ -81,7 +81,7 @@ function handleClick(option: DropdownSectionFilterOption, value: any) {
81
81
  tabindex="0"
82
82
  @keyup.up.prevent="focusPrev"
83
83
  @keyup.down.prevent="focusNext"
84
- @click="handleClick(option, option.value)"
84
+ @click="onClick(option, option.value)"
85
85
  >
86
86
  <span v-if="Array.isArray(unref(selected))" class="checkbox">
87
87
  <span class="checkbox-box">