@globalbrain/sefirot 2.1.4 → 2.2.1
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/lib/components/SInputDropdown.vue +13 -2
- package/lib/components/SInputDropdownItem.vue +3 -0
- package/lib/components/SInputDropdownItemAvatar.vue +8 -3
- package/lib/components/SInputDropdownItemText.vue +9 -4
- package/lib/components/SInputNumber.vue +51 -50
- package/lib/components/SInputText.vue +12 -1
- package/lib/components/SInputYMD.vue +1 -1
- package/lib/components/STableCellPill.vue +3 -2
- package/lib/composables/Form.ts +4 -2
- package/lib/validation/rules/index.ts +6 -0
- package/lib/validation/rules/maxValue.ts +10 -0
- package/lib/validation/rules/minValue.ts +10 -0
- package/lib/validation/rules/month.ts +11 -0
- package/lib/validation/rules/rule.ts +8 -0
- package/lib/validation/validators/month.ts +3 -0
- package/package.json +2 -2
|
@@ -83,6 +83,14 @@ const hasSelected = computed(() => {
|
|
|
83
83
|
return selected.value.length > 0
|
|
84
84
|
})
|
|
85
85
|
|
|
86
|
+
const removable = computed(() => {
|
|
87
|
+
if (isArray(props.modelValue)) {
|
|
88
|
+
return props.nullable || selected.value.length > 1
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return !!props.nullable
|
|
92
|
+
})
|
|
93
|
+
|
|
86
94
|
async function handleOpen() {
|
|
87
95
|
!props.disabled && open()
|
|
88
96
|
}
|
|
@@ -137,6 +145,7 @@ function handleArray(value: OptionValue) {
|
|
|
137
145
|
<SInputDropdownItem
|
|
138
146
|
v-if="hasSelected"
|
|
139
147
|
:items="selected"
|
|
148
|
+
:removable="removable"
|
|
140
149
|
:disabled="disabled ?? false"
|
|
141
150
|
@remove="handleSelect"
|
|
142
151
|
/>
|
|
@@ -223,8 +232,8 @@ function handleArray(value: OptionValue) {
|
|
|
223
232
|
}
|
|
224
233
|
}
|
|
225
234
|
|
|
226
|
-
.
|
|
227
|
-
.
|
|
235
|
+
.SInputDropdown.has-error {
|
|
236
|
+
.box {
|
|
228
237
|
border-color: var(--c-danger);
|
|
229
238
|
}
|
|
230
239
|
}
|
|
@@ -266,6 +275,8 @@ function handleArray(value: OptionValue) {
|
|
|
266
275
|
padding: 2px 4px;
|
|
267
276
|
font-weight: 500;
|
|
268
277
|
color: var(--c-text-3);
|
|
278
|
+
overflow: hidden;
|
|
279
|
+
white-space: nowrap;
|
|
269
280
|
}
|
|
270
281
|
|
|
271
282
|
.box-icon {
|
|
@@ -22,6 +22,7 @@ export interface ItemAvatar extends ItemBase {
|
|
|
22
22
|
|
|
23
23
|
defineProps<{
|
|
24
24
|
items: Item[]
|
|
25
|
+
removable: boolean
|
|
25
26
|
disabled: boolean
|
|
26
27
|
}>()
|
|
27
28
|
|
|
@@ -37,6 +38,7 @@ defineEmits<{
|
|
|
37
38
|
v-if="item.type === 'text' || item.type === undefined"
|
|
38
39
|
:label="item.label"
|
|
39
40
|
:value="item.value"
|
|
41
|
+
:removable="removable"
|
|
40
42
|
:disabled="disabled"
|
|
41
43
|
@remove="(v) => $emit('remove', v)"
|
|
42
44
|
/>
|
|
@@ -45,6 +47,7 @@ defineEmits<{
|
|
|
45
47
|
:label="item.label"
|
|
46
48
|
:image="item.image"
|
|
47
49
|
:value="item.value"
|
|
50
|
+
:removable="removable"
|
|
48
51
|
:disabled="disabled"
|
|
49
52
|
@remove="(v) => $emit('remove', v)"
|
|
50
53
|
/>
|
|
@@ -7,6 +7,7 @@ defineProps<{
|
|
|
7
7
|
label: string
|
|
8
8
|
image?: string | null
|
|
9
9
|
value: string | number | boolean
|
|
10
|
+
removable: boolean
|
|
10
11
|
disabled: boolean
|
|
11
12
|
}>()
|
|
12
13
|
|
|
@@ -16,7 +17,7 @@ defineEmits<{
|
|
|
16
17
|
</script>
|
|
17
18
|
|
|
18
19
|
<template>
|
|
19
|
-
<div class="SInputDropdownItemAvatar" :class="{ disabled }">
|
|
20
|
+
<div class="SInputDropdownItemAvatar" :class="{ disabled, removable }">
|
|
20
21
|
<div class="user">
|
|
21
22
|
<div class="avatar">
|
|
22
23
|
<SAvatar size="nano" :avatar="image" :name="label" />
|
|
@@ -24,7 +25,7 @@ defineEmits<{
|
|
|
24
25
|
<p class="name">{{ label }}</p>
|
|
25
26
|
</div>
|
|
26
27
|
|
|
27
|
-
<div v-if="!disabled" class="remove" role="button" @click="$emit('remove', value)">
|
|
28
|
+
<div v-if="!disabled && removable" class="remove" role="button" @click="$emit('remove', value)">
|
|
28
29
|
<div class="remove-box">
|
|
29
30
|
<SIcon :icon="IconX" class="remove-icon" />
|
|
30
31
|
</div>
|
|
@@ -37,10 +38,14 @@ defineEmits<{
|
|
|
37
38
|
display: flex;
|
|
38
39
|
border: 1px solid var(--c-divider-light);
|
|
39
40
|
border-radius: 14px;
|
|
40
|
-
padding: 0;
|
|
41
|
+
padding: 0 12px 0 0;
|
|
41
42
|
background-color: var(--c-bg-mute);
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
.SInputDropdownItemAvatar.removable {
|
|
46
|
+
padding: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
.SInputDropdownItemUserAvatar.disabled {
|
|
45
50
|
padding: 0 10px 0 0;
|
|
46
51
|
background-color: var(--c-gray-light-4);
|
|
@@ -5,6 +5,7 @@ import SIcon from './SIcon.vue'
|
|
|
5
5
|
defineProps<{
|
|
6
6
|
label: string
|
|
7
7
|
value: string | number | boolean
|
|
8
|
+
removable: boolean
|
|
8
9
|
disabled: boolean
|
|
9
10
|
}>()
|
|
10
11
|
|
|
@@ -14,10 +15,10 @@ defineEmits<{
|
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<template>
|
|
17
|
-
<div class="SInputDropdownItemText" :class="{ disabled }">
|
|
18
|
+
<div class="SInputDropdownItemText" :class="{ disabled, removable }">
|
|
18
19
|
<p class="text">{{ label }}</p>
|
|
19
20
|
|
|
20
|
-
<div v-if="!disabled" class="remove" role="button" @click.stop="$emit('remove', value)">
|
|
21
|
+
<div v-if="!disabled && removable" class="remove" role="button" @click.stop="$emit('remove', value)">
|
|
21
22
|
<div class="remove-box">
|
|
22
23
|
<SIcon :icon="IconX" class="remove-icon" />
|
|
23
24
|
</div>
|
|
@@ -30,12 +31,16 @@ defineEmits<{
|
|
|
30
31
|
display: flex;
|
|
31
32
|
border: 1px solid var(--c-divider-light);
|
|
32
33
|
border-radius: 14px;
|
|
33
|
-
padding: 0
|
|
34
|
+
padding: 0 12px;
|
|
34
35
|
background-color: var(--c-bg-mute);
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
.SInputDropdownItemText.removable {
|
|
39
|
+
padding: 0 0 0 12px;
|
|
40
|
+
}
|
|
41
|
+
|
|
37
42
|
.SInputDropdownItemText.disabled {
|
|
38
|
-
padding: 0 10px
|
|
43
|
+
padding: 0 10px;
|
|
39
44
|
background-color: var(--c-gray-light-4);
|
|
40
45
|
|
|
41
46
|
.text {
|
|
@@ -1,56 +1,35 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<SInputText
|
|
3
|
-
class="SInputNumber"
|
|
4
|
-
:name="name"
|
|
5
|
-
:size="size"
|
|
6
|
-
type="number"
|
|
7
|
-
:label="label"
|
|
8
|
-
:note="note"
|
|
9
|
-
:help="help"
|
|
10
|
-
:align="align"
|
|
11
|
-
:placeholder="placeholder"
|
|
12
|
-
:disabled="disabled"
|
|
13
|
-
:error-message="errorMessage"
|
|
14
|
-
:display-value="displayValue"
|
|
15
|
-
:model-value="String(modelValue)"
|
|
16
|
-
:validation="validation"
|
|
17
|
-
@update:model-value="emitUpdate"
|
|
18
|
-
>
|
|
19
|
-
<template #before-help>
|
|
20
|
-
<p v-if="helpFormat" class="help-text">
|
|
21
|
-
{{ valueWithSeparator }}
|
|
22
|
-
</p>
|
|
23
|
-
</template>
|
|
24
|
-
</SInputText>
|
|
25
|
-
</template>
|
|
26
|
-
|
|
27
1
|
<script setup lang="ts">
|
|
28
|
-
import { computed
|
|
2
|
+
import { computed } from 'vue'
|
|
29
3
|
import { Validatable } from '../composables/Validation'
|
|
30
4
|
import { isNullish } from '../support/Utils'
|
|
31
|
-
import SInputText
|
|
5
|
+
import SInputText from './SInputText.vue'
|
|
32
6
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
7
|
+
export type Size = 'mini' | 'small' | 'medium'
|
|
8
|
+
export type Align = 'left' | 'center' | 'right'
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{
|
|
11
|
+
size?: Size
|
|
12
|
+
name?: string
|
|
13
|
+
label?: string
|
|
14
|
+
note?: string
|
|
15
|
+
help?: string
|
|
16
|
+
placeholder?: string
|
|
17
|
+
align?: Align
|
|
18
|
+
separator?: boolean
|
|
19
|
+
disabled?: boolean
|
|
20
|
+
modelValue: number | null
|
|
21
|
+
displayValue?: string | null
|
|
22
|
+
hideError?: boolean
|
|
23
|
+
validation?: Validatable
|
|
24
|
+
}>()
|
|
48
25
|
|
|
49
|
-
const emit = defineEmits
|
|
26
|
+
const emit = defineEmits<{
|
|
27
|
+
(e: 'update:modelValue', value: number | null): void
|
|
28
|
+
}>()
|
|
50
29
|
|
|
51
30
|
const valueWithSeparator = computed(() => {
|
|
52
31
|
if (isNullish(props.modelValue)) {
|
|
53
|
-
return
|
|
32
|
+
return null
|
|
54
33
|
}
|
|
55
34
|
|
|
56
35
|
return props.modelValue >= 100000000000000000000
|
|
@@ -59,14 +38,36 @@ const valueWithSeparator = computed(() => {
|
|
|
59
38
|
})
|
|
60
39
|
|
|
61
40
|
const displayValue = computed(() => {
|
|
62
|
-
if (!props.
|
|
63
|
-
return
|
|
41
|
+
if (!isNullish(props.displayValue)) {
|
|
42
|
+
return props.displayValue
|
|
64
43
|
}
|
|
65
44
|
|
|
66
|
-
return valueWithSeparator.value
|
|
45
|
+
return !props.separator || valueWithSeparator.value === null
|
|
46
|
+
? null
|
|
47
|
+
: valueWithSeparator.value
|
|
67
48
|
})
|
|
68
49
|
|
|
69
|
-
function emitUpdate(value: string | null)
|
|
70
|
-
emit('update:modelValue', value ? Number(value)
|
|
50
|
+
function emitUpdate(value: string | null) {
|
|
51
|
+
emit('update:modelValue', isNullish(value) ? null : Number(value))
|
|
71
52
|
}
|
|
72
53
|
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<SInputText
|
|
57
|
+
class="SInputNumber"
|
|
58
|
+
:name="name"
|
|
59
|
+
:size="size"
|
|
60
|
+
type="number"
|
|
61
|
+
:label="label"
|
|
62
|
+
:note="note"
|
|
63
|
+
:help="help"
|
|
64
|
+
:align="align"
|
|
65
|
+
:placeholder="placeholder"
|
|
66
|
+
:disabled="disabled"
|
|
67
|
+
:hide-error="hideError"
|
|
68
|
+
:display-value="displayValue"
|
|
69
|
+
:model-value="String(modelValue)"
|
|
70
|
+
:validation="validation"
|
|
71
|
+
@update:model-value="emitUpdate"
|
|
72
|
+
/>
|
|
73
|
+
</template>
|
|
@@ -141,6 +141,10 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
141
141
|
font-size: 14px;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
.display {
|
|
145
|
+
top: 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
144
148
|
.icon {
|
|
145
149
|
width: 22px;
|
|
146
150
|
height: 30px;
|
|
@@ -172,6 +176,10 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
172
176
|
font-size: 16px;
|
|
173
177
|
}
|
|
174
178
|
|
|
179
|
+
.display {
|
|
180
|
+
top: 2px;
|
|
181
|
+
}
|
|
182
|
+
|
|
175
183
|
.icon {
|
|
176
184
|
width: 26px;
|
|
177
185
|
height: 38px;
|
|
@@ -203,6 +211,10 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
203
211
|
font-size: 16px;
|
|
204
212
|
}
|
|
205
213
|
|
|
214
|
+
.display {
|
|
215
|
+
top: 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
206
218
|
.icon {
|
|
207
219
|
width: 28px;
|
|
208
220
|
height: 46px;
|
|
@@ -288,7 +300,6 @@ function getValue(e: Event | FocusEvent | KeyboardEvent): string | null {
|
|
|
288
300
|
|
|
289
301
|
.display {
|
|
290
302
|
position: absolute;
|
|
291
|
-
top: 0;
|
|
292
303
|
left: 0;
|
|
293
304
|
width: 100%;
|
|
294
305
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
export type Color = 'info' | 'success' | 'warning' | 'danger' | 'mute'
|
|
4
5
|
|
|
5
6
|
const props = defineProps<{
|
|
6
7
|
value?: any
|
|
7
8
|
record: any
|
|
8
9
|
getter?: string | ((value: any) => string)
|
|
9
|
-
color?:
|
|
10
|
+
color?: Color | ((value: any) => Color)
|
|
10
11
|
}>()
|
|
11
12
|
|
|
12
13
|
const _value = computed(() => {
|
package/lib/composables/Form.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface Form<T extends Record<string, any>> {
|
|
|
14
14
|
|
|
15
15
|
export interface UseFormOptions<T extends Record<string, any>> {
|
|
16
16
|
data: T,
|
|
17
|
-
rules?: Record<string, any>
|
|
17
|
+
rules?: Record<string, any> | ((state: T) => Record<string, any>)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function useForm<
|
|
@@ -26,7 +26,9 @@ export function useForm<
|
|
|
26
26
|
|
|
27
27
|
const data = reactive(options.data)
|
|
28
28
|
|
|
29
|
-
const rules = options.rules
|
|
29
|
+
const rules = options.rules
|
|
30
|
+
? typeof options.rules === 'function' ? options.rules(data) : options.rules
|
|
31
|
+
: {}
|
|
30
32
|
|
|
31
33
|
const validation = useValidation(data, rules)
|
|
32
34
|
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
export { or, and, not } from '@vuelidate/validators'
|
|
2
|
+
|
|
1
3
|
export * from './checked'
|
|
2
4
|
export * from './email'
|
|
3
5
|
export * from './fileExtension'
|
|
4
6
|
export * from './hms'
|
|
5
7
|
export * from './maxLength'
|
|
6
8
|
export * from './minLength'
|
|
9
|
+
export * from './maxValue'
|
|
10
|
+
export * from './minValue'
|
|
7
11
|
export * from './required'
|
|
8
12
|
export * from './requiredHms'
|
|
9
13
|
export * from './requiredIf'
|
|
10
14
|
export * from './requiredYmd'
|
|
11
15
|
export * from './url'
|
|
16
|
+
export * from './month'
|
|
12
17
|
export * from './ymd'
|
|
18
|
+
export * from './rule'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { helpers, maxValue as baseMaxValue } from '@vuelidate/validators'
|
|
2
|
+
|
|
3
|
+
export function maxValue(value: number, msg?: string) {
|
|
4
|
+
return helpers.withMessage(
|
|
5
|
+
({ $params }) => {
|
|
6
|
+
return msg ?? `The value must be less or equal to ${($params as any).max}.`
|
|
7
|
+
},
|
|
8
|
+
baseMaxValue(value)
|
|
9
|
+
)
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { helpers, minValue as baseMinValue } from '@vuelidate/validators'
|
|
2
|
+
|
|
3
|
+
export function minValue(value: number, msg?: string) {
|
|
4
|
+
return helpers.withMessage(
|
|
5
|
+
({ $params }) => {
|
|
6
|
+
return msg ?? `The value must be greater or equal to ${($params as any).min}.`
|
|
7
|
+
},
|
|
8
|
+
baseMinValue(value)
|
|
9
|
+
)
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { helpers } from '@vuelidate/validators'
|
|
2
|
+
import { month as baseMonth } from '../validators/month'
|
|
3
|
+
|
|
4
|
+
export function month(msg?: string) {
|
|
5
|
+
return helpers.withMessage(
|
|
6
|
+
() => msg ?? 'The month is invalid.',
|
|
7
|
+
(value: number) => {
|
|
8
|
+
return !helpers.req(value) || baseMonth(value)
|
|
9
|
+
}
|
|
10
|
+
)
|
|
11
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Vue Components for Global Brain Design System.",
|
|
5
5
|
"files": [
|
|
6
6
|
"lib"
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"vitest": "^0.23.4",
|
|
85
85
|
"vue": "^3.2.40",
|
|
86
86
|
"vue-router": "^4.1.5",
|
|
87
|
-
"vue-tsc": "^0.
|
|
87
|
+
"vue-tsc": "^1.0.8"
|
|
88
88
|
},
|
|
89
89
|
"scripts": {
|
|
90
90
|
"docs": "vitepress dev docs --port 3000",
|