@globalbrain/sefirot 3.40.2 → 3.42.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 +8 -2
- package/lib/components/STooltip.vue +63 -89
- package/lib/composables/Tooltip.ts +107 -72
- package/lib/validation/Rule.ts +20 -6
- package/lib/validation/rules/index.ts +2 -0
- package/lib/validation/rules/requiredHms.ts +1 -2
- package/lib/validation/rules/requiredHmsIf.ts +17 -0
- package/lib/validation/rules/requiredIf.ts +1 -0
- package/lib/validation/rules/requiredYmd.ts +1 -2
- package/lib/validation/rules/requiredYmdIf.ts +17 -0
- package/lib/validation/validators/index.ts +2 -0
- package/lib/validation/validators/requiredHmsIf.ts +19 -0
- package/lib/validation/validators/requiredYmdIf.ts +19 -0
- package/package.json +28 -25
- package/lib/types/shims.d.ts +0 -7
package/README.md
CHANGED
|
@@ -27,10 +27,16 @@ Sefirot follows the official [Vue Style Guide](https://v3.vuejs.org/style-guide/
|
|
|
27
27
|
### Development
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
$ pnpm run
|
|
30
|
+
$ pnpm run story
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Serve
|
|
33
|
+
Serve Histoire at http://localhost:4010.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
$ pnpm run docs
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Serve documentation website at http://localhost:4011.
|
|
34
40
|
|
|
35
41
|
```bash
|
|
36
42
|
$ pnpm run lint
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { onKeyStroke } from '@vueuse/core'
|
|
3
|
-
import { computed, ref, shallowRef } from 'vue'
|
|
2
|
+
import { onClickOutside, onKeyStroke, useElementHover, useFocusWithin } from '@vueuse/core'
|
|
3
|
+
import { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
|
4
4
|
import { type Position, useTooltip } from '../composables/Tooltip'
|
|
5
5
|
|
|
6
6
|
const props = withDefaults(defineProps<{
|
|
@@ -17,13 +17,13 @@ const props = withDefaults(defineProps<{
|
|
|
17
17
|
trigger: 'hover'
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
const
|
|
21
|
-
const tip = shallowRef<HTMLElement | null>(null)
|
|
20
|
+
const root = shallowRef<HTMLElement | null>(null)
|
|
22
21
|
const content = shallowRef<HTMLElement | null>(null)
|
|
22
|
+
const trigger = shallowRef<HTMLElement | null>(null)
|
|
23
23
|
|
|
24
24
|
const rootClasses = computed(() => [
|
|
25
25
|
props.display,
|
|
26
|
-
props.tabindex &&
|
|
26
|
+
props.tabindex && props.tabindex > -1 && 'focusable'
|
|
27
27
|
])
|
|
28
28
|
|
|
29
29
|
const containerClasses = computed(() => [props.position])
|
|
@@ -38,77 +38,76 @@ const tabindex = computed(() => {
|
|
|
38
38
|
})
|
|
39
39
|
|
|
40
40
|
const { on, show, hide } = useTooltip(
|
|
41
|
-
|
|
41
|
+
root,
|
|
42
|
+
trigger,
|
|
42
43
|
content,
|
|
43
|
-
tip,
|
|
44
44
|
computed(() => props.position),
|
|
45
45
|
timeoutId
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
48
|
+
const isRootHovered = useElementHover(root, { delayLeave: 100 })
|
|
49
|
+
const isContentHovered = useElementHover(content, { delayLeave: 100 })
|
|
50
|
+
const { focused: isRootFocused } = useFocusWithin(root)
|
|
51
|
+
const { focused: isContentFocused } = useFocusWithin(content)
|
|
52
|
+
const ignore = ref(false)
|
|
53
|
+
|
|
54
|
+
watch(
|
|
55
|
+
[isRootHovered, isContentHovered, isRootFocused, isContentFocused],
|
|
56
|
+
([rootHover, contentHover, rootFocus, contentFocus]) => {
|
|
57
|
+
if (ignore.value) { return }
|
|
58
|
+
if (
|
|
59
|
+
(props.trigger === 'hover' && (rootHover || contentHover))
|
|
60
|
+
|| (props.trigger === 'focus' && (rootFocus || contentHover || contentFocus))
|
|
61
|
+
|| (props.trigger === 'both' && (rootHover || contentHover || rootFocus || contentFocus))
|
|
62
|
+
) {
|
|
63
|
+
show()
|
|
64
|
+
|
|
65
|
+
if (rootFocus && props.timeout) {
|
|
66
|
+
timeoutId.value = window.setTimeout(hide, props.timeout)
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
hide()
|
|
70
|
+
}
|
|
68
71
|
}
|
|
69
|
-
|
|
72
|
+
)
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const cleanups = [
|
|
75
|
+
onKeyStroke('Escape', (e) => {
|
|
76
|
+
if (
|
|
77
|
+
on.value
|
|
78
|
+
&& props.trigger !== 'hover'
|
|
79
|
+
&& (isRootFocused.value || isContentHovered.value || isContentFocused.value)
|
|
80
|
+
) {
|
|
81
|
+
e.preventDefault()
|
|
82
|
+
e.stopPropagation()
|
|
83
|
+
ignore.value = true
|
|
84
|
+
hide()
|
|
85
|
+
setTimeout(() => { ignore.value = false })
|
|
76
86
|
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
87
|
+
}),
|
|
88
|
+
onClickOutside(root, hide, { ignore: [content] }),
|
|
89
|
+
() => timeoutId.value != null && window.clearTimeout(timeoutId.value)
|
|
90
|
+
]
|
|
79
91
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|| (props.trigger === 'both' && !el.value?.matches(':hover'))
|
|
84
|
-
) {
|
|
85
|
-
hide()
|
|
86
|
-
}
|
|
87
|
-
}
|
|
92
|
+
onBeforeUnmount(() => {
|
|
93
|
+
cleanups.forEach((cleanup) => cleanup())
|
|
94
|
+
})
|
|
88
95
|
</script>
|
|
89
96
|
|
|
90
97
|
<template>
|
|
91
|
-
<component
|
|
92
|
-
ref="
|
|
93
|
-
:is="tag"
|
|
94
|
-
class="STooltip"
|
|
95
|
-
:class="rootClasses"
|
|
96
|
-
:tabindex="tabindex"
|
|
97
|
-
@mouseenter="onMouseEnter"
|
|
98
|
-
@mouseleave="onMouseLeave"
|
|
99
|
-
@focusin="onFocus"
|
|
100
|
-
@focusout="onBlur"
|
|
101
|
-
>
|
|
102
|
-
<span class="content" ref="content">
|
|
98
|
+
<component ref="root" :is="tag" class="STooltip" :class="rootClasses" :tabindex="tabindex">
|
|
99
|
+
<span class="trigger" ref="trigger">
|
|
103
100
|
<slot />
|
|
104
101
|
</span>
|
|
105
102
|
|
|
106
|
-
<
|
|
107
|
-
<
|
|
108
|
-
<span v-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
<Teleport to="#sefirot-modals">
|
|
104
|
+
<Transition name="fade">
|
|
105
|
+
<span v-show="on" class="container" :class="containerClasses" ref="content">
|
|
106
|
+
<span v-if="$slots.text" class="tip"><slot name="text" /></span>
|
|
107
|
+
<span v-else-if="text" class="tip" v-html="text" />
|
|
108
|
+
</span>
|
|
109
|
+
</Transition>
|
|
110
|
+
</Teleport>
|
|
112
111
|
</component>
|
|
113
112
|
</template>
|
|
114
113
|
|
|
@@ -129,7 +128,7 @@ function onBlur() {
|
|
|
129
128
|
&.block { display: block; }
|
|
130
129
|
}
|
|
131
130
|
|
|
132
|
-
.
|
|
131
|
+
.trigger {
|
|
133
132
|
white-space: nowrap;
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -138,6 +137,7 @@ function onBlur() {
|
|
|
138
137
|
z-index: var(--z-index-tooltip);
|
|
139
138
|
display: block;
|
|
140
139
|
transition: opacity 0.25s;
|
|
140
|
+
padding: 8px;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
.container.fade-enter-from,
|
|
@@ -149,37 +149,11 @@ function onBlur() {
|
|
|
149
149
|
&.left .tip { transform: translateX(8px); }
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
.container.top {
|
|
153
|
-
top: 0;
|
|
154
|
-
left: 50%;
|
|
155
|
-
padding-bottom: 8px;
|
|
156
|
-
transform: translate(-50%, -100%);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.container.right {
|
|
160
|
-
top: 50%;
|
|
161
|
-
left: 100%;
|
|
162
|
-
transform: translate(8px, -50%);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.container.bottom {
|
|
166
|
-
bottom: 0;
|
|
167
|
-
left: 50%;
|
|
168
|
-
padding-top: 8px;
|
|
169
|
-
transform: translate(-50%, 100%);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
.container.left {
|
|
173
|
-
top: 50%;
|
|
174
|
-
right: 100%;
|
|
175
|
-
transform: translate(-8px, -50%);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
152
|
.tip {
|
|
179
153
|
display: block;
|
|
180
154
|
border: 1px solid var(--tooltip-border-color);
|
|
181
155
|
border-radius: 6px;
|
|
182
|
-
padding:
|
|
156
|
+
padding: 8px 12px;
|
|
183
157
|
width: max-content;
|
|
184
158
|
max-width: var(--tooltip-max-width);
|
|
185
159
|
line-height: 20px;
|
|
@@ -1,113 +1,148 @@
|
|
|
1
1
|
import { type Ref, ref } from 'vue'
|
|
2
2
|
|
|
3
|
-
export interface Tooltip {
|
|
4
|
-
on: Ref<boolean>
|
|
5
|
-
show: () => void
|
|
6
|
-
hide: () => void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
3
|
export type Position = 'top' | 'right' | 'bottom' | 'left'
|
|
10
4
|
|
|
11
5
|
const globalHide = ref<() => void>()
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
* Prevent tooltip going off-screen by adjusting the position depending on
|
|
15
|
-
* the current window size.
|
|
16
|
-
* `bottom` since we only care about left and right of the screen.
|
|
9
|
+
* the current window size.
|
|
17
10
|
*/
|
|
18
11
|
export function useTooltip(
|
|
19
|
-
|
|
12
|
+
root: Ref<HTMLElement | null>,
|
|
13
|
+
trigger: Ref<HTMLElement | null>,
|
|
20
14
|
content: Ref<HTMLElement | null>,
|
|
21
|
-
tip: Ref<HTMLElement | null>,
|
|
22
15
|
position: Ref<Position>,
|
|
23
16
|
timeoutId: Ref<number | null>
|
|
24
|
-
)
|
|
17
|
+
) {
|
|
25
18
|
const on = ref(false)
|
|
19
|
+
const showTimeout = ref<number | null>()
|
|
26
20
|
|
|
27
21
|
function show(): void {
|
|
28
22
|
if (on.value) { return }
|
|
29
23
|
globalHide.value?.()
|
|
30
|
-
setPosition()
|
|
31
|
-
setTimeout(() => {
|
|
24
|
+
setPosition(trigger.value, content.value, position.value)
|
|
25
|
+
showTimeout.value = window.setTimeout(() => {
|
|
26
|
+
showTimeout.value = null
|
|
27
|
+
on.value = true
|
|
28
|
+
}, 200)
|
|
32
29
|
globalHide.value = hide
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
function hide(): void {
|
|
33
|
+
if (showTimeout.value != null) {
|
|
34
|
+
window.clearTimeout(showTimeout.value)
|
|
35
|
+
showTimeout.value = null
|
|
36
|
+
}
|
|
37
|
+
if (timeoutId.value != null) {
|
|
38
|
+
window.clearTimeout(timeoutId.value)
|
|
39
|
+
timeoutId.value = null
|
|
40
|
+
}
|
|
36
41
|
if (!on.value) { return }
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
clearTimeout(timeoutId.value)
|
|
40
|
-
timeoutId.value = null
|
|
41
|
-
}
|
|
42
|
+
globalHide.value = undefined
|
|
43
|
+
window.setTimeout(() => {
|
|
42
44
|
on.value = false
|
|
43
|
-
if (
|
|
44
|
-
(document.activeElement as HTMLElement)?.blur?.()
|
|
45
|
+
if (root.value?.matches(':focus-within')) {
|
|
46
|
+
;(document.activeElement as HTMLElement)?.blur?.()
|
|
45
47
|
}
|
|
46
48
|
})
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
return {
|
|
52
|
+
on,
|
|
53
|
+
show,
|
|
54
|
+
hide
|
|
53
55
|
}
|
|
56
|
+
}
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
function setPosition(
|
|
59
|
+
trigger: HTMLElement | null,
|
|
60
|
+
content: HTMLElement | null,
|
|
61
|
+
placement: Position
|
|
62
|
+
): void {
|
|
63
|
+
if (typeof document === 'undefined' || !trigger || !content) { return }
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
const contentRect = content.value!.getBoundingClientRect()
|
|
64
|
-
const tipRect = tip.value!.getBoundingClientRect()
|
|
65
|
+
const pos = getCurrentPositions(trigger, content)
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
let top = pos.minY
|
|
68
|
+
let left = pos.minX
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
if (placement === 'top') {
|
|
71
|
+
top = pos.triggerTop - pos.contentHeight
|
|
72
|
+
if (top < pos.minY) {
|
|
73
|
+
top = pos.triggerTop + pos.triggerHeight
|
|
74
|
+
}
|
|
75
|
+
left = pos.triggerLeft + pos.triggerWidth / 2 - pos.contentWidth / 2
|
|
76
|
+
if (left + pos.contentWidth > pos.maxX) {
|
|
77
|
+
left = pos.maxX - pos.contentWidth
|
|
78
|
+
}
|
|
79
|
+
if (left < pos.minX) {
|
|
80
|
+
left = pos.minX
|
|
81
|
+
}
|
|
82
|
+
} else if (placement === 'right') {
|
|
83
|
+
top = pos.triggerTop + pos.triggerHeight / 2 - pos.contentHeight / 2
|
|
84
|
+
if (top + pos.contentHeight > pos.maxY) {
|
|
85
|
+
top = pos.maxY - pos.contentHeight
|
|
86
|
+
}
|
|
87
|
+
if (top < pos.minY) {
|
|
88
|
+
top = pos.minY
|
|
89
|
+
}
|
|
90
|
+
left = pos.triggerLeft + pos.triggerWidth
|
|
91
|
+
if (left + pos.contentWidth > pos.maxX) {
|
|
92
|
+
left = pos.triggerLeft - pos.contentWidth
|
|
93
|
+
}
|
|
94
|
+
} else if (placement === 'bottom') {
|
|
95
|
+
top = pos.triggerTop + pos.triggerHeight
|
|
96
|
+
if (top + pos.contentHeight > pos.maxY) {
|
|
97
|
+
top = pos.triggerTop - pos.contentHeight
|
|
98
|
+
}
|
|
99
|
+
left = pos.triggerLeft + pos.triggerWidth / 2 - pos.contentWidth / 2
|
|
100
|
+
if (left + pos.contentWidth > pos.maxX) {
|
|
101
|
+
left = pos.maxX - pos.contentWidth
|
|
102
|
+
}
|
|
103
|
+
if (left < pos.minX) {
|
|
104
|
+
left = pos.minX
|
|
105
|
+
}
|
|
106
|
+
} else if (placement === 'left') {
|
|
107
|
+
top = pos.triggerTop + pos.triggerHeight / 2 - pos.contentHeight / 2
|
|
108
|
+
if (top + pos.contentHeight > pos.maxY) {
|
|
109
|
+
top = pos.maxY - pos.contentHeight
|
|
110
|
+
}
|
|
111
|
+
if (top < pos.minY) {
|
|
112
|
+
top = pos.minY
|
|
113
|
+
}
|
|
114
|
+
left = pos.triggerLeft - pos.contentWidth
|
|
115
|
+
if (left < pos.minX) {
|
|
116
|
+
left = pos.triggerLeft + pos.triggerWidth
|
|
73
117
|
}
|
|
74
|
-
|
|
75
|
-
tip.value!.style.display = 'none'
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function adjustLeftPosition(screenPadding: number, contentRectX: number): void {
|
|
79
|
-
tip.value!.style.left = '0'
|
|
80
|
-
tip.value!.style.right = 'auto'
|
|
81
|
-
setTransform(-contentRectX + screenPadding)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function adjustRightPosition(screenPadding: number, contentRightX: number): void {
|
|
85
|
-
tip.value!.style.left = 'auto'
|
|
86
|
-
tip.value!.style.right = '0'
|
|
87
|
-
setTransform((document.body.clientWidth - contentRightX) - screenPadding)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function resetPosition(): void {
|
|
91
|
-
tip.value!.style.left = ''
|
|
92
|
-
tip.value!.style.right = ''
|
|
93
|
-
tip.value!.style.transform = ''
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function setTransform(x: number): void {
|
|
97
|
-
tip.value!.style.transform = `translate(${x}px, ${position.value === 'top' ? -100 : 100}%)`
|
|
98
118
|
}
|
|
99
119
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
120
|
+
content.style.top = `${top}px`
|
|
121
|
+
content.style.left = `${left}px`
|
|
122
|
+
}
|
|
104
123
|
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
function getCurrentPositions(trigger: HTMLElement, content: HTMLElement) {
|
|
125
|
+
const bodyRect = document.body.getBoundingClientRect()
|
|
126
|
+
const triggerRect = trigger.getBoundingClientRect()
|
|
127
|
+
const contentDisplay = content.style.display
|
|
128
|
+
content.style.display = 'block'
|
|
129
|
+
const contentRect = content.getBoundingClientRect()
|
|
130
|
+
content.style.display = contentDisplay
|
|
107
131
|
|
|
108
132
|
return {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
minX: -bodyRect.left,
|
|
134
|
+
minY: -bodyRect.top,
|
|
135
|
+
maxX: bodyRect.width - bodyRect.left,
|
|
136
|
+
maxY: bodyRect.height - bodyRect.top,
|
|
137
|
+
|
|
138
|
+
triggerTop: triggerRect.top - bodyRect.top,
|
|
139
|
+
triggerLeft: triggerRect.left - bodyRect.left,
|
|
140
|
+
triggerWidth: triggerRect.width,
|
|
141
|
+
triggerHeight: triggerRect.height,
|
|
142
|
+
|
|
143
|
+
contentTop: contentRect.top - bodyRect.top,
|
|
144
|
+
contentLeft: contentRect.left - bodyRect.left,
|
|
145
|
+
contentWidth: contentRect.width,
|
|
146
|
+
contentHeight: contentRect.height
|
|
112
147
|
}
|
|
113
148
|
}
|
package/lib/validation/Rule.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { _required } from './validators'
|
|
|
6
6
|
export interface RuleOptions {
|
|
7
7
|
optional?: boolean
|
|
8
8
|
async?: boolean
|
|
9
|
+
params?: Record<string, any>
|
|
9
10
|
message(params: MessageProps): string
|
|
10
11
|
validation(value: unknown): boolean | Promise<boolean>
|
|
11
12
|
}
|
|
@@ -19,14 +20,27 @@ export function createRule(
|
|
|
19
20
|
): ValidationRuleWithParams {
|
|
20
21
|
const lang = useLang()
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const params = options.params ?? {}
|
|
24
|
+
|
|
25
|
+
const validator = helpers.withParams(
|
|
26
|
+
params,
|
|
27
|
+
(value: unknown) => {
|
|
28
|
+
return options.optional && !_required(value)
|
|
29
|
+
? true
|
|
30
|
+
: options.validation(value)
|
|
31
|
+
}
|
|
32
|
+
)
|
|
27
33
|
|
|
28
34
|
return helpers.withMessage(
|
|
29
35
|
(params) => options.message({ ...params, lang }),
|
|
30
|
-
options.async
|
|
36
|
+
options.async
|
|
37
|
+
? helpers.withAsync(validator, createParamsForAsyncValidator(params))
|
|
38
|
+
: validator
|
|
31
39
|
)
|
|
32
40
|
}
|
|
41
|
+
|
|
42
|
+
function createParamsForAsyncValidator(params: Record<string, any>) {
|
|
43
|
+
return Object.keys(params).map((key) => {
|
|
44
|
+
return params[key]
|
|
45
|
+
})
|
|
46
|
+
}
|
|
@@ -16,8 +16,10 @@ export { negativeInteger } from './negativeInteger'
|
|
|
16
16
|
export { positiveInteger } from './positiveInteger'
|
|
17
17
|
export { required } from './required'
|
|
18
18
|
export { requiredHms } from './requiredHms'
|
|
19
|
+
export { requiredHmsIf } from './requiredHmsIf'
|
|
19
20
|
export { requiredIf } from './requiredIf'
|
|
20
21
|
export { requiredYmd } from './requiredYmd'
|
|
22
|
+
export { requiredYmdIf } from './requiredYmdIf'
|
|
21
23
|
export { rule } from './rule'
|
|
22
24
|
export { slackChannelName } from './slackChannelName'
|
|
23
25
|
export { url } from './url'
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { type HmsType } from '../../support/Day'
|
|
1
2
|
import { createRule } from '../Rule'
|
|
2
3
|
import { requiredHms as baseRequiredHms } from '../validators/requiredHms'
|
|
3
4
|
|
|
4
|
-
type HmsType = 'h' | 'm' | 's'
|
|
5
|
-
|
|
6
5
|
export const message = {
|
|
7
6
|
en: 'The field is required.',
|
|
8
7
|
ja: 'この項目は必須です。'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HmsType } from '../../support/Day'
|
|
2
|
+
import { createRule } from '../Rule'
|
|
3
|
+
import { type RequiredIfCondition, requiredHmsIf as baseRequiredHmsIf } from '../validators'
|
|
4
|
+
|
|
5
|
+
export const message = {
|
|
6
|
+
en: 'The field is required.',
|
|
7
|
+
ja: 'この項目は必須です。'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function requiredHmsIf(condition: RequiredIfCondition, required?: HmsType[], msg?: string) {
|
|
11
|
+
return createRule({
|
|
12
|
+
async: true,
|
|
13
|
+
params: { condition },
|
|
14
|
+
message: ({ lang }) => msg ?? message[lang],
|
|
15
|
+
validation: (value) => baseRequiredHmsIf(value, condition, required)
|
|
16
|
+
})
|
|
17
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { type YmdType } from '../../support/Day'
|
|
1
2
|
import { createRule } from '../Rule'
|
|
2
3
|
import { requiredYmd as baseRequiredYmd } from '../validators/requiredYmd'
|
|
3
4
|
|
|
4
|
-
type YmdType = 'y' | 'm' | 'd'
|
|
5
|
-
|
|
6
5
|
export const message = {
|
|
7
6
|
en: 'The field is required.',
|
|
8
7
|
ja: 'この項目は必須です。'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type YmdType } from '../../support/Day'
|
|
2
|
+
import { createRule } from '../Rule'
|
|
3
|
+
import { type RequiredIfCondition, requiredYmdIf as baseRequiredYmdIf } from '../validators'
|
|
4
|
+
|
|
5
|
+
export const message = {
|
|
6
|
+
en: 'The field is required.',
|
|
7
|
+
ja: 'この項目は必須です。'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function requiredYmdIf(condition: RequiredIfCondition, required?: YmdType[], msg?: string) {
|
|
11
|
+
return createRule({
|
|
12
|
+
async: true,
|
|
13
|
+
params: { condition },
|
|
14
|
+
message: ({ lang }) => msg ?? message[lang],
|
|
15
|
+
validation: (value) => baseRequiredYmdIf(value, condition, required)
|
|
16
|
+
})
|
|
17
|
+
}
|
|
@@ -15,8 +15,10 @@ export * from './negativeInteger'
|
|
|
15
15
|
export * from './positiveInteger'
|
|
16
16
|
export * from './required'
|
|
17
17
|
export * from './requiredHms'
|
|
18
|
+
export * from './requiredHmsIf'
|
|
18
19
|
export * from './requiredIf'
|
|
19
20
|
export * from './requiredYmd'
|
|
21
|
+
export * from './requiredYmdIf'
|
|
20
22
|
export * from './slackChannelName'
|
|
21
23
|
export * from './url'
|
|
22
24
|
export * from './ymd'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type HmsType } from '../../support/Day'
|
|
2
|
+
import { requiredHms } from './requiredHms'
|
|
3
|
+
import { type RequiredIfCondition } from './requiredIf'
|
|
4
|
+
|
|
5
|
+
export async function requiredHmsIf(value: unknown, condition: RequiredIfCondition, required: HmsType[] = ['h', 'm', 's']): Promise<boolean> {
|
|
6
|
+
if (typeof condition === 'boolean' && condition) {
|
|
7
|
+
return requiredHms(value, required)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (typeof condition === 'string' && condition) {
|
|
11
|
+
return requiredHms(value, required)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof condition === 'function' && (await condition())) {
|
|
15
|
+
return requiredHms(value, required)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type YmdType } from '../../support/Day'
|
|
2
|
+
import { type RequiredIfCondition } from './requiredIf'
|
|
3
|
+
import { requiredYmd } from './requiredYmd'
|
|
4
|
+
|
|
5
|
+
export async function requiredYmdIf(value: unknown, condition: RequiredIfCondition, required: YmdType[] = ['y', 'm', 'd']): Promise<boolean> {
|
|
6
|
+
if (typeof condition === 'boolean' && condition) {
|
|
7
|
+
return requiredYmd(value, required)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (typeof condition === 'string' && condition) {
|
|
11
|
+
return requiredYmd(value, required)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof condition === 'function' && (await condition())) {
|
|
15
|
+
return requiredYmd(value, required)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return true
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"packageManager": "pnpm@8.15.
|
|
3
|
+
"version": "3.42.0",
|
|
4
|
+
"packageManager": "pnpm@8.15.7",
|
|
5
5
|
"description": "Vue Components for Global Brain Design System.",
|
|
6
6
|
"author": "Kia Ishii <ka.ishii@globalbrains.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -22,12 +22,13 @@
|
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"docs": "pnpm docs:dev",
|
|
25
|
-
"docs:dev": "vitepress dev docs --port
|
|
25
|
+
"docs:dev": "vitepress dev docs --port 4011",
|
|
26
26
|
"docs:build": "vitepress build docs",
|
|
27
|
-
"docs:preview": "vitepress serve docs --port
|
|
28
|
-
"story": "
|
|
27
|
+
"docs:preview": "vitepress serve docs --port 4011",
|
|
28
|
+
"story": "pnpm story:dev",
|
|
29
|
+
"story:dev": "histoire dev --port 4010",
|
|
29
30
|
"story:build": "histoire build",
|
|
30
|
-
"story:preview": "histoire preview --port
|
|
31
|
+
"story:preview": "histoire preview --port 4010",
|
|
31
32
|
"type": "vue-tsc --noEmit",
|
|
32
33
|
"lint": "eslint --fix .",
|
|
33
34
|
"lint:fail": "eslint .",
|
|
@@ -44,8 +45,9 @@
|
|
|
44
45
|
"@iconify/vue": "^4.1.1",
|
|
45
46
|
"@types/body-scroll-lock": "^3.1.2",
|
|
46
47
|
"@types/lodash-es": "^4.17.12",
|
|
47
|
-
"@types/markdown-it": "^
|
|
48
|
-
"@vue/reactivity": "^3.4.
|
|
48
|
+
"@types/markdown-it": "^14.0.1",
|
|
49
|
+
"@vue/reactivity": "^3.4.22",
|
|
50
|
+
"@vue/runtime-core": "^3.4.22",
|
|
49
51
|
"@vuelidate/core": "^2.0.3",
|
|
50
52
|
"@vuelidate/validators": "^2.0.4",
|
|
51
53
|
"@vueuse/core": "^10.9.0",
|
|
@@ -58,35 +60,36 @@
|
|
|
58
60
|
"postcss": "^8.4.38",
|
|
59
61
|
"postcss-nested": "^6.0.1",
|
|
60
62
|
"v-calendar": "^3.1.2",
|
|
61
|
-
"vue": "^3.4.
|
|
63
|
+
"vue": "^3.4.22",
|
|
62
64
|
"vue-router": "^4.3.0"
|
|
63
65
|
},
|
|
64
66
|
"dependencies": {
|
|
65
|
-
"@sentry/browser": "^8.0.0-
|
|
67
|
+
"@sentry/browser": "^8.0.0-beta.1",
|
|
66
68
|
"@tanstack/vue-virtual": "3.0.0-beta.62",
|
|
67
69
|
"@tinyhttp/content-disposition": "^2.2.0",
|
|
68
70
|
"@tinyhttp/cookie": "^2.1.0",
|
|
69
71
|
"@types/file-saver": "^2.0.7",
|
|
70
|
-
"@types/qs": "^6.9.
|
|
72
|
+
"@types/qs": "^6.9.15",
|
|
71
73
|
"dayjs": "^1.11.10",
|
|
72
74
|
"file-saver": "^2.0.5",
|
|
73
75
|
"ofetch": "^1.3.4",
|
|
74
|
-
"qs": "^6.12.
|
|
76
|
+
"qs": "^6.12.1"
|
|
75
77
|
},
|
|
76
78
|
"devDependencies": {
|
|
77
79
|
"@globalbrain/eslint-config": "^1.6.0",
|
|
78
|
-
"@histoire/plugin-vue": "
|
|
80
|
+
"@histoire/plugin-vue": "0.16.5",
|
|
79
81
|
"@iconify-icons/ph": "^1.2.5",
|
|
80
82
|
"@iconify-icons/ri": "^1.2.10",
|
|
81
83
|
"@iconify/vue": "^4.1.1",
|
|
82
84
|
"@release-it/conventional-changelog": "^8.0.1",
|
|
83
85
|
"@types/body-scroll-lock": "^3.1.2",
|
|
84
86
|
"@types/lodash-es": "^4.17.12",
|
|
85
|
-
"@types/markdown-it": "^
|
|
86
|
-
"@types/node": "^20.
|
|
87
|
+
"@types/markdown-it": "^14.0.1",
|
|
88
|
+
"@types/node": "^20.12.7",
|
|
87
89
|
"@vitejs/plugin-vue": "^5.0.4",
|
|
88
|
-
"@vitest/coverage-v8": "^1.
|
|
89
|
-
"@vue/reactivity": "^3.4.
|
|
90
|
+
"@vitest/coverage-v8": "^1.5.0",
|
|
91
|
+
"@vue/reactivity": "^3.4.22",
|
|
92
|
+
"@vue/runtime-core": "^3.4.22",
|
|
90
93
|
"@vue/test-utils": "^2.4.5",
|
|
91
94
|
"@vuelidate/core": "^2.0.3",
|
|
92
95
|
"@vuelidate/validators": "^2.0.4",
|
|
@@ -94,8 +97,8 @@
|
|
|
94
97
|
"body-scroll-lock": "4.0.0-beta.0",
|
|
95
98
|
"eslint": "^8.57.0",
|
|
96
99
|
"fuse.js": "^7.0.0",
|
|
97
|
-
"happy-dom": "^14.
|
|
98
|
-
"histoire": "
|
|
100
|
+
"happy-dom": "^14.7.1",
|
|
101
|
+
"histoire": "0.16.5",
|
|
99
102
|
"lodash-es": "^4.17.21",
|
|
100
103
|
"markdown-it": "^14.1.0",
|
|
101
104
|
"normalize.css": "^8.0.1",
|
|
@@ -103,13 +106,13 @@
|
|
|
103
106
|
"postcss": "^8.4.38",
|
|
104
107
|
"postcss-nested": "^6.0.1",
|
|
105
108
|
"punycode": "^2.3.1",
|
|
106
|
-
"release-it": "^17.
|
|
107
|
-
"typescript": "~5.4.
|
|
109
|
+
"release-it": "^17.2.0",
|
|
110
|
+
"typescript": "~5.4.5",
|
|
108
111
|
"v-calendar": "^3.1.2",
|
|
109
|
-
"vite": "^5.2.
|
|
110
|
-
"vitepress": "1.0
|
|
111
|
-
"vitest": "^1.
|
|
112
|
-
"vue": "^3.4.
|
|
112
|
+
"vite": "^5.2.9",
|
|
113
|
+
"vitepress": "^1.1.0",
|
|
114
|
+
"vitest": "^1.5.0",
|
|
115
|
+
"vue": "^3.4.22",
|
|
113
116
|
"vue-router": "^4.3.0",
|
|
114
117
|
"vue-tsc": "^1.8.27"
|
|
115
118
|
}
|