@globalbrain/sefirot 3.15.0 → 3.16.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.
@@ -36,6 +36,8 @@ const props = defineProps<{
36
36
  type?: Type
37
37
  mode?: Mode
38
38
  icon?: any
39
+ leadIcon?: any
40
+ trailIcon?: any
39
41
  iconMode?: Mode
40
42
  label?: string
41
43
  labelMode?: Mode
@@ -52,12 +54,15 @@ const emit = defineEmits<{
52
54
  (e: 'disabled-click'): void
53
55
  }>()
54
56
 
57
+ const _leadIcon = computed(() => props.leadIcon ?? props.icon)
58
+
55
59
  const classes = computed(() => [
56
60
  props.size ?? 'medium',
57
61
  props.type ?? 'fill',
58
62
  props.mode ?? 'default',
59
63
  { 'has-label': props.label },
60
- { 'has-icon': props.icon },
64
+ { 'has-lead-icon': _leadIcon.value },
65
+ { 'has-trail-icon': props.trailIcon },
61
66
  { loading: props.loading },
62
67
  { rounded: props.rounded },
63
68
  { block: props.block },
@@ -104,12 +109,15 @@ function handleClick(): void {
104
109
  @click="handleClick"
105
110
  >
106
111
  <span class="content">
107
- <span v-if="icon" class="icon" :class="iconMode">
108
- <SIcon :icon="icon" class="icon-svg" />
112
+ <span v-if="_leadIcon" class="icon" :class="iconMode">
113
+ <SIcon :icon="_leadIcon" class="icon-svg" />
109
114
  </span>
110
115
  <span v-if="label" class="label" :class="labelMode">
111
116
  {{ label }}
112
117
  </span>
118
+ <span v-if="trailIcon" class="icon" :class="iconMode">
119
+ <SIcon :icon="trailIcon" class="icon-svg" />
120
+ </span>
113
121
  </span>
114
122
 
115
123
  <transition name="fade">
@@ -192,11 +200,12 @@ function handleClick(): void {
192
200
  min-height: 28px;
193
201
  font-size: var(--button-font-size, var(--button-mini-font-size));
194
202
 
195
- &.rounded { border-radius: 16px; }
196
- &.has-label { padding: var(--button-padding, 0 12px); }
197
- &.has-label.has-icon { padding: var(--button-padding, 0 10px 0 8px); }
198
- .content { gap: 4px; }
199
- .icon-svg { width: 16px; height: 16px; }
203
+ &.rounded { border-radius: 16px; }
204
+ &.has-label { padding: var(--button-padding, 0 12px); }
205
+ &.has-label.has-lead-icon { padding: var(--button-padding, 0 10px 0 8px); }
206
+ &.has-label.has-trail-icon { padding: var(--button-padding, 0 8px 0 10px); }
207
+ .content { gap: 4px; }
208
+ .icon-svg { width: 16px; height: 16px; }
200
209
  }
201
210
 
202
211
  .SButton.small {
@@ -204,11 +213,12 @@ function handleClick(): void {
204
213
  min-height: 32px;
205
214
  font-size: var(--button-font-size, var(--button-small-font-size));
206
215
 
207
- &.rounded { border-radius: 16px; }
208
- &.has-label { padding: var(--button-padding, 0 12px); }
209
- &.has-label.has-icon { padding: var(--button-padding, 0 10px 0 8px); }
210
- .content { gap: 6px; }
211
- .icon-svg { width: 16px; height: 16px; }
216
+ &.rounded { border-radius: 16px; }
217
+ &.has-label { padding: var(--button-padding, 0 12px); }
218
+ &.has-label.has-lead-icon { padding: var(--button-padding, 0 10px 0 8px); }
219
+ &.has-label.has-trail-icon { padding: var(--button-padding, 0 8px 0 10px); }
220
+ .content { gap: 6px; }
221
+ .icon-svg { width: 16px; height: 16px; }
212
222
  }
213
223
 
214
224
  .SButton.medium {
@@ -216,11 +226,12 @@ function handleClick(): void {
216
226
  min-height: 40px;
217
227
  font-size: var(--button-font-size, var(--button-medium-font-size));
218
228
 
219
- &.rounded { border-radius: 20px; }
220
- &.has-label { padding: var(--button-padding, 0 16px); }
221
- &.has-label.has-icon { padding: var(--button-padding, 0 12px 0 10px); }
222
- .content { gap: 6px; }
223
- .icon-svg { width: 18px; height: 18px; }
229
+ &.rounded { border-radius: 20px; }
230
+ &.has-label { padding: var(--button-padding, 0 16px); }
231
+ &.has-label.has-lead-icon { padding: var(--button-padding, 0 12px 0 10px); }
232
+ &.has-label.has-trail-icon { padding: var(--button-padding, 0 10px 0 12px); }
233
+ .content { gap: 6px; }
234
+ .icon-svg { width: 18px; height: 18px; }
224
235
  }
225
236
 
226
237
  .SButton.large {
@@ -228,11 +239,12 @@ function handleClick(): void {
228
239
  min-height: 48px;
229
240
  font-size: var(--button-font-size, var(--button-large-font-size));
230
241
 
231
- &.rounded { border-radius: 24px; }
232
- &.has-label { padding: var(--button-padding, 0 20px); }
233
- &.has-label.has-icon { padding: var(--button-padding, 0 14px 0 12px); }
234
- .content { gap: 6px; }
235
- .icon-svg { width: 18px; height: 18px; }
242
+ &.rounded { border-radius: 24px; }
243
+ &.has-label { padding: var(--button-padding, 0 20px); }
244
+ &.has-label.has-lead-icon { padding: var(--button-padding, 0 14px 0 12px); }
245
+ &.has-label.has-trail-icon { padding: var(--button-padding, 0 12px 0 14px); }
246
+ .content { gap: 6px; }
247
+ .icon-svg { width: 18px; height: 18px; }
236
248
  }
237
249
 
238
250
  .SButton.jumbo {
@@ -240,11 +252,12 @@ function handleClick(): void {
240
252
  min-height: 64px;
241
253
  font-size: var(--button-font-size, var(--button-jumbo-font-size));
242
254
 
243
- &.rounded { border-radius: 32px; }
244
- &.has-label { padding: var(--button-padding, 0 24px); }
245
- &.has-label.has-icon { padding: var(--button-padding, 0 20px 0 18px); }
246
- .content { gap: 8px; }
247
- .icon-svg { width: 20px; height: 20px; }
255
+ &.rounded { border-radius: 32px; }
256
+ &.has-label { padding: var(--button-padding, 0 24px); }
257
+ &.has-label.has-lead-icon { padding: var(--button-padding, 0 20px 0 18px); }
258
+ &.has-label.has-trail-icon { padding: var(--button-padding, 0 18px 0 20px); }
259
+ .content { gap: 8px; }
260
+ .icon-svg { width: 20px; height: 20px; }
248
261
  }
249
262
 
250
263
  .SButton.disabled {
@@ -10,13 +10,13 @@ const props = defineProps<{
10
10
  mode?: Mode
11
11
  }>()
12
12
 
13
- const { isCollapsed } = provideCardState()
14
-
15
13
  const classes = computed(() => [
16
14
  props.size,
17
15
  props.mode ?? 'neutral',
18
16
  { collapsed: isCollapsed.value }
19
17
  ])
18
+
19
+ const { isCollapsed } = provideCardState()
20
20
  </script>
21
21
 
22
22
  <template>
@@ -1,25 +1,35 @@
1
1
  <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { type CardBlockSize, provideCardBlockSize } from '../composables/Card'
4
+
5
+ export type { CardBlockSize as Size }
6
+
7
+ // @deprecated Use CSS utility classes instead.
2
8
  export type Space = 'compact' | 'wide' | 'xwide'
3
9
 
4
- defineProps<{
10
+ const props = defineProps<{
11
+ size?: CardBlockSize
12
+
13
+ // @deprecated Use CSS utility classes instead.
5
14
  space?: Space
6
15
  }>()
16
+
17
+ provideCardBlockSize(computed(() => props.size ?? null))
7
18
  </script>
8
19
 
9
20
  <template>
10
- <div class="SCardBlock" :class="[space]">
21
+ <div class="SCardBlock" :class="[size, space]">
11
22
  <slot />
12
23
  </div>
13
24
  </template>
14
25
 
15
26
  <style scoped lang="postcss">
16
27
  .SCardBlock {
17
- padding: var(--card-padding, 0);
18
28
  background-color: var(--c-bg-elv-3);
19
29
 
20
- &.compact { padding: 24px; }
21
- &.wide { padding: 32px; }
22
- &.xwide { padding: 48px; }
30
+ &.compact { padding: 12px; }
31
+ &.wide { padding: 16px; }
32
+ &.xwide { padding: 24px; }
23
33
  }
24
34
 
25
35
  .SCard > .SCardBlock:first-child {
@@ -31,4 +41,20 @@ defineProps<{
31
41
  border-bottom-right-radius: 5px;
32
42
  border-bottom-left-radius: 5px;
33
43
  }
44
+
45
+ .SCardBlock.xsmall,
46
+ .SCardBlock.small,
47
+ .SCardBlock.medium,
48
+ .SCardBlock.large,
49
+ .SCardBlock.xlarge {
50
+ display: flex;
51
+ align-items: center;
52
+ width: 100%;
53
+ }
54
+
55
+ .SCardBlock.xsmall { height: 40px; }
56
+ .SCardBlock.small { height: 48px; }
57
+ .SCardBlock.medium { height: 56px; }
58
+ .SCardBlock.large { height: 64px; }
59
+ .SCardBlock.xlarge { height: 80px; }
34
60
  </style>
@@ -0,0 +1,50 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { useCardBlockSize } from '../composables/Card'
4
+ import { type ControlSize, provideControlSize } from '../composables/Control'
5
+
6
+ export type { ControlSize as Size }
7
+
8
+ const props = defineProps<{
9
+ size?: ControlSize
10
+ }>()
11
+
12
+ const cardSize = useCardBlockSize()
13
+
14
+ const sizeDict = {
15
+ xsmall: 'small',
16
+ small: 'small',
17
+ medium: 'small',
18
+ large: 'medium',
19
+ xlarge: 'medium',
20
+ null: null
21
+ } as const
22
+
23
+ const _size = computed(() => {
24
+ return props.size ?? sizeDict[cardSize.value ?? 'null'] ?? 'small'
25
+ })
26
+
27
+ const classes = computed(() => [
28
+ _size.value,
29
+ cardSize.value ? `card-size-${cardSize.value}` : null
30
+ ])
31
+
32
+ provideControlSize(_size)
33
+ </script>
34
+
35
+ <template>
36
+ <div class="SControl" :class="classes">
37
+ <slot />
38
+ </div>
39
+ </template>
40
+
41
+ <style scoped lang="postcss">
42
+ .SControl {
43
+ display: flex;
44
+ align-items: center;
45
+ flex-grow: 1;
46
+ }
47
+
48
+ .SControl.small { gap: 8px; height: 32px; }
49
+ .SControl.medium { gap: 12px; height: 40px; }
50
+ </style>
@@ -0,0 +1,45 @@
1
+ <script setup lang="ts">
2
+ import { useControlSize } from '../composables/Control'
3
+ import SButton, { type Mode, type Tooltip, type Type } from './SButton.vue'
4
+
5
+ defineProps<{
6
+ tag?: string
7
+ type?: Type
8
+ mode?: Mode
9
+ icon?: any
10
+ iconMode?: Mode
11
+ label?: string
12
+ labelMode?: Mode
13
+ href?: string
14
+ loading?: boolean
15
+ disabled?: boolean
16
+ tooltip?: Tooltip
17
+ }>()
18
+
19
+ defineEmits<{
20
+ (e: 'click'): void
21
+ }>()
22
+
23
+ const size = useControlSize()
24
+ </script>
25
+
26
+ <template>
27
+ <div class="SControlButton">
28
+ <SButton
29
+ :tag="tag"
30
+ :size="size"
31
+ :type="type"
32
+ :mode="mode"
33
+ :icon="icon"
34
+ :icon-mode="iconMode"
35
+ :label="label"
36
+ :label-mode="labelMode"
37
+ :href="href"
38
+ :tooltip="tooltip"
39
+ block
40
+ :loading="loading"
41
+ :disabled="disabled"
42
+ @click="$emit('click')"
43
+ />
44
+ </div>
45
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import { provideControlPosition } from '../composables/Control'
3
+
4
+ provideControlPosition('center')
5
+ </script>
6
+
7
+ <template>
8
+ <div class="SControlCenter">
9
+ <slot />
10
+ </div>
11
+ </template>
12
+
13
+ <style scoped lang="postcss">
14
+ .SControlCenter {
15
+ display: flex;
16
+ justify-content: center;
17
+ align-items: center;
18
+ flex-grow: 1;
19
+ flex-shrink: 0;
20
+ }
21
+
22
+ .SControl.small .SControlCenter { gap: 8px; }
23
+ .SControl.medium .SControlCenter { gap: 12px; }
24
+ </style>
@@ -0,0 +1,68 @@
1
+ <script setup lang="ts">
2
+ import IconMagnifyingGlass from '@iconify-icons/ph/magnifying-glass-bold'
3
+ import { computed } from 'vue'
4
+ import { useControlSize } from '../composables/Control'
5
+ import { useTrans } from '../composables/Lang'
6
+ import { type Validatable } from '../composables/V'
7
+ import SInputText, { type Align, type TextColor } from './SInputText.vue'
8
+
9
+ const props = defineProps<{
10
+ placeholder?: string
11
+ unitAfter?: any
12
+ textColor?: TextColor | ((value: string | null) => TextColor)
13
+ align?: Align
14
+ disabled?: boolean
15
+ value?: string | null
16
+ modelValue?: string | null
17
+ displayValue?: string | null
18
+ validation?: Validatable
19
+ }>()
20
+
21
+ defineEmits<{
22
+ (e: 'update:model-value', value: string | null): void
23
+ (e: 'input', value: string | null): void
24
+ (e: 'blur', value: string | null): void
25
+ (e: 'enter', value: string | null): void
26
+ }>()
27
+
28
+ const { t } = useTrans({
29
+ en: { placeholder: 'Search items' },
30
+ ja: { placeholder: '検索する' }
31
+ })
32
+
33
+ const size = useControlSize()
34
+
35
+ const sizeDict = {
36
+ small: 'mini',
37
+ medium: 'small'
38
+ } as const
39
+
40
+ const _value = computed(() => {
41
+ return props.modelValue ?? props.value ?? null
42
+ })
43
+ </script>
44
+
45
+ <template>
46
+ <div class="SControlInputSearch">
47
+ <SInputText
48
+ :size="sizeDict[size]"
49
+ type="search"
50
+ :placeholder="placeholder ?? t.placeholder"
51
+ :unit-before="IconMagnifyingGlass"
52
+ :model-value="_value"
53
+ :validation="validation"
54
+ hide-error
55
+ @update:model-value="$emit('update:model-value', $event)"
56
+ @input="$emit('input', $event)"
57
+ @blur="$emit('blur', $event)"
58
+ @enter="$emit('enter', $event)"
59
+ />
60
+ </div>
61
+ </template>
62
+
63
+ <style scoped lang="postcss">
64
+ .SControlInputSearch {
65
+ flex-grow: 1;
66
+ flex-shrink: 0;
67
+ }
68
+ </style>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import { provideControlPosition } from '../composables/Control'
3
+
4
+ provideControlPosition('left')
5
+ </script>
6
+
7
+ <template>
8
+ <div class="SControlLeft">
9
+ <slot />
10
+ </div>
11
+ </template>
12
+
13
+ <style scoped lang="postcss">
14
+ .SControlLeft {
15
+ display: flex;
16
+ justify-content: flex-start;
17
+ align-items: center;
18
+ flex-grow: 1;
19
+ flex-shrink: 0;
20
+ }
21
+
22
+ .SControl.small .SControlLeft { gap: 8px; }
23
+ .SControl.medium .SControlLeft { gap: 12px; }
24
+ </style>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import { useControlPosition, useControlSize } from '../composables/Control'
3
+ import SPagination, { type Size } from './SPagination.vue'
4
+
5
+ defineProps<{
6
+ size?: Size
7
+ total: number
8
+ page: number
9
+ perPage: number
10
+ }>()
11
+
12
+ const size = useControlSize()
13
+ const position = useControlPosition()
14
+ </script>
15
+
16
+ <template>
17
+ <div class="SControlPagination">
18
+ <SPagination
19
+ :size="size"
20
+ :align="position"
21
+ :total="total"
22
+ :page="page"
23
+ :per-page="perPage"
24
+ />
25
+ </div>
26
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ import { provideControlPosition } from '../composables/Control'
3
+
4
+ provideControlPosition('right')
5
+ </script>
6
+
7
+ <template>
8
+ <div class="SControlRight">
9
+ <slot />
10
+ </div>
11
+ </template>
12
+
13
+ <style scoped lang="postcss">
14
+ .SControlRight {
15
+ display: flex;
16
+ justify-content: flex-end;
17
+ align-items: center;
18
+ flex-grow: 1;
19
+ flex-shrink: 0;
20
+ }
21
+
22
+ .SControl.small .SControlRight { gap: 8px; }
23
+ .SControl.medium .SControlRight { gap: 12px; }
24
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <div class="SControlText">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped lang="postcss">
8
+ .SControlText {
9
+ line-height: 24px;
10
+ font-size: 14px;
11
+ }
12
+ </style>
@@ -6,12 +6,7 @@ import { isString } from '../support/Utils'
6
6
  import SIcon from './SIcon.vue'
7
7
  import SInputBase from './SInputBase.vue'
8
8
 
9
- export type Size = 'mini' | 'small' | 'medium'
10
- export type Align = 'left' | 'center' | 'right'
11
- export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
12
- export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
13
-
14
- const props = defineProps<{
9
+ export interface Props {
15
10
  size?: Size
16
11
  name?: string
17
12
  label?: string
@@ -32,7 +27,14 @@ const props = defineProps<{
32
27
  displayValue?: string | null
33
28
  hideError?: boolean
34
29
  validation?: Validatable
35
- }>()
30
+ }
31
+
32
+ export type Size = 'mini' | 'small' | 'medium'
33
+ export type Align = 'left' | 'center' | 'right'
34
+ export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
35
+ export type TextColor = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
36
+
37
+ const props = defineProps<Props>()
36
38
 
37
39
  const emit = defineEmits<{
38
40
  (e: 'update:model-value', value: string | null): void
@@ -0,0 +1,132 @@
1
+ <script setup lang="ts">
2
+ import IconCaretLeft from '@iconify-icons/ph/caret-left-bold'
3
+ import IconCaretRight from '@iconify-icons/ph/caret-right-bold'
4
+ import { computed } from 'vue'
5
+ import { useTrans } from '../composables/Lang'
6
+ import { format } from '../support/Num'
7
+ import SButton from './SButton.vue'
8
+
9
+ export type Size = 'mini' | 'small' | 'medium'
10
+ export type Align = 'left' | 'center' | 'right'
11
+
12
+ const props = withDefaults(defineProps<{
13
+ size?: Size
14
+ align?: Align
15
+ total: number
16
+ page: number
17
+ perPage: number
18
+ }>(), {
19
+ size: 'medium',
20
+ align: 'center'
21
+ })
22
+
23
+ const emit = defineEmits<{
24
+ (e: 'prev'): void
25
+ (e: 'next'): void
26
+ }>()
27
+
28
+ const { t } = useTrans({
29
+ en: { prev: 'Prev', next: 'Next' },
30
+ ja: { prev: '前へ', next: '次へ' }
31
+ })
32
+
33
+ const from = computed(() => {
34
+ return props.page === 1 ? 1 : (props.page - 1) * props.perPage + 1
35
+ })
36
+
37
+ const to = computed(() => {
38
+ const value = props.page * props.perPage
39
+
40
+ return value > props.total ? props.total : value
41
+ })
42
+
43
+ const hasPrev = computed(() => {
44
+ return props.page > 1
45
+ })
46
+
47
+ const hasNext = computed(() => {
48
+ return to.value < props.total
49
+ })
50
+
51
+ function prev() {
52
+ hasPrev.value && emit('prev')
53
+ }
54
+
55
+ function next() {
56
+ hasNext.value && emit('next')
57
+ }
58
+ </script>
59
+
60
+ <template>
61
+ <div class="SPagination" :class="[size, align]">
62
+ <div class="button prev">
63
+ <SButton
64
+ type="outline"
65
+ mode="mute"
66
+ :size="size"
67
+ :lead-icon="IconCaretLeft"
68
+ :label="t.prev"
69
+ :disabled="!hasPrev"
70
+ @click="prev"
71
+ />
72
+ </div>
73
+ <div class="text">
74
+ {{ format(from) }}–{{ format(to) }} of {{ format(props.total) }}
75
+ </div>
76
+ <div class="button next">
77
+ <SButton
78
+ type="outline"
79
+ mode="mute"
80
+ :size="size"
81
+ :trail-icon="IconCaretRight"
82
+ :label="t.next"
83
+ :disabled="!hasNext"
84
+ @click="next"
85
+ />
86
+ </div>
87
+ </div>
88
+ </template>
89
+
90
+ <style scoped lang="postcss">
91
+ .SPagination {
92
+ display: flex;
93
+ align-items: center;
94
+ }
95
+
96
+ .text {
97
+ padding: 0 8px;
98
+ line-height: 24px;
99
+ font-size: 14px;
100
+ color: var(--c-text-2);
101
+ }
102
+
103
+ .SPagination.mini {
104
+ gap: 8px;
105
+ }
106
+
107
+ .SPagination.small {
108
+ gap: 8px;
109
+ }
110
+
111
+ .SPagination.medium {
112
+ gap: 12px;
113
+ }
114
+
115
+ .SPagination.left {
116
+ .prev { order: 1; }
117
+ .next { order: 2; }
118
+ .text { order: 3; }
119
+ }
120
+
121
+ .SPagination.center {
122
+ .prev { order: 1; }
123
+ .text { order: 2; }
124
+ .next { order: 3; }
125
+ }
126
+
127
+ .SPagination.right {
128
+ .text { order: 1; }
129
+ .prev { order: 2; }
130
+ .next { order: 3; }
131
+ }
132
+ </style>
@@ -491,7 +491,9 @@ function updateSelected(selected: unknown[]) {
491
491
  width: 100%;
492
492
 
493
493
  .STable.borderless & {
494
+ border-top: 0;
494
495
  border-right: 0;
496
+ border-bottom: 0;
495
497
  border-left: 0;
496
498
  border-radius: 0;
497
499
  }
@@ -523,7 +525,8 @@ function updateSelected(selected: unknown[]) {
523
525
  display: none;
524
526
  }
525
527
 
526
- .STable.has-header & {
528
+ .STable.has-header &,
529
+ .STable.borderless & {
527
530
  border-radius: 0;
528
531
  }
529
532
  }
@@ -533,7 +536,8 @@ function updateSelected(selected: unknown[]) {
533
536
  line-height: 0;
534
537
  max-height: var(--table-max-height, 100%);
535
538
 
536
- .STable.has-footer & {
539
+ .STable.has-footer &,
540
+ .STable.borderless & {
537
541
  border-radius: 0;
538
542
  }
539
543
  }
@@ -148,7 +148,7 @@ function stopDialogPositionListener() {
148
148
 
149
149
  <style scoped lang="postcss">
150
150
  .STableColumn {
151
- background-color: var(--c-bg-elv-4);
151
+ background-color: var(--c-bg-elv-3);
152
152
 
153
153
  &.has-header {
154
154
  border-top: 1px solid var(--c-gutter);
@@ -1,3 +1,3 @@
1
1
  <template>
2
- <wbr><span class="u-nowrap"><slot /></span>
2
+ <wbr><span class="s-nowrap"><slot /></span>
3
3
  </template>
@@ -1,4 +1,4 @@
1
- import { type Ref, inject, provide, ref } from 'vue'
1
+ import { type ComputedRef, type Ref, computed, inject, provide, ref, toValue } from 'vue'
2
2
 
3
3
  export interface CardState {
4
4
  isCollapsed: Ref<boolean>
@@ -6,7 +6,10 @@ export interface CardState {
6
6
  toggleCollapse(): void
7
7
  }
8
8
 
9
- export const CardStateKey = 'card-state'
9
+ export type CardBlockSize = 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'
10
+
11
+ export const CardStateKey = 'sefirot-card-state-key'
12
+ export const CardBlockSizeKey = 'sefirot-card-block-size-key'
10
13
 
11
14
  export function provideCardState(): CardState {
12
15
  const isCollapsed = ref(false)
@@ -30,8 +33,12 @@ export function provideCardState(): CardState {
30
33
  return cardState
31
34
  }
32
35
 
36
+ export function provideCardBlockSize(cardBlockSize: ComputedRef<CardBlockSize | null>): void {
37
+ provide(CardBlockSizeKey, cardBlockSize)
38
+ }
39
+
33
40
  export function useCardState(): CardState {
34
- const cardState = inject<CardState | null>(CardStateKey, null)
41
+ const cardState = inject<CardState | null>(CardStateKey, null) || null
35
42
 
36
43
  if (!cardState) {
37
44
  throw new Error(
@@ -43,3 +50,8 @@ export function useCardState(): CardState {
43
50
 
44
51
  return cardState
45
52
  }
53
+
54
+ export function useCardBlockSize(): ComputedRef<CardBlockSize | null> {
55
+ const cardSize = inject<ComputedRef<CardBlockSize | null> | null>(CardBlockSizeKey, null) || null
56
+ return computed(() => toValue(cardSize))
57
+ }
@@ -0,0 +1,43 @@
1
+ import { type ComputedRef, computed, inject, provide, toValue } from 'vue'
2
+
3
+ export type ControlSize = 'small' | 'medium'
4
+ export type ControlPosition = 'left' | 'center' | 'right'
5
+
6
+ export const ControlSizeKey = 'sefirot-control-size-key'
7
+ export const ControlPositionKey = 'sefirot-control-position-key'
8
+
9
+ export function provideControlSize(controlSize: ComputedRef<ControlSize>): void {
10
+ provide(ControlSizeKey, controlSize)
11
+ }
12
+
13
+ export function provideControlPosition(controlPosition: ControlPosition): void {
14
+ provide(ControlPositionKey, controlPosition)
15
+ }
16
+
17
+ export function useControlSize(): ComputedRef<ControlSize> {
18
+ const controlSize = inject<ComputedRef<ControlSize> | null>(ControlSizeKey, null) || null
19
+
20
+ if (!controlSize) {
21
+ throw new Error(
22
+ '[sefirot] Unexpected call to `useControlSize`. This probably means'
23
+ + ' you are using `<SControl>` child component outside of `<SControl>`.'
24
+ + ' Make sure to wrap the component within `<SControl>` component.'
25
+ )
26
+ }
27
+
28
+ return computed(() => toValue(controlSize))
29
+ }
30
+
31
+ export function useControlPosition(): ControlPosition {
32
+ const controlPosition = inject<ControlPosition | null>(ControlPositionKey, null) || null
33
+
34
+ if (!controlPosition) {
35
+ throw new Error(
36
+ '[sefirot] Unexpected call to `useControlPosition`. This probably means'
37
+ + ' you are using `<SControl>` child component outside of `<SControl>`.'
38
+ + ' Make sure to wrap the component within `<SControl>` component.'
39
+ )
40
+ }
41
+
42
+ return controlPosition
43
+ }
@@ -8,27 +8,29 @@ export interface Table<
8
8
  R extends Record<string, any> = any,
9
9
  SR extends Record<string, any> = any
10
10
  > {
11
+ records?: MaybeRef<R[] | null | undefined>
11
12
  orders: MaybeRef<O[]>
12
13
  columns: MaybeRef<TableColumns<O, R, SR>>
13
- menu?: MaybeRef<TableMenu[] | TableMenu[][]>
14
+ summary?: MaybeRef<SR | null | undefined>
15
+ indexField?: keyof R
16
+ loading?: MaybeRef<boolean | undefined>
17
+ rowSize?: MaybeRef<number | undefined>
18
+ borderless?: MaybeRef<boolean>
19
+
20
+ /**
21
+ * @deprecated Use `<SControl>` to add equivalent features.
22
+ */
14
23
  actions?: MaybeRef<TableHeaderAction[]>
15
- records?: MaybeRef<R[] | null | undefined>
24
+ menu?: MaybeRef<TableMenu[] | TableMenu[][]>
16
25
  header?: MaybeRef<boolean | undefined>
17
26
  footer?: MaybeRef<boolean | undefined>
18
- summary?: MaybeRef<SR | null | undefined>
19
27
  total?: MaybeRef<number | null | undefined>
20
28
  page?: MaybeRef<number | null | undefined>
21
29
  perPage?: MaybeRef<number | null | undefined>
22
- /** @deprecated use `actions` instead */
23
30
  reset?: MaybeRef<boolean | undefined>
24
- borderless?: MaybeRef<boolean>
25
- loading?: MaybeRef<boolean | undefined>
26
- rowSize?: MaybeRef<number | undefined>
27
31
  borderSize?: MaybeRef<number | undefined>
28
- indexField?: keyof R
29
32
  onPrev?(): void
30
33
  onNext?(): void
31
- /** @deprecated use `actions` instead */
32
34
  onReset?(): void
33
35
  }
34
36
 
@@ -0,0 +1,30 @@
1
+ import { type App } from 'vue'
2
+ import SControl from '../components/SControl.vue'
3
+ import SControlButton from '../components/SControlButton.vue'
4
+ import SControlCenter from '../components/SControlCenter.vue'
5
+ import SControlInputSearch from '../components/SControlInputSearch.vue'
6
+ import SControlLeft from '../components/SControlLeft.vue'
7
+ import SControlRight from '../components/SControlRight.vue'
8
+ import SControlText from '../components/SControlText.vue'
9
+
10
+ export function mixin(app: App): void {
11
+ app.component('SControl', SControl)
12
+ app.component('SControlButton', SControlButton)
13
+ app.component('SControlCenter', SControlCenter)
14
+ app.component('SControlInputSearch', SControlInputSearch)
15
+ app.component('SControlLeft', SControlLeft)
16
+ app.component('SControlRight', SControlRight)
17
+ app.component('SControlText', SControlText)
18
+ }
19
+
20
+ declare module 'vue' {
21
+ export interface GlobalComponents {
22
+ SControl: typeof SControl
23
+ SControlButton: typeof SControlButton
24
+ SControlCenter: typeof SControlCenter
25
+ SControlInputSearch: typeof SControlInputSearch
26
+ SControlLeft: typeof SControlLeft
27
+ SControlRight: typeof SControlRight
28
+ SControlText: typeof SControlText
29
+ }
30
+ }
@@ -1,3 +1,113 @@
1
- .u-nowrap {
2
- white-space: nowrap;
3
- }
1
+ .bg-elv-1 { background-color: var(--c-bg-elv-1); }
2
+ .bg-elv-2 { background-color: var(--c-bg-elv-2); }
3
+ .bg-elv-3 { background-color: var(--c-bg-elv-3); }
4
+ .bg-elv-4 { background-color: var(--c-bg-elv-4); }
5
+
6
+ .s-flex { display: flex; }
7
+
8
+ .s-font-12 { font-size: 12px; }
9
+ .s-font-14 { font-size: 14px; }
10
+ .s-font-16 { font-size: 16px; }
11
+ .s-font-20 { font-size: 20px; }
12
+ .s-font-24 { font-size: 24px; }
13
+ .s-font-32 { font-size: 32px; }
14
+
15
+ .s-font-w-100 { font-weight: 100; }
16
+ .s-font-w-200 { font-weight: 200; }
17
+ .s-font-w-300 { font-weight: 300; }
18
+ .s-font-w-400 { font-weight: 400; }
19
+ .s-font-w-500 { font-weight: 500; }
20
+ .s-font-w-600 { font-weight: 600; }
21
+ .s-font-w-700 { font-weight: 700; }
22
+ .s-font-w-800 { font-weight: 800; }
23
+ .s-font-w-900 { font-weight: 900; }
24
+
25
+ .s-gap-4 { gap: 4px; }
26
+ .s-gap-8 { gap: 8px; }
27
+ .s-gap-12 { gap: 12px; }
28
+ .s-gap-16 { gap: 16px; }
29
+
30
+ .s-grow { flex-grow: 1; }
31
+ .s-grow-0 { flex-grow: 0; }
32
+
33
+ .s-nowrap { white-space: nowrap; }
34
+
35
+ .s-overflow-hidden { overflow: hidden; }
36
+
37
+ .s-p-8 { padding: 8px; }
38
+ .s-p-12 { padding: 12px; }
39
+ .s-p-16 { padding: 16px; }
40
+ .s-p-24 { padding: 24px; }
41
+ .s-p-32 { padding: 32px; }
42
+ .s-p-48 { padding: 48px; }
43
+ .s-p-56 { padding: 56px; }
44
+ .s-p-64 { padding: 64px; }
45
+
46
+ .s-pb-8 { padding-bottom: 8px; }
47
+ .s-pb-12 { padding-bottom: 12px; }
48
+ .s-pb-16 { padding-bottom: 16px; }
49
+ .s-pb-24 { padding-bottom: 24px; }
50
+ .s-pb-32 { padding-bottom: 32px; }
51
+ .s-pb-48 { padding-bottom: 48px; }
52
+ .s-pb-56 { padding-bottom: 56px; }
53
+ .s-pb-64 { padding-bottom: 64px; }
54
+
55
+ .s-pl-8 { padding-left: 8px; }
56
+ .s-pl-12 { padding-left: 12px; }
57
+ .s-pl-16 { padding-left: 16px; }
58
+ .s-pl-24 { padding-left: 24px; }
59
+ .s-pl-32 { padding-left: 32px; }
60
+ .s-pl-48 { padding-left: 48px; }
61
+ .s-pl-56 { padding-left: 56px; }
62
+ .s-pl-64 { padding-left: 64px; }
63
+
64
+ .s-pr-8 { padding-right: 8px; }
65
+ .s-pr-12 { padding-right: 12px; }
66
+ .s-pr-16 { padding-right: 16px; }
67
+ .s-pr-24 { padding-right: 24px; }
68
+ .s-pr-32 { padding-right: 32px; }
69
+ .s-pr-48 { padding-right: 48px; }
70
+ .s-pr-56 { padding-right: 56px; }
71
+ .s-pr-64 { padding-right: 64px; }
72
+
73
+ .s-pt-8 { padding-top: 8px; }
74
+ .s-pt-12 { padding-top: 12px; }
75
+ .s-pt-16 { padding-top: 16px; }
76
+ .s-pt-24 { padding-top: 24px; }
77
+ .s-pt-32 { padding-top: 32px; }
78
+ .s-pt-48 { padding-top: 48px; }
79
+ .s-pt-56 { padding-top: 56px; }
80
+ .s-pt-64 { padding-top: 64px; }
81
+
82
+ .s-px-8 { padding-right: 8px; padding-left: 8px; }
83
+ .s-px-12 { padding-right: 12px; padding-left: 12px; }
84
+ .s-px-16 { padding-right: 16px; padding-left: 16px; }
85
+ .s-px-24 { padding-right: 24px; padding-left: 24px; }
86
+ .s-px-32 { padding-right: 32px; padding-left: 32px; }
87
+ .s-px-48 { padding-right: 48px; padding-left: 48px; }
88
+ .s-px-56 { padding-right: 56px; padding-left: 56px; }
89
+ .s-px-64 { padding-right: 64px; padding-left: 64px; }
90
+
91
+ .s-py-8 { padding-top: 8px; padding-bottom: 8px; }
92
+ .s-py-12 { padding-top: 12px; padding-bottom: 12px; }
93
+ .s-py-16 { padding-top: 16px; padding-bottom: 16px; }
94
+ .s-py-24 { padding-top: 24px; padding-bottom: 24px; }
95
+ .s-py-32 { padding-top: 32px; padding-bottom: 32px; }
96
+ .s-py-48 { padding-top: 48px; padding-bottom: 48px; }
97
+ .s-py-56 { padding-top: 56px; padding-bottom: 56px; }
98
+ .s-py-64 { padding-top: 64px; padding-bottom: 64px; }
99
+
100
+ .s-shrink { flex-shrink: 1; }
101
+ .s-shrink-0 { flex-shrink: 0; }
102
+
103
+ .s-text-1 { color: var(--c-text-1); }
104
+ .s-text-2 { color: var(--c-text-2); }
105
+ .s-text-3 { color: var(--c-text-3); }
106
+
107
+ .s-w-256 { width: 256px; }
108
+ .s-w-320 { width: 320px; }
109
+ .s-w-512 { width: 512px; }
110
+
111
+ .s-max-w-256 { max-width: 256px; }
112
+ .s-max-w-320 { max-width: 320px; }
113
+ .s-max-w-512 { max-width: 512px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
- "version": "3.15.0",
3
+ "version": "3.16.0",
4
4
  "packageManager": "pnpm@8.12.1",
5
5
  "description": "Vue Components for Global Brain Design System.",
6
6
  "author": "Kia Ishii <ka.ishii@globalbrains.com>",