@globalbrain/sefirot 3.3.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # Sefirot
2
2
 
3
3
  [![GitHub Actions](https://github.com/globalbrain/sefirot/workflows/Test/badge.svg)](https://github.com/globalbrain/sefirot/actions)
4
- [![Codecov](https://codecov.io/gh/globalbrain/sefirot/branch/main/graph/badge.svg)](https://codecov.io/gh/globalbrain/sefirot)
5
4
  [![License](https://img.shields.io/npm/l/@globalbrain/sefirot.svg)](https://github.com/globalbrain/sefirot/blob/main/LICENSE.md)
6
5
 
7
6
  Sefirot is a collection of Vue Components for Global Brain Design System. Components are meant to be clean, sophisticated, and scalable.
@@ -2,7 +2,7 @@
2
2
  import { computed } from 'vue'
3
3
  import { provideCardState } from '../composables/Card'
4
4
 
5
- export type Size = 'small' | 'medium' | 'large'
5
+ export type Size = 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge'
6
6
  export type Mode = 'neutral' | 'info' | 'success' | 'warning' | 'danger'
7
7
 
8
8
  const props = defineProps<{
@@ -83,6 +83,20 @@ const classes = computed(() => [
83
83
  max-width: 768px;
84
84
  }
85
85
  }
86
+
87
+ &.xlarge {
88
+ @media (min-width: 1056px) {
89
+ margin: 48px auto 128px;
90
+ max-width: 960px;
91
+ }
92
+ }
93
+
94
+ &.xxlarge {
95
+ @media (min-width: 1248px) {
96
+ margin: 48px auto 128px;
97
+ max-width: 1152px;
98
+ }
99
+ }
86
100
  }
87
101
 
88
102
  .SModal.fade-enter-from > .SCard,
@@ -0,0 +1,98 @@
1
+ <script setup lang="ts">
2
+ import IconDownloadSimple from '@iconify-icons/ph/download-simple-bold'
3
+ import IconFileText from '@iconify-icons/ph/file-text-bold'
4
+ import { computed } from 'vue'
5
+ import { isArray } from '../support/Utils'
6
+ import SButton from './SButton.vue'
7
+ import SDescEmpty from './SDescEmpty.vue'
8
+ import SIcon from './SIcon.vue'
9
+
10
+ export interface Item {
11
+ name: string
12
+ onDownload(): void
13
+ }
14
+
15
+ const props = defineProps<{
16
+ item?: Item | Item[] | null
17
+ }>()
18
+
19
+ const items = computed(() => {
20
+ return props.item
21
+ ? isArray(props.item) ? props.item : [props.item]
22
+ : null
23
+ })
24
+ </script>
25
+
26
+ <template>
27
+ <div v-if="items && items.length" class="SDescFile">
28
+ <div class="value">
29
+ <div v-for="item, index in items" :key="index" class="item">
30
+ <div class="data">
31
+ <div class="icon"><SIcon class="icon-svg" :icon="IconFileText" /></div>
32
+ <div class="name">{{ item.name }}</div>
33
+ </div>
34
+ <div class="actions">
35
+ <SButton
36
+ size="small"
37
+ type="text"
38
+ mode="info"
39
+ :icon="IconDownloadSimple"
40
+ label="Download"
41
+ @click="item.onDownload"
42
+ />
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ <SDescEmpty v-else />
48
+ </template>
49
+
50
+ <style scoped lang="postcss">
51
+ .value {
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 1px;
55
+ border: 1px solid var(--c-divider);
56
+ border-radius: 6px;
57
+ margin-top: 2px;
58
+ background-color: var(--c-gutter);
59
+ overflow: hidden;
60
+ }
61
+
62
+ .item {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 8px;
66
+ padding: 0 8px 0 12px;
67
+ width: 100%;
68
+ height: 48px;
69
+ background-color: var(--c-bg-elv-4);
70
+ }
71
+
72
+ .data {
73
+ display: flex;
74
+ gap: 8px;
75
+ flex-grow: 1;
76
+ align-items: center;
77
+ overflow: hidden;
78
+ }
79
+
80
+ .icon-svg {
81
+ width: 18px;
82
+ height: 18px;
83
+ color: var(--c-text-2);
84
+ }
85
+
86
+ .name {
87
+ line-height: 24px;
88
+ font-size: 14px;
89
+ color: var(--c-text-1);
90
+ white-space: nowrap;
91
+ overflow: hidden;
92
+ text-overflow: ellipsis;
93
+ }
94
+
95
+ .actions {
96
+ flex-shrink: 0;
97
+ }
98
+ </style>
@@ -25,13 +25,14 @@ const labelWidth = computed(() => {
25
25
  <style scoped lang="postcss">
26
26
  .SDescItem {
27
27
  display: grid;
28
+ grid-template-columns: minmax(0, 1fr);
28
29
  }
29
30
 
30
31
  .SDesc.row > .SDescItem {
31
- grid-template-columns: var(--desc-label-width, v-bind(labelWidth)) 1fr;
32
+ grid-template-columns: var(--desc-label-width, v-bind(labelWidth)) minmax(0, 1fr);
32
33
  }
33
34
 
34
- .SDesc.divider > .SDescItem {
35
+ .SDesc.divider > .SDescItem:not(:has(> .SDescFile)) {
35
36
  border-bottom: 1px dashed var(--c-divider);
36
37
  padding-bottom: 7px;
37
38
  }
@@ -60,11 +60,13 @@ function getErrorMsg(validation: Validatable) {
60
60
  <span class="label-text">{{ label }}</span>
61
61
 
62
62
  <STooltip v-if="hasInfo" :text="info" trigger="focus" @click.prevent>
63
- <SIcon class="label-info" :icon="IconQuestion" />
63
+ <div class="label-info">
64
+ <SIcon class="label-info-icon" :icon="IconQuestion" />
65
+ </div>
64
66
  <template v-if="$slots.info" #text><slot name="info" /></template>
65
67
  </STooltip>
66
68
 
67
- <span class="label-note">{{ note }}</span>
69
+ <span class="label-note" :class="{ 'has-info': hasInfo }">{{ note }}</span>
68
70
 
69
71
  <span v-if="checkIcon || checkText" class="check" :class="checkColor || 'neutral'">
70
72
  <SIcon v-if="checkIcon" class="check-icon" :icon="checkIcon" />
@@ -84,18 +86,21 @@ function getErrorMsg(validation: Validatable) {
84
86
 
85
87
  <style scoped lang="postcss">
86
88
  .SInputBase.mini {
87
- .label { padding-bottom: 6px; height: 22px; }
88
- .label-text { font-size: var(--input-label-font-size, var(--input-mini-label-font-size)); }
89
- .label-info { width: 14px; height: 14px; }
89
+ .label { padding-bottom: 4px; min-height: 24px; }
90
+ .label-text { font-size: var(--input-label-font-size, var(--input-mini-label-font-size)); }
91
+ .label-info { margin-top: 0; margin-bottom: 0; width: 20px; height: 20px; }
92
+ .label-info-icon { width: 14px; height: 14px; }
93
+ .label-note { padding-top: 0; line-height: 20px; }
94
+ .check { padding-top: 0; line-height: 20px; }
90
95
  }
91
96
 
92
97
  .SInputBase.small {
93
- .label { padding-bottom: 8px; height: 24px; }
98
+ .label { padding-bottom: 6px; min-height: 26px; }
94
99
  .label-text { font-size: var(--input-label-font-size, var(--input-small-label-font-size)); }
95
100
  }
96
101
 
97
102
  .SInputBase.medium {
98
- .label { padding-bottom: 8px; height: 24px; }
103
+ .label { padding-bottom: 6px; min-height: 26px; }
99
104
  .label-text { font-size: var(--input-label-font-size, var(--input-medium-label-font-size)); }
100
105
  }
101
106
 
@@ -107,9 +112,9 @@ function getErrorMsg(validation: Validatable) {
107
112
 
108
113
  .label {
109
114
  display: flex;
110
- align-items: baseline;
115
+ align-items: flex-start;
111
116
  width: 100%;
112
- line-height: 16px;
117
+ line-height: 20px;
113
118
  cursor: pointer;
114
119
  transition: color 0.25s;
115
120
  }
@@ -122,8 +127,18 @@ function getErrorMsg(validation: Validatable) {
122
127
 
123
128
  :deep(.STooltip) {
124
129
  .label-info {
125
- display: inline-block;
126
- margin-left: 4px;
130
+ display: flex;
131
+ justify-content: center;
132
+ align-items: center;
133
+ flex-shrink: 0;
134
+ margin-top: -2px;
135
+ margin-left: 2px;
136
+ margin-bottom: -2px;
137
+ width: 24px;
138
+ height: 24px;
139
+ }
140
+
141
+ .label-info-icon {
127
142
  width: 16px;
128
143
  height: 16px;
129
144
  color: var(--c-text-2);
@@ -131,7 +146,7 @@ function getErrorMsg(validation: Validatable) {
131
146
  }
132
147
 
133
148
  &:hover, &:focus, &:focus-within {
134
- .label-info {
149
+ .label-info-icon {
135
150
  color: var(--c-text-info-1);
136
151
  }
137
152
  }
@@ -143,10 +158,17 @@ function getErrorMsg(validation: Validatable) {
143
158
 
144
159
  .label-note {
145
160
  display: inline-block;
161
+ flex-shrink: 0;
146
162
  margin-left: 8px;
163
+ padding-top: 1px;
164
+ line-height: 19px;
147
165
  font-size: 12px;
148
166
  font-weight: 400;
149
167
  color: var(--c-text-2);
168
+
169
+ &.has-info {
170
+ margin-left: 4px;
171
+ }
150
172
  }
151
173
 
152
174
  .help {
@@ -168,7 +190,7 @@ function getErrorMsg(validation: Validatable) {
168
190
  .help-text {
169
191
  max-width: 65ch;
170
192
  margin: 0;
171
- padding: 4px 0 0;
193
+ padding: 6px 0 0;
172
194
  line-height: 20px;
173
195
  font-size: 12px;
174
196
  font-weight: 400;
@@ -183,10 +205,13 @@ function getErrorMsg(validation: Validatable) {
183
205
 
184
206
  .check {
185
207
  display: inline-flex;
208
+ flex-shrink: 0;
186
209
  align-items: center;
187
210
  gap: 4px;
188
211
  margin-left: auto;
189
- line-height: 16px;
212
+ padding-top: 1px;
213
+ padding-left: 8px;
214
+ line-height: 19px;
190
215
  font-size: 12px;
191
216
 
192
217
  &.neutral { color: var(--c-text-1); }
@@ -162,6 +162,14 @@ function emitBlur() {
162
162
  color: var(--input-placeholder-color);
163
163
  }
164
164
 
165
+ &:hover {
166
+ border-color: var(--input-hover-border-color);
167
+ }
168
+
169
+ &:focus {
170
+ border-color: var(--input-focus-border-color);
171
+ }
172
+
165
173
  &.disabled {
166
174
  border-color: var(--input-disabled-border-color);
167
175
  background-color: var(--input-disabled-bg-color);
@@ -195,7 +195,7 @@ function handleArray(value: OptionValue) {
195
195
  .box-content {
196
196
  padding: 3px 30px 3px 12px;
197
197
  line-height: 24px;
198
- font-size: 14px;
198
+ font-size: var(--input-font-size, var(--input-mini-font-size));
199
199
  }
200
200
 
201
201
  .box-icon {
@@ -212,7 +212,7 @@ function handleArray(value: OptionValue) {
212
212
  .box-content {
213
213
  padding: 5px 30px 5px 8px;
214
214
  line-height: 24px;
215
- font-size: 16px;
215
+ font-size: var(--input-font-size, var(--input-small-font-size));
216
216
  }
217
217
 
218
218
  .box-icon {
@@ -229,7 +229,7 @@ function handleArray(value: OptionValue) {
229
229
  .box-content {
230
230
  padding: 11px 44px 11px 16px;
231
231
  line-height: 24px;
232
- font-size: 16px;
232
+ font-size: var(--input-font-size, var(--input-medium-font-size));
233
233
  }
234
234
 
235
235
  .box-icon {
@@ -255,7 +255,7 @@ function handleArray(value: OptionValue) {
255
255
 
256
256
  .SInputDropdown.has-error {
257
257
  .box {
258
- border-color: var(--c-danger);
258
+ border-color: var(--input-error-border-color);
259
259
  }
260
260
  }
261
261
 
@@ -265,37 +265,22 @@ function handleArray(value: OptionValue) {
265
265
 
266
266
  .box {
267
267
  position: relative;
268
- border: 1px solid var(--c-divider);
268
+ border: 1px solid var(--input-border-color);
269
269
  border-radius: 6px;
270
270
  width: 100%;
271
271
  color: var(--input-text);
272
- background-color: var(--c-bg);
272
+ background-color: var(--input-bg-color);;
273
273
  cursor: pointer;
274
- transition: border-color .25s, background-color .25s;
274
+ transition: border-color 0.25s, background-color 0.25s;
275
275
 
276
276
  &:hover {
277
- border-color: var(--c-black);
278
- }
279
-
280
- &:focus,
281
- &:hover.focus {
282
- border-color: var(--c-info);
283
- }
284
-
285
- .dark &:hover {
286
- border-color: var(--c-gray);
287
- }
288
-
289
- .dark &:focus,
290
- .dark &:hover:focus {
291
- border-color: var(--c-info);
277
+ border-color: var(--input-hover-border-color);
292
278
  }
293
279
  }
294
280
 
295
281
  .box-placeholder {
296
282
  padding: 2px 4px;
297
- font-weight: 500;
298
- color: var(--c-text-3);
283
+ color: var(--input-placeholder-color);
299
284
  overflow: hidden;
300
285
  white-space: nowrap;
301
286
  }
@@ -36,7 +36,7 @@ defineEmits<{
36
36
  <style lang="postcss" scoped>
37
37
  .SInputDropdownItemAvatar {
38
38
  display: flex;
39
- border: 1px solid var(--c-divider-light);
39
+ border: 1px solid var(--c-divider);
40
40
  border-radius: 14px;
41
41
  padding: 0 12px 0 0;
42
42
  background-color: var(--c-bg-mute);
@@ -29,7 +29,7 @@ defineEmits<{
29
29
  <style lang="postcss" scoped>
30
30
  .SInputDropdownItemText {
31
31
  display: flex;
32
- border: 1px solid var(--c-divider-light);
32
+ border: 1px solid var(--c-divider);
33
33
  border-radius: 14px;
34
34
  padding: 0 12px;
35
35
  background-color: var(--c-bg-mute);
@@ -130,7 +130,7 @@ function onChange(e: Event) {
130
130
  .button {
131
131
  padding: 0 8px;
132
132
  line-height: 26px;
133
- font-size: 13px;
133
+ font-size: 12px;
134
134
  font-weight: 500;
135
135
  }
136
136
 
@@ -150,7 +150,7 @@ function onChange(e: Event) {
150
150
  .button {
151
151
  padding: 0 12px;
152
152
  line-height: 30px;
153
- font-size: 14px;
153
+ font-size: 13px;
154
154
  font-weight: 500;
155
155
  }
156
156
 
@@ -184,6 +184,11 @@ function onChange(e: Event) {
184
184
  &:hover {
185
185
  border-color: var(--input-hover-border-color);
186
186
  }
187
+
188
+ &:hover .button {
189
+ border-color: var(--c-border-mute-2);
190
+ background-color: var(--c-bg-mute-2);
191
+ }
187
192
  }
188
193
 
189
194
  .action {
@@ -191,11 +196,11 @@ function onChange(e: Event) {
191
196
  }
192
197
 
193
198
  .button {
194
- border: 1px solid var(--c-divider);
195
- border-radius: 4px;
199
+ border: 1px solid var(--c-border-mute-1);
200
+ border-radius: 3px;
196
201
  color: var(--c-text-1);
197
- background-color: var(--c-mute);
198
- transition: background-color 0.25s;
202
+ background-color: var(--c-bg-mute-1);
203
+ transition: border-color 0.25s, background-color 0.25s;
199
204
  }
200
205
 
201
206
  .text {
@@ -307,7 +307,8 @@ function createRequiredTouched(): boolean[] {
307
307
  }
308
308
 
309
309
  .input {
310
- font-family: var(--input-value-font-family, var(--font-family-number));
310
+ font-family: var(--input-value-font-family, var(--font-family-base));
311
+ font-feature-settings: "tnum";
311
312
  line-height: 24px;
312
313
  background-color: transparent;
313
314
 
@@ -6,7 +6,8 @@ import SInputBase from './SInputBase.vue'
6
6
  import SInputSegmentsOption, { type Mode } from './SInputSegmentsOption.vue'
7
7
 
8
8
  export type Size = 'mini' | 'small' | 'medium'
9
- export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
9
+ export type Color = 'default' | 'mute' | 'neutral' | 'info' | 'success' | 'warning' | 'danger'
10
+ export type CheckColor = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
10
11
 
11
12
  export interface Option<T extends string | number | boolean> {
12
13
  label: string
@@ -24,7 +25,7 @@ const props = defineProps<{
24
25
  help?: string
25
26
  checkIcon?: IconifyIcon
26
27
  checkText?: string
27
- checkColor?: Color
28
+ checkColor?: CheckColor
28
29
  options: Option<T>[]
29
30
  block?: boolean
30
31
  disabled?: boolean
@@ -78,7 +79,7 @@ function onSelect(value: T) {
78
79
  :size="size ?? 'small'"
79
80
  :label="option.label"
80
81
  :value="option.value"
81
- :mode="option.mode ?? 'neutral'"
82
+ :mode="option.mode ?? 'default'"
82
83
  :active="_value === option.value"
83
84
  :disabled="disabled ? true : option.disabled ?? false"
84
85
  @click="onSelect(option.value)"
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts" generic="T extends string | number | boolean">
2
2
  export type Size = 'mini' | 'small' | 'medium'
3
- export type Mode = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
3
+ export type Mode = 'default' | 'mute' | 'neutral' | 'info' | 'success' | 'warning' | 'danger'
4
4
 
5
5
  const props = defineProps<{
6
6
  size: Size
@@ -67,7 +67,7 @@ function onClick() {
67
67
  width: 1px;
68
68
  height: 16px;
69
69
  border-radius: 4px;
70
- background-color: var(--c-divider-2);
70
+ background-color: var(--c-divider);
71
71
  content: "";
72
72
  transition: opacity 0.25s;
73
73
  }
@@ -108,18 +108,24 @@ function onClick() {
108
108
  }
109
109
  }
110
110
 
111
- .SInputSegmentsOption.neutral.active {
112
- border-color: var(--button-fill-mute-border-color);
113
- color: var(--button-fill-mute-text-color);
114
- background-color: var(--button-fill-mute-bg-color);
111
+ .SInputSegmentsOption.default.active {
112
+ border-color: var(--button-fill-default-border-color);
113
+ color: var(--button-fill-default-text-color);
114
+ background-color: var(--button-fill-default-bg-color);
115
115
  }
116
116
 
117
117
  .SInputSegmentsOption.mute.active {
118
118
  border-color: var(--button-fill-mute-border-color);
119
- color: var(--c-text-2);
119
+ color: var(--button-fill-mute-text-color);
120
120
  background-color: var(--button-fill-mute-bg-color);
121
121
  }
122
122
 
123
+ .SInputSegmentsOption.neutral.active {
124
+ border-color: var(--button-fill-neutral-border-color);
125
+ color: var(--button-fill-neutral-text-color);
126
+ background-color: var(--button-fill-neutral-bg-color);
127
+ }
128
+
123
129
  .SInputSegmentsOption.info.active {
124
130
  border-color: var(--button-fill-info-border-color);
125
131
  color: var(--button-fill-info-text-color);
@@ -304,7 +304,7 @@ function createRequiredTouched(): boolean[] {
304
304
 
305
305
  .input {
306
306
  line-height: 24px;
307
- font-family: var(--input-value-font-family, var(--font-family-number));
307
+ font-family: var(--input-value-font-family, var(--font-family-base));
308
308
  font-feature-settings: "tnum";
309
309
  background-color: transparent;
310
310
 
@@ -2,7 +2,8 @@
2
2
  import SM, { type Props } from './SM.vue'
3
3
 
4
4
  withDefaults(defineProps<Props>(), {
5
- opacity: 0
5
+ opacity: 0,
6
+ once: true
6
7
  })
7
8
  </script>
8
9
 
@@ -31,7 +31,7 @@ defineEmits<{
31
31
  <style scoped lang="postcss">
32
32
  .SSheet {
33
33
  position: relative;
34
- border: 1px solid var(--c-divider-light);
34
+ border: 1px solid var(--c-divider);
35
35
  border-radius: 16px;
36
36
  background-color: var(--c-bg);
37
37
  transition: opacity 0.25s, transform 0.25s;
@@ -6,7 +6,7 @@
6
6
 
7
7
  <style scoped lang="postcss">
8
8
  .SSheetFooter {
9
- border-top: 1px solid var(--c-divider-light);
9
+ border-top: 1px solid var(--c-divider);
10
10
  padding: 0 16px;
11
11
 
12
12
  @media (min-width: 512px) {
@@ -44,7 +44,7 @@ function close() {
44
44
  <style scoped lang="postcss">
45
45
  .SSnackbar {
46
46
  position: relative;
47
- border: 1px solid var(--c-divider-light);
47
+ border: 1px solid var(--c-divider);
48
48
  border-radius: 6px;
49
49
  width: 100%;
50
50
  background-color: var(--c-bg-elv-up);
@@ -92,7 +92,7 @@ defineProps({
92
92
  height: 2px;
93
93
  }
94
94
 
95
- .bar.mute { background-color: var(--c-divider-light); }
95
+ .bar.mute { background-color: var(--c-divider); }
96
96
  .bar.active { background-color: var(--c-success); }
97
97
  .bar.failed { background-color: var(--c-danger); }
98
98
 
@@ -12,6 +12,7 @@ import {
12
12
  watch
13
13
  } from 'vue'
14
14
  import { type Table } from '../composables/Table'
15
+ import { getTextWidth } from '../support/Text'
15
16
  import SInputCheckbox from './SInputCheckbox.vue'
16
17
  import SSpinner from './SSpinner.vue'
17
18
  import STableCell from './STableCell.vue'
@@ -204,6 +205,52 @@ useResizeObserver(block, ([entry]) => {
204
205
 
205
206
  const resizeObserver = useResizeObserver(head, handleResize)
206
207
 
208
+ const font = typeof document !== 'undefined'
209
+ ? `500 12px ${getComputedStyle(document.body).fontFamily}`
210
+ : '500 12px Inter'
211
+
212
+ const actionsColumnWidth = computed(() => {
213
+ const { cell } = unref(props.options.columns).actions ?? {}
214
+
215
+ if (
216
+ typeof document === 'undefined'
217
+ || !cell
218
+ || typeof cell === 'function'
219
+ || cell.type !== 'actions'
220
+ ) {
221
+ return undefined
222
+ }
223
+
224
+ const { actions } = cell
225
+
226
+ const widths = actions.map(({ icon, label }) => {
227
+ // has only icon
228
+ if (icon && !label) {
229
+ return 1 /* border */ + 5 /* padding */ + 16 /* icon */ + 5 /* padding */ + 1 /* border */
230
+ }
231
+
232
+ // has only label
233
+ if (label && !icon) {
234
+ return 1 /* border */ + 12 /* padding */ + getTextWidth(label, font) + 12 /* padding */ + 1 /* border */
235
+ }
236
+
237
+ // has both icon and label
238
+ if (icon && label) {
239
+ return 1 /* border */ + 8 /* padding */ + 16 /* icon */ + 4 /* padding */ + getTextWidth(label, font) + 10 /* padding */ + 1 /* border */
240
+ }
241
+
242
+ return 0
243
+ })
244
+
245
+ return 8 /* padding */ + widths.reduce((a, b) => a + b, 0) + 8 /* padding */
246
+ })
247
+
248
+ watch(actionsColumnWidth, (newValue) => {
249
+ if (newValue) {
250
+ updateColWidth('actions', `${newValue}px`)
251
+ }
252
+ }, { immediate: true, flush: 'post' })
253
+
207
254
  function stopObserving() {
208
255
  const orders = ordersToShow.value
209
256
  const lastOrder
@@ -496,7 +543,7 @@ function updateSelected(selected: unknown[]) {
496
543
 
497
544
  :deep(.row) {
498
545
  display: flex;
499
- border-bottom: 1px solid var(--c-divider-2);
546
+ border-bottom: 1px solid var(--c-gutter);
500
547
  }
501
548
 
502
549
  :deep(.row.last),
@@ -31,8 +31,8 @@ defineProps<{
31
31
  min-height: 40px;
32
32
  display: flex;
33
33
  align-items: center;
34
- justify-content: center;
35
34
  flex-wrap: nowrap;
36
35
  flex-direction: row;
36
+ padding: 0 8px;
37
37
  }
38
38
  </style>
@@ -151,7 +151,7 @@ function stopDialogPositionListener() {
151
151
  background-color: var(--c-bg-elv-4);
152
152
 
153
153
  &.has-header {
154
- border-top: 1px solid var(--c-divider-2);
154
+ border-top: 1px solid var(--c-gutter);
155
155
  }
156
156
 
157
157
  .STableItem:first-child & {
@@ -56,7 +56,7 @@ const hasNext = computed(() => {
56
56
 
57
57
  <style scoped lang="postcss">
58
58
  .STableFooter {
59
- border-top: 1px solid var(--c-divider-2);
59
+ border-top: 1px solid var(--c-gutter);
60
60
  border-radius: 0 0 calc(var(--table-border-radius) - 1px) calc(var(--table-border-radius) - 1px);
61
61
  padding-right: var(--table-padding-right);
62
62
  padding-left: var(--table-padding-left);
@@ -47,6 +47,6 @@ const normalizedMenu = computed(() => {
47
47
  margin: 0 8px;
48
48
  width: 1px;
49
49
  height: 16px;
50
- background-color: var(--c-divider-2);
50
+ background-color: var(--c-gutter);
51
51
  }
52
52
  </style>
@@ -26,10 +26,13 @@ const classes = computed(() => [
26
26
  .STableItem {
27
27
  position: var(--table-col-position, relative);
28
28
  left: var(--table-col-left, 0);
29
+ right: var(--table-col-right, auto);
29
30
  z-index: var(--table-col-z-index, auto);
30
31
  flex-shrink: 0;
31
32
  flex-grow: 1;
32
- border-right: 1px solid var(--c-divider-light);
33
+ border-left: var(--table-col-border-left, 0) solid var(--c-gutter);
34
+ border-right: 1px solid var(--c-gutter);
35
+ margin-left: calc(var(--table-col-border-left, 0) * -1);
33
36
  min-width: var(--table-col-width);
34
37
  max-width: var(--table-col-width);
35
38
 
@@ -2,6 +2,7 @@ import { type App } from 'vue'
2
2
  import SDesc from '../components/SDesc.vue'
3
3
  import SDescDay from '../components/SDescDay.vue'
4
4
  import SDescEmpty from '../components/SDescEmpty.vue'
5
+ import SDescFile from '../components/SDescFile.vue'
5
6
  import SDescItem from '../components/SDescItem.vue'
6
7
  import SDescLabel from '../components/SDescLabel.vue'
7
8
  import SDescLink from '../components/SDescLink.vue'
@@ -14,6 +15,7 @@ export function mixin(app: App): void {
14
15
  app.component('SDesc', SDesc)
15
16
  app.component('SDescDay', SDescDay)
16
17
  app.component('SDescEmpty', SDescEmpty)
18
+ app.component('SDescFile', SDescFile)
17
19
  app.component('SDescItem', SDescItem)
18
20
  app.component('SDescLabel', SDescLabel)
19
21
  app.component('SDescLink', SDescLink)
@@ -28,6 +30,7 @@ declare module 'vue' {
28
30
  SDesc: typeof SDesc
29
31
  SDescDay: typeof SDescDay
30
32
  SDescEmpty: typeof SDescEmpty
33
+ SDescFile: typeof SDescFile
31
34
  SDescItem: typeof SDescItem
32
35
  SDescLabel: typeof SDescLabel
33
36
  SDescLink: typeof SDescLink
@@ -153,6 +153,7 @@
153
153
  /**
154
154
  * Color: Divider and Gutter
155
155
  * -------------------------------------------------------------------------- */
156
+
156
157
  :root {
157
158
  --c-divider: #e0e0e1;
158
159
  --c-gutter: #e2e2e3;
@@ -166,6 +167,7 @@
166
167
  /**
167
168
  * Color: Neutral
168
169
  * -------------------------------------------------------------------------- */
170
+
169
171
  :root {
170
172
  --c-neutral-1: var(--c-neutral-light-1);
171
173
  --c-neutral-2: var(--c-neutral-light-2);
@@ -441,7 +443,7 @@
441
443
  --button-fill-mute-active-border-color: var(--c-border-mute-3);
442
444
  --button-fill-mute-active-text-color: var(--c-text-2);
443
445
  --button-fill-mute-active-bg-color: var(--c-bg-mute-3);
444
- --button-fill-mute-disabled-border-color: var(--c-divider-2);
446
+ --button-fill-mute-disabled-border-color: var(--c-border-mute-1);
445
447
  --button-fill-mute-disabled-text-color: var(--c-text-3);
446
448
  --button-fill-mute-disabled-content-color: var(--c-text-3);
447
449
  --button-fill-mute-disabled-bg-color: var(--c-bg-mute-1);
@@ -508,11 +510,11 @@
508
510
  --button-fill-info-disabled-border-color: var(--c-border-info-1);
509
511
  --button-fill-info-disabled-text-color: var(--c-white-a3);
510
512
  --button-fill-info-disabled-content-color: var(--c-white-a3);
511
- --button-fill-info-disabled-bg-color: var(--c-info-bg-dark);
513
+ --button-fill-info-disabled-bg-color: var(--c-blue-8);
512
514
 
513
515
  --button-fill-success-border-color: var(--c-border-success-1);
514
516
  --button-fill-success-text-color: var(--c-white-1);
515
- --button-fill-success-content-color: var(--c-success-text);
517
+ --button-fill-success-content-color: var(--c-white-1);
516
518
  --button-fill-success-bg-color: var(--c-bg-success-1);
517
519
  --button-fill-success-loader-color: var(--c-white);
518
520
  --button-fill-success-hover-border-color: var(--c-border-success-2);
@@ -524,7 +526,7 @@
524
526
  --button-fill-success-disabled-border-color: var(--c-border-success-1);
525
527
  --button-fill-success-disabled-text-color: var(--c-white-a3);
526
528
  --button-fill-success-disabled-content-color: var(--c-white-a3);
527
- --button-fill-success-disabled-bg-color: var(--c-success-bg-dark);
529
+ --button-fill-success-disabled-bg-color: var(--c-green-8);
528
530
 
529
531
  --button-fill-warning-border-color: var(--c-border-mute-1);
530
532
  --button-fill-warning-text-color: var(--c-text-warning-1);
@@ -826,7 +828,7 @@
826
828
  * -------------------------------------------------------------------------- */
827
829
 
828
830
  :root {
829
- --table-border: 1px solid var(--c-divider-2);
831
+ --table-border: 1px solid var(--c-divider);
830
832
  --table-border-top: var(--table-border);
831
833
  --table-border-right: var(--table-border);
832
834
  --table-border-bottom: var(--table-border);
@@ -0,0 +1,25 @@
1
+ // Adapted from https://stackoverflow.com/a/21015393/11613622
2
+
3
+ let _canvas: HTMLCanvasElement
4
+
5
+ export function getTextWidth(text: string, font: string): number
6
+ export function getTextWidth(text: string, el: HTMLElement): number
7
+
8
+ export function getTextWidth(text: string, fontOrEl: string | HTMLElement): number {
9
+ const canvas = _canvas || (_canvas = document.createElement('canvas'))
10
+ const context = canvas.getContext('2d')!
11
+ context.font = typeof fontOrEl === 'string' ? fontOrEl : getCanvasFont(fontOrEl)
12
+ const metrics = context.measureText(text)
13
+
14
+ return metrics.width
15
+ }
16
+
17
+ function getCanvasFont(el: HTMLElement) {
18
+ const {
19
+ fontWeight = 'normal',
20
+ fontSize = '16px',
21
+ fontFamily = 'Times New Roman'
22
+ } = getComputedStyle(el)
23
+
24
+ return `${fontWeight} ${fontSize} ${fontFamily}`
25
+ }
@@ -1,3 +1,7 @@
1
- declare module 'v-calendar' {
2
- export const DatePicker: any
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import { DefineComponent } from 'vue'
5
+ const component: DefineComponent<{}, {}, any>
6
+ export default component
3
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
- "version": "3.3.0",
4
- "packageManager": "pnpm@8.10.3",
3
+ "version": "3.5.0",
4
+ "packageManager": "pnpm@8.10.4",
5
5
  "description": "Vue Components for Global Brain Design System.",
6
6
  "author": "Kia Ishii <ka.ishii@globalbrains.com>",
7
7
  "license": "MIT",
@@ -20,6 +20,23 @@
20
20
  "files": [
21
21
  "lib"
22
22
  ],
23
+ "scripts": {
24
+ "docs": "vitepress dev docs --port 4000",
25
+ "docs:build": "vitepress build docs",
26
+ "docs:preview": "vitepress serve docs --port 3000",
27
+ "story": "histoire dev --port 3000",
28
+ "story:build": "histoire build",
29
+ "story:preview": "histoire preview --port 3000",
30
+ "type": "vue-tsc --noEmit",
31
+ "lint": "eslint --fix .",
32
+ "lint:fail": "eslint .",
33
+ "vitest": "vitest",
34
+ "vitest:run": "vitest run",
35
+ "coverage": "vitest run --coverage",
36
+ "test": "pnpm run type && pnpm run lint && pnpm run coverage",
37
+ "test:fail": "pnpm run type && pnpm run lint:fail && pnpm run coverage",
38
+ "release": "release-it"
39
+ },
23
40
  "peerDependencies": {
24
41
  "@iconify-icons/ph": "^1.2.5",
25
42
  "@iconify/vue": "^4.1.1",
@@ -29,7 +46,7 @@
29
46
  "@types/markdown-it": "^13.0.6",
30
47
  "@vuelidate/core": "^2.0.3",
31
48
  "@vuelidate/validators": "^2.0.4",
32
- "@vueuse/core": "^10.6.0",
49
+ "@vueuse/core": "^10.6.1",
33
50
  "body-scroll-lock": "4.0.0-beta.0",
34
51
  "fuse.js": "^7.0.0",
35
52
  "lodash-es": "^4.17.21",
@@ -47,9 +64,10 @@
47
64
  },
48
65
  "devDependencies": {
49
66
  "@globalbrain/eslint-config": "^1.5.2",
50
- "@histoire/plugin-vue": "^0.17.4",
67
+ "@histoire/plugin-vue": "^0.17.5",
51
68
  "@iconify-icons/ph": "^1.2.5",
52
69
  "@iconify/vue": "^4.1.1",
70
+ "@release-it/conventional-changelog": "^8.0.1",
53
71
  "@tanstack/vue-virtual": "3.0.0-beta.62",
54
72
  "@types/body-scroll-lock": "^3.1.2",
55
73
  "@types/lodash-es": "^4.17.11",
@@ -60,23 +78,19 @@
60
78
  "@vue/test-utils": "^2.4.1",
61
79
  "@vuelidate/core": "^2.0.3",
62
80
  "@vuelidate/validators": "^2.0.4",
63
- "@vueuse/core": "^10.6.0",
81
+ "@vueuse/core": "^10.6.1",
64
82
  "body-scroll-lock": "4.0.0-beta.0",
65
- "chalk": "^4.1.2",
66
- "conventional-changelog-cli": "^4.1.0",
67
- "enquirer": "^2.4.1",
68
83
  "eslint": "^8.53.0",
69
- "execa": "^5.1.1",
70
84
  "fuse.js": "^7.0.0",
71
85
  "happy-dom": "^12.10.3",
72
- "histoire": "^0.17.4",
86
+ "histoire": "^0.17.5",
73
87
  "lodash-es": "^4.17.21",
74
88
  "markdown-it": "^13.0.2",
75
89
  "normalize.css": "^8.0.1",
76
90
  "pinia": "^2.1.7",
77
91
  "postcss": "^8.4.31",
78
92
  "postcss-nested": "^6.0.1",
79
- "semver": "^7.5.4",
93
+ "release-it": "^17.0.0",
80
94
  "typescript": "~5.2.2",
81
95
  "v-calendar": "^3.1.2",
82
96
  "vite": "^4.5.0",
@@ -85,22 +99,5 @@
85
99
  "vue": "^3.3.8",
86
100
  "vue-router": "^4.2.5",
87
101
  "vue-tsc": "^1.8.22"
88
- },
89
- "scripts": {
90
- "docs": "vitepress dev docs --port 4000",
91
- "docs:build": "vitepress build docs",
92
- "docs:preview": "vitepress serve docs --port 3000",
93
- "story": "histoire dev --port 3000",
94
- "story:build": "histoire build",
95
- "story:preview": "histoire preview --port 3000",
96
- "type": "vue-tsc --noEmit",
97
- "lint": "eslint --fix .",
98
- "lint:fail": "eslint .",
99
- "vitest": "vitest",
100
- "coverage": "vitest run --coverage",
101
- "test": "pnpm run type && pnpm run lint && pnpm run coverage",
102
- "test:fail": "pnpm run type && pnpm run lint:fail && pnpm run coverage",
103
- "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
104
- "release": "node scripts/release.js"
105
102
  }
106
- }
103
+ }
@@ -1,7 +0,0 @@
1
- declare module '*.vue' {
2
- import { DefineComponent } from 'vue'
3
-
4
- const component: DefineComponent<{}, {}, any>
5
-
6
- export default component
7
- }