@globalbrain/sefirot 2.22.0 → 2.24.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/lib/components/SInputCheckbox.vue +48 -32
- package/lib/components/SInputCheckboxes.vue +47 -38
- package/lib/components/SInputFile.vue +2 -10
- package/lib/components/SInputRadio.vue +1 -1
- package/lib/components/SMarkdown.vue +2 -2
- package/lib/components/STable.vue +3 -3
- package/lib/components/STooltip.vue +3 -3
- package/lib/support/Day.ts +51 -3
- package/lib/validation/rules/hms.ts +3 -1
- package/lib/validation/rules/index.ts +1 -0
- package/lib/validation/rules/maxTotalFileSize.ts +16 -0
- package/lib/validation/rules/requiredHms.ts +3 -1
- package/lib/validation/rules/requiredYmd.ts +3 -1
- package/lib/validation/rules/ymd.ts +3 -1
- package/lib/validation/validators/hms.ts +4 -8
- package/lib/validation/validators/index.ts +9 -0
- package/lib/validation/validators/maxTotalFileSize.ts +17 -0
- package/lib/validation/validators/requiredHms.ts +3 -7
- package/lib/validation/validators/requiredYmd.ts +8 -3
- package/lib/validation/validators/ymd.ts +3 -8
- package/package.json +8 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { IconifyIcon } from '@iconify/vue/dist/offline'
|
|
3
|
-
import IconCheck from '@iconify-icons/ph/check'
|
|
4
|
-
import
|
|
3
|
+
import IconCheck from '@iconify-icons/ph/check-bold'
|
|
4
|
+
import { computed } from 'vue'
|
|
5
5
|
import type { Validatable } from '../composables/Validation'
|
|
6
6
|
import SIcon from './SIcon.vue'
|
|
7
7
|
import SInputBase from './SInputBase.vue'
|
|
@@ -9,31 +9,46 @@ import SInputBase from './SInputBase.vue'
|
|
|
9
9
|
export type Size = 'mini' | 'small' | 'medium'
|
|
10
10
|
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
11
11
|
|
|
12
|
-
const props = defineProps
|
|
13
|
-
size
|
|
14
|
-
label
|
|
15
|
-
info
|
|
16
|
-
note
|
|
17
|
-
help
|
|
18
|
-
checkIcon
|
|
19
|
-
checkText
|
|
20
|
-
checkColor
|
|
21
|
-
text
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
13
|
+
size?: Size
|
|
14
|
+
label?: string
|
|
15
|
+
info?: string
|
|
16
|
+
note?: string
|
|
17
|
+
help?: string
|
|
18
|
+
checkIcon?: IconifyIcon
|
|
19
|
+
checkText?: string
|
|
20
|
+
checkColor?: Color
|
|
21
|
+
text?: string
|
|
22
|
+
value?: boolean
|
|
23
|
+
modelValue?: boolean
|
|
24
|
+
validation?: Validatable
|
|
25
|
+
hideError?: boolean
|
|
26
|
+
}>(), {
|
|
27
|
+
value: undefined,
|
|
28
|
+
modelValue: undefined
|
|
24
29
|
})
|
|
25
30
|
|
|
26
|
-
const emit = defineEmits
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
(e: 'update:model-value', value: boolean): void
|
|
33
|
+
(e: 'change', value: boolean): void
|
|
34
|
+
}>()
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
const _value = computed(() => {
|
|
37
|
+
return props.modelValue !== undefined
|
|
38
|
+
? props.modelValue
|
|
39
|
+
: props.value !== undefined ? props.value : false
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
function onClick() {
|
|
43
|
+
emit('update:model-value', !_value.value)
|
|
44
|
+
emit('change', !_value.value)
|
|
30
45
|
}
|
|
31
46
|
</script>
|
|
32
47
|
|
|
33
48
|
<template>
|
|
34
49
|
<SInputBase
|
|
35
50
|
class="SInputCheckbox"
|
|
36
|
-
:class="[size]"
|
|
51
|
+
:class="[size ?? 'small']"
|
|
37
52
|
:label="label"
|
|
38
53
|
:note="note"
|
|
39
54
|
:info="info"
|
|
@@ -44,21 +59,21 @@ function emitChange() {
|
|
|
44
59
|
:validation="validation"
|
|
45
60
|
>
|
|
46
61
|
<div class="container">
|
|
47
|
-
<div class="input" :class="{ on:
|
|
62
|
+
<div class="input" :class="{ on: _value }" role="button" @click="onClick">
|
|
48
63
|
<div class="box">
|
|
49
64
|
<div class="check">
|
|
50
65
|
<SIcon :icon="IconCheck" class="check-icon" />
|
|
51
66
|
</div>
|
|
52
67
|
</div>
|
|
53
68
|
|
|
54
|
-
<p class="text">{{ text }}</p>
|
|
69
|
+
<p v-if="text" class="text">{{ text }}</p>
|
|
55
70
|
</div>
|
|
56
71
|
</div>
|
|
57
72
|
<template v-if="$slots.info" #info><slot name="info" /></template>
|
|
58
73
|
</SInputBase>
|
|
59
74
|
</template>
|
|
60
75
|
|
|
61
|
-
<style lang="postcss"
|
|
76
|
+
<style scoped lang="postcss">
|
|
62
77
|
.container {
|
|
63
78
|
display: flex;
|
|
64
79
|
}
|
|
@@ -68,19 +83,19 @@ function emitChange() {
|
|
|
68
83
|
display: flex;
|
|
69
84
|
align-items: center;
|
|
70
85
|
height: 32px;
|
|
86
|
+
cursor: pointer;
|
|
71
87
|
|
|
72
88
|
&:hover {
|
|
73
89
|
.box {
|
|
74
|
-
border-color: var(--c-
|
|
90
|
+
border-color: var(--c-info-light);
|
|
75
91
|
}
|
|
76
92
|
}
|
|
77
93
|
}
|
|
78
94
|
|
|
79
95
|
.input.on {
|
|
80
96
|
.box {
|
|
81
|
-
border-color: var(--c-
|
|
82
|
-
background-color: var(--c-
|
|
83
|
-
box-shadow: var(--shadow-depth-3);
|
|
97
|
+
border-color: var(--c-info-light);
|
|
98
|
+
background-color: var(--c-info-light);
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
.check {
|
|
@@ -91,11 +106,12 @@ function emitChange() {
|
|
|
91
106
|
|
|
92
107
|
.box {
|
|
93
108
|
position: relative;
|
|
94
|
-
border:
|
|
95
|
-
border-radius:
|
|
96
|
-
width:
|
|
97
|
-
height:
|
|
98
|
-
|
|
109
|
+
border: 1px solid var(--c-divider-1);
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
width: 16px;
|
|
112
|
+
height: 16px;
|
|
113
|
+
background-color: var(--input-bg-color);
|
|
114
|
+
transition: border-color 0.25s, background-color 0.25s;
|
|
99
115
|
}
|
|
100
116
|
|
|
101
117
|
.check {
|
|
@@ -118,9 +134,9 @@ function emitChange() {
|
|
|
118
134
|
|
|
119
135
|
.text {
|
|
120
136
|
margin: 0;
|
|
121
|
-
padding-left:
|
|
137
|
+
padding-left: 10px;
|
|
122
138
|
line-height: 20px;
|
|
123
139
|
font-size: 14px;
|
|
124
|
-
font-weight:
|
|
140
|
+
font-weight: 400;
|
|
125
141
|
}
|
|
126
142
|
</style>
|
|
@@ -1,50 +1,73 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { IconifyIcon } from '@iconify/vue/dist/offline'
|
|
3
|
-
import
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import type { Validatable } from '../composables/Validation'
|
|
4
5
|
import SInputBase from './SInputBase.vue'
|
|
5
6
|
import SInputCheckbox from './SInputCheckbox.vue'
|
|
6
7
|
|
|
7
8
|
export type Size = 'mini' | 'small' | 'medium'
|
|
8
9
|
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
export type Value = string | number | boolean
|
|
12
|
+
|
|
13
|
+
export interface Option {
|
|
11
14
|
label: string
|
|
12
|
-
value:
|
|
15
|
+
value: Value
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
const props = defineProps
|
|
16
|
-
size
|
|
17
|
-
name
|
|
18
|
-
label
|
|
19
|
-
info
|
|
20
|
-
note
|
|
21
|
-
help
|
|
22
|
-
checkIcon
|
|
23
|
-
checkText
|
|
24
|
-
checkColor
|
|
25
|
-
options:
|
|
26
|
-
|
|
18
|
+
const props = withDefaults(defineProps<{
|
|
19
|
+
size?: Size
|
|
20
|
+
name?: string
|
|
21
|
+
label?: string
|
|
22
|
+
info?: string
|
|
23
|
+
note?: string
|
|
24
|
+
help?: string
|
|
25
|
+
checkIcon?: IconifyIcon
|
|
26
|
+
checkText?: string
|
|
27
|
+
checkColor?: Color
|
|
28
|
+
options: Option[]
|
|
29
|
+
nullable?: boolean
|
|
30
|
+
value?: Value[]
|
|
31
|
+
modelValue?: Value[]
|
|
32
|
+
validation?: Validatable
|
|
33
|
+
hideError?: boolean
|
|
34
|
+
}>(), {
|
|
35
|
+
nullable: true
|
|
27
36
|
})
|
|
28
37
|
|
|
29
|
-
const emit = defineEmits
|
|
38
|
+
const emit = defineEmits<{
|
|
39
|
+
(e: 'update:model-value', value: Value[]): void
|
|
40
|
+
(e: 'change', value: Value[]): void
|
|
41
|
+
}>()
|
|
42
|
+
|
|
43
|
+
const _value = computed(() => {
|
|
44
|
+
return props.modelValue !== undefined
|
|
45
|
+
? props.modelValue
|
|
46
|
+
: props.value !== undefined ? props.value : []
|
|
47
|
+
})
|
|
30
48
|
|
|
31
|
-
function isChecked(value:
|
|
32
|
-
return
|
|
49
|
+
function isChecked(value: Value): boolean {
|
|
50
|
+
return _value.value.includes(value)
|
|
33
51
|
}
|
|
34
52
|
|
|
35
|
-
function handleChange(value:
|
|
36
|
-
const distinct =
|
|
53
|
+
function handleChange(value: Value): void {
|
|
54
|
+
const distinct = _value.value
|
|
37
55
|
.filter((v) => v !== value)
|
|
38
|
-
.concat(
|
|
56
|
+
.concat(_value.value.includes(value) ? [] : [value])
|
|
39
57
|
|
|
40
|
-
|
|
58
|
+
if (distinct.length === 0 && !props.nullable) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
emit('update:model-value', distinct)
|
|
63
|
+
emit('change', distinct)
|
|
41
64
|
}
|
|
42
65
|
</script>
|
|
43
66
|
|
|
44
67
|
<template>
|
|
45
68
|
<SInputBase
|
|
46
69
|
class="SInputCheckboxes"
|
|
47
|
-
:class="[size]"
|
|
70
|
+
:class="[size ?? 'small']"
|
|
48
71
|
:name="name"
|
|
49
72
|
:label="label"
|
|
50
73
|
:note="note"
|
|
@@ -56,7 +79,7 @@ function handleChange(value: unknown): void {
|
|
|
56
79
|
>
|
|
57
80
|
<div class="container">
|
|
58
81
|
<div class="row">
|
|
59
|
-
<div v-for="option in options" :key="option.value" class="col">
|
|
82
|
+
<div v-for="option in options" :key="String(option.value)" class="col">
|
|
60
83
|
<SInputCheckbox
|
|
61
84
|
:text="option.label"
|
|
62
85
|
:model-value="isChecked(option.value)"
|
|
@@ -68,17 +91,3 @@ function handleChange(value: unknown): void {
|
|
|
68
91
|
<template v-if="$slots.info" #info><slot name="info" /></template>
|
|
69
92
|
</SInputBase>
|
|
70
93
|
</template>
|
|
71
|
-
|
|
72
|
-
<style lang="postcss" scoped>
|
|
73
|
-
.container {
|
|
74
|
-
display: flex;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.row {
|
|
78
|
-
margin: -2px -8px;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.col {
|
|
82
|
-
padding: 2px 8px;
|
|
83
|
-
}
|
|
84
|
-
</style>
|
|
@@ -111,7 +111,7 @@ function onChange(e: Event) {
|
|
|
111
111
|
.placeholder {
|
|
112
112
|
line-height: 30px;
|
|
113
113
|
font-size: var(--input-font-size, var(--input-mini-font-size));
|
|
114
|
-
font-weight:
|
|
114
|
+
font-weight: 400;
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
@@ -123,7 +123,7 @@ function onChange(e: Event) {
|
|
|
123
123
|
.button {
|
|
124
124
|
padding: 0 8px;
|
|
125
125
|
line-height: 26px;
|
|
126
|
-
font-size:
|
|
126
|
+
font-size: 13px;
|
|
127
127
|
font-weight: 500;
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -133,10 +133,6 @@ function onChange(e: Event) {
|
|
|
133
133
|
font-size: var(--input-font-size, var(--input-small-font-size));
|
|
134
134
|
font-weight: 400;
|
|
135
135
|
}
|
|
136
|
-
|
|
137
|
-
.placeholder {
|
|
138
|
-
font-weight: 500;
|
|
139
|
-
}
|
|
140
136
|
}
|
|
141
137
|
|
|
142
138
|
.SInputFile.medium {
|
|
@@ -157,10 +153,6 @@ function onChange(e: Event) {
|
|
|
157
153
|
font-size: var(--input-font-size, var(--input-medium-font-size));
|
|
158
154
|
font-weight: 400;
|
|
159
155
|
}
|
|
160
|
-
|
|
161
|
-
.placeholder {
|
|
162
|
-
font-weight: 500;
|
|
163
|
-
}
|
|
164
156
|
}
|
|
165
157
|
|
|
166
158
|
.SInputFile.has-error {
|
|
@@ -112,7 +112,7 @@ function onClick() {
|
|
|
112
112
|
align-items: center;
|
|
113
113
|
border-radius: 50%;
|
|
114
114
|
width: 100%;
|
|
115
|
-
background-color: var(--c-info-
|
|
115
|
+
background-color: var(--c-info-light);
|
|
116
116
|
opacity: 0;
|
|
117
117
|
transform: scale(0);
|
|
118
118
|
transition: opacity 0.25s, transform 0.1s;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, nextTick,
|
|
2
|
+
import { computed, nextTick, shallowRef, watch } from 'vue'
|
|
3
3
|
import type { LinkCallback, LinkSubscriberPayload } from '../composables/Markdown'
|
|
4
4
|
import { useLink, useMarkdown } from '../composables/Markdown'
|
|
5
5
|
|
|
@@ -14,7 +14,7 @@ const emit = defineEmits<{
|
|
|
14
14
|
(e: 'clicked', payload: LinkSubscriberPayload): void
|
|
15
15
|
}>()
|
|
16
16
|
|
|
17
|
-
const container =
|
|
17
|
+
const container = shallowRef<Element | null>(null)
|
|
18
18
|
|
|
19
19
|
const { addListeners, subscribe } = useLink({
|
|
20
20
|
container,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, reactive,
|
|
2
|
+
import { computed, reactive, shallowRef, toRefs, watch } from 'vue'
|
|
3
3
|
import type { Table } from '../composables/Table'
|
|
4
4
|
import SSpinner from './SSpinner.vue'
|
|
5
5
|
import STableCell from './STableCell.vue'
|
|
@@ -29,8 +29,8 @@ const {
|
|
|
29
29
|
onReset
|
|
30
30
|
} = toRefs(props.options)
|
|
31
31
|
|
|
32
|
-
const head =
|
|
33
|
-
const body =
|
|
32
|
+
const head = shallowRef<HTMLElement | null>(null)
|
|
33
|
+
const body = shallowRef<HTMLElement | null>(null)
|
|
34
34
|
|
|
35
35
|
let headLock = false
|
|
36
36
|
let bodyLock = false
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed,
|
|
2
|
+
import { computed, shallowRef } from 'vue'
|
|
3
3
|
import type { Position } from '../composables/Tooltip'
|
|
4
4
|
import { useTooltip } from '../composables/Tooltip'
|
|
5
5
|
import SMarkdown from './SMarkdown.vue'
|
|
@@ -10,8 +10,8 @@ const props = defineProps<{
|
|
|
10
10
|
position?: Position
|
|
11
11
|
}>()
|
|
12
12
|
|
|
13
|
-
const tip =
|
|
14
|
-
const content =
|
|
13
|
+
const tip = shallowRef<HTMLElement | null>(null)
|
|
14
|
+
const content = shallowRef<HTMLElement | null>(null)
|
|
15
15
|
const classes = computed(() => [props.position ?? 'top'])
|
|
16
16
|
|
|
17
17
|
const { on, show, hide } = useTooltip(
|
package/lib/support/Day.ts
CHANGED
|
@@ -4,13 +4,31 @@ import PluginRelativeTime from 'dayjs/plugin/relativeTime'
|
|
|
4
4
|
import PluginTimezone from 'dayjs/plugin/timezone'
|
|
5
5
|
import PluginUtc from 'dayjs/plugin/utc'
|
|
6
6
|
|
|
7
|
-
export type Day = Dayjs
|
|
8
|
-
export type Input = ConfigType
|
|
9
|
-
|
|
10
7
|
dayjs.extend(PluginUtc)
|
|
11
8
|
dayjs.extend(PluginTimezone)
|
|
12
9
|
dayjs.extend(PluginRelativeTime)
|
|
13
10
|
|
|
11
|
+
export type Day = Dayjs
|
|
12
|
+
export type Input = ConfigType
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The year, month, and date object interface.
|
|
16
|
+
*/
|
|
17
|
+
export interface Ymd {
|
|
18
|
+
year: number | null
|
|
19
|
+
month: number | null
|
|
20
|
+
date: number | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The hour, minute, and second object interface.
|
|
25
|
+
*/
|
|
26
|
+
export interface Hms {
|
|
27
|
+
hour: string | null
|
|
28
|
+
minute: string | null
|
|
29
|
+
second: string | null
|
|
30
|
+
}
|
|
31
|
+
|
|
14
32
|
export function day(input?: Input): Day {
|
|
15
33
|
return dayjs(input)
|
|
16
34
|
}
|
|
@@ -22,3 +40,33 @@ export function utc(input?: Input): Day {
|
|
|
22
40
|
export function tz(input?: Input, timezone?: string): Day {
|
|
23
41
|
return dayjs.tz(input, timezone)
|
|
24
42
|
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new `Ymd` object.
|
|
46
|
+
*/
|
|
47
|
+
export function createYmd(
|
|
48
|
+
year: number | null = null,
|
|
49
|
+
month: number | null = null,
|
|
50
|
+
date: number | null = null
|
|
51
|
+
): Ymd {
|
|
52
|
+
return {
|
|
53
|
+
year,
|
|
54
|
+
month,
|
|
55
|
+
date
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Creates a new `Hms` object.
|
|
61
|
+
*/
|
|
62
|
+
export function createHms(
|
|
63
|
+
hour: string | null = null,
|
|
64
|
+
minute: string | null = null,
|
|
65
|
+
second: string | null = null
|
|
66
|
+
): Hms {
|
|
67
|
+
return {
|
|
68
|
+
hour,
|
|
69
|
+
minute,
|
|
70
|
+
second
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { helpers } from '@vuelidate/validators'
|
|
2
|
-
import type { Hms
|
|
2
|
+
import type { Hms } from '../../support/Day'
|
|
3
3
|
import { hms as baseHms } from '../validators/hms'
|
|
4
4
|
|
|
5
|
+
type HmsType = 'h' | 'm' | 's'
|
|
6
|
+
|
|
5
7
|
export function hms(required?: HmsType[], msg?: string) {
|
|
6
8
|
return helpers.withMessage(
|
|
7
9
|
() => msg ?? 'The time is invalid.',
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { helpers } from '@vuelidate/validators'
|
|
2
|
+
import { maxTotalFileSize as baseMaxTotalFileSize } from '../validators/maxTotalFileSize'
|
|
3
|
+
|
|
4
|
+
export function maxTotalFileSize(size: string, msg?: string) {
|
|
5
|
+
return helpers.withParams(
|
|
6
|
+
{ size },
|
|
7
|
+
helpers.withMessage(
|
|
8
|
+
({ $params }) => {
|
|
9
|
+
return msg ?? `The total file size must be smaller than ${$params.size}.`
|
|
10
|
+
},
|
|
11
|
+
(files: File[]) => {
|
|
12
|
+
return !helpers.req(files) || baseMaxTotalFileSize(files, size)
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { helpers } from '@vuelidate/validators'
|
|
2
|
-
import type { Hms
|
|
2
|
+
import type { Hms } from '../../support/Day'
|
|
3
3
|
import { requiredHms as baseRequiredHms } from '../validators/requiredHms'
|
|
4
4
|
|
|
5
|
+
type HmsType = 'h' | 'm' | 's'
|
|
6
|
+
|
|
5
7
|
export function requiredHms(required?: HmsType[], msg?: string) {
|
|
6
8
|
return helpers.withMessage(
|
|
7
9
|
() => msg ?? 'The field is required.',
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { helpers } from '@vuelidate/validators'
|
|
2
|
-
import type { Ymd
|
|
2
|
+
import type { Ymd } from '../../support/Day'
|
|
3
3
|
import { requiredYmd as baseRequiredYmd } from '../validators/requiredYmd'
|
|
4
4
|
|
|
5
|
+
type YmdType = 'y' | 'm' | 'd'
|
|
6
|
+
|
|
5
7
|
export function requiredYmd(required?: YmdType[], msg?: string) {
|
|
6
8
|
return helpers.withMessage(
|
|
7
9
|
() => msg ?? 'The field is required.',
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { helpers } from '@vuelidate/validators'
|
|
2
|
-
import type { Ymd
|
|
2
|
+
import type { Ymd } from '../../support/Day'
|
|
3
3
|
import { ymd as baseYmd } from '../validators/ymd'
|
|
4
4
|
|
|
5
|
+
type YmdType = 'y' | 'm' | 'd'
|
|
6
|
+
|
|
5
7
|
export function ymd(required?: YmdType[], msg?: string) {
|
|
6
8
|
return helpers.withMessage(
|
|
7
9
|
() => msg ?? 'The date is invalid.',
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
hour?: string | null
|
|
3
|
-
minute?: string | null
|
|
4
|
-
second?: string | null
|
|
5
|
-
}
|
|
1
|
+
import type { Hms } from '../../support/Day'
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
type HmsType = 'h' | 'm' | 's'
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
const HmsMap = {
|
|
10
6
|
h: 'hour',
|
|
11
7
|
m: 'minute',
|
|
12
8
|
s: 'second'
|
|
@@ -16,7 +12,7 @@ export function hms(hms: Hms, required: HmsType[] = ['h', 'm', 's']): boolean {
|
|
|
16
12
|
return required.every((r) => {
|
|
17
13
|
const value = hms[HmsMap[r]]
|
|
18
14
|
|
|
19
|
-
if (value ===
|
|
15
|
+
if (value === null) {
|
|
20
16
|
return true
|
|
21
17
|
}
|
|
22
18
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './checked'
|
|
2
|
+
export * from './fileExtension'
|
|
3
|
+
export * from './hms'
|
|
4
|
+
export * from './maxFileSize'
|
|
5
|
+
export * from './maxTotalFileSize'
|
|
6
|
+
export * from './month'
|
|
7
|
+
export * from './requiredHms'
|
|
8
|
+
export * from './requiredYmd'
|
|
9
|
+
export * from './ymd'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates if the total size of the given files is smaller than the
|
|
3
|
+
* given size.
|
|
4
|
+
*/
|
|
5
|
+
export function maxTotalFileSize(files: File[], size: string): boolean {
|
|
6
|
+
const factor = /gb/i.test(size)
|
|
7
|
+
? 1e9
|
|
8
|
+
: /mb/i.test(size)
|
|
9
|
+
? 1e6
|
|
10
|
+
: /kb/i.test(size)
|
|
11
|
+
? 1e3
|
|
12
|
+
: 1
|
|
13
|
+
|
|
14
|
+
const total = files.reduce((total, file) => total + file.size, 0)
|
|
15
|
+
|
|
16
|
+
return total <= factor * +size.replace(/[^\d\.]/g, '')
|
|
17
|
+
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
hour?: string | null
|
|
3
|
-
minute?: string | null
|
|
4
|
-
second?: string | null
|
|
5
|
-
}
|
|
1
|
+
import type { Hms } from '../../support/Day'
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
type HmsType = 'h' | 'm' | 's'
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
const HmsMap = {
|
|
10
6
|
h: 'hour',
|
|
11
7
|
m: 'minute',
|
|
12
8
|
s: 'second'
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type { Ymd
|
|
2
|
-
import { YmdMap } from './ymd'
|
|
1
|
+
import type { Ymd } from '../../support/Day'
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
type YmdType = 'y' | 'm' | 'd'
|
|
4
|
+
|
|
5
|
+
const YmdMap = {
|
|
6
|
+
y: 'year',
|
|
7
|
+
m: 'month',
|
|
8
|
+
d: 'date'
|
|
9
|
+
} as const
|
|
5
10
|
|
|
6
11
|
export function requiredYmd(ymd: Ymd, required: YmdType[] = ['y', 'm', 'd']): boolean {
|
|
7
12
|
return required.every((r) => ymd[YmdMap[r]] != null)
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import day from 'dayjs'
|
|
2
|
+
import type { Ymd } from '../../support/Day'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
year: number | null
|
|
5
|
-
month: number | null
|
|
6
|
-
date: number | null
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type YmdType = 'y' | 'm' | 'd'
|
|
4
|
+
type YmdType = 'y' | 'm' | 'd'
|
|
10
5
|
|
|
11
|
-
|
|
6
|
+
const YmdMap = {
|
|
12
7
|
y: 'year',
|
|
13
8
|
m: 'month',
|
|
14
9
|
d: 'date'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"packageManager": "pnpm@7.26.2",
|
|
5
5
|
"description": "Vue Components for Global Brain Design System.",
|
|
6
6
|
"author": "Kia Ishii <ka.ishii@globalbrains.com>",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"@types/body-scroll-lock": "^3.1.0",
|
|
54
54
|
"@types/lodash-es": "^4.17.6",
|
|
55
55
|
"@types/markdown-it": "^12.2.3",
|
|
56
|
-
"@types/node": "^18.
|
|
56
|
+
"@types/node": "^18.14.6",
|
|
57
57
|
"@vitejs/plugin-vue": "^4.0.0",
|
|
58
|
-
"@vitest/coverage-c8": "^0.
|
|
59
|
-
"@vue/test-utils": "^2.
|
|
58
|
+
"@vitest/coverage-c8": "^0.29.2",
|
|
59
|
+
"@vue/test-utils": "^2.3.0",
|
|
60
60
|
"@vuelidate/core": "^2.0.0",
|
|
61
61
|
"@vuelidate/validators": "^2.0.0",
|
|
62
62
|
"@vueuse/core": "^9.11.1",
|
|
@@ -77,12 +77,12 @@
|
|
|
77
77
|
"semver": "^7.3.8",
|
|
78
78
|
"typescript": "^4.9.4",
|
|
79
79
|
"v-calendar": "3.0.0-alpha.8",
|
|
80
|
-
"vite": "^4.
|
|
81
|
-
"vitepress": "1.0.0-alpha.
|
|
82
|
-
"vitest": "^0.
|
|
80
|
+
"vite": "^4.1.4",
|
|
81
|
+
"vitepress": "1.0.0-alpha.50",
|
|
82
|
+
"vitest": "^0.29.2",
|
|
83
83
|
"vue": "^3.2.45",
|
|
84
84
|
"vue-router": "^4.1.6",
|
|
85
|
-
"vue-tsc": "^1.0
|
|
85
|
+
"vue-tsc": "^1.2.0"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"docs": "vitepress dev docs --port 4000",
|