@globalbrain/sefirot 2.0.0-draft.8 → 2.0.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 +6 -6
- package/lib/components/SAvatar.vue +17 -17
- package/lib/components/SButton.vue +512 -267
- package/lib/components/SButtonGroup.vue +149 -0
- package/lib/components/SDropdown.vue +26 -150
- package/lib/components/SDropdownSection.vue +48 -0
- package/lib/components/SDropdownSectionFilter.vue +189 -0
- package/lib/components/SDropdownSectionFilterItem.vue +21 -0
- package/lib/components/SDropdownSectionFilterItemAvatar.vue +31 -0
- package/lib/components/SDropdownSectionFilterItemText.vue +20 -0
- package/lib/components/SDropdownSectionMenu.vue +39 -0
- package/lib/components/SIcon.vue +13 -0
- package/lib/components/SInputBase.vue +31 -31
- package/lib/components/SInputCheckbox.vue +1 -1
- package/lib/components/SInputCheckboxes.vue +74 -0
- package/lib/components/SInputDate.vue +182 -0
- package/lib/components/SInputDropdown.vue +158 -157
- package/lib/components/SInputDropdownItem.vue +46 -48
- package/lib/components/{SInputDropdownItemUserTag.vue → SInputDropdownItemAvatar.vue} +43 -44
- package/lib/components/SInputDropdownItemText.vue +79 -16
- package/lib/components/SInputFile.vue +55 -60
- package/lib/components/SInputHMS.vue +120 -110
- package/lib/components/SInputNumber.vue +38 -9
- package/lib/components/SInputRadio.vue +39 -36
- package/lib/components/SInputRadios.vue +40 -53
- package/lib/components/SInputSelect.vue +3 -3
- package/lib/components/SInputSwitch.vue +193 -0
- package/lib/components/SInputSwitches.vue +88 -0
- package/lib/components/SInputText.vue +206 -62
- package/lib/components/SInputTextarea.vue +46 -32
- package/lib/components/SInputYMD.vue +123 -126
- package/lib/components/SMarkdown.vue +52 -0
- package/lib/components/SModal.vue +25 -63
- package/lib/components/SMount.vue +19 -0
- package/lib/components/SSheet.vue +49 -55
- package/lib/components/SSheetFooter.vue +1 -1
- package/lib/components/SSheetFooterAction.vue +24 -17
- package/lib/components/SSheetFooterActions.vue +1 -4
- package/lib/components/SSheetForm.vue +15 -0
- package/lib/components/SSheetMedium.vue +8 -10
- package/lib/components/SSheetTitle.vue +7 -14
- package/lib/components/SSnackbar.vue +55 -45
- package/lib/components/{SPortalSnackbars.vue → SSnackbars.vue} +17 -20
- package/lib/components/SStep.vue +106 -0
- package/lib/components/SSteps.vue +59 -0
- package/lib/components/STable.vue +241 -0
- package/lib/components/STableCell.vue +82 -0
- package/lib/components/STableCellAvatar.vue +69 -0
- package/lib/components/STableCellAvatars.vue +93 -0
- package/lib/components/STableCellDay.vue +40 -0
- package/lib/components/STableCellPill.vue +84 -0
- package/lib/components/STableCellText.vue +102 -0
- package/lib/components/STableColumn.vue +255 -0
- package/lib/components/STableFooter.vue +115 -0
- package/lib/components/STableHeader.vue +74 -0
- package/lib/components/STableItem.vue +38 -0
- package/lib/components/STooltip.vue +112 -0
- package/lib/composables/Dropdown.ts +40 -99
- package/lib/composables/Form.ts +21 -18
- package/lib/composables/Grid.ts +117 -0
- package/lib/composables/Markdown.ts +138 -0
- package/lib/composables/Step.ts +7 -0
- package/lib/composables/Table.ts +103 -0
- package/lib/composables/Tooltip.ts +91 -0
- package/lib/composables/Validation.ts +5 -9
- package/lib/composables/markdown/LinkPlugin.ts +45 -0
- package/lib/mixins/Sheet.ts +5 -3
- package/lib/stores/Snackbars.ts +48 -0
- package/lib/{assets/styles → styles}/base.css +0 -0
- package/lib/{assets/styles → styles}/bootstrap.css +1 -0
- package/lib/{assets/styles → styles}/variables.css +55 -48
- package/lib/support/Day.ts +8 -0
- package/lib/support/Num.ts +3 -0
- package/lib/support/Time.ts +5 -2
- package/lib/support/Utils.ts +4 -3
- package/lib/types/shims.d.ts +3 -0
- package/lib/validation/validators/requiredYmd.ts +1 -1
- package/lib/validation/validators/ymd.ts +4 -4
- package/package.json +57 -37
- package/CHANGELOG.md +0 -47
- package/lib/.DS_Store +0 -0
- package/lib/components/.DS_Store +0 -0
- package/lib/components/SDialog.vue +0 -140
- package/lib/components/SDropdownItem.vue +0 -78
- package/lib/components/SDropdownItemText.vue +0 -22
- package/lib/components/SDropdownItemUser.vue +0 -40
- package/lib/components/SInputDropdownItemTextTag.vue +0 -94
- package/lib/components/SInputDropdownItemUser.vue +0 -41
- package/lib/components/SPortalModals.vue +0 -74
- package/lib/components/icons/.DS_Store +0 -0
- package/lib/composables/Dialog.ts +0 -38
- package/lib/composables/Modal.ts +0 -34
- package/lib/composables/Snackbar.ts +0 -18
- package/lib/store/Sefirot.ts +0 -17
- package/lib/store/dialog/index.ts +0 -42
- package/lib/store/modal/index.ts +0 -61
- package/lib/store/snackbars/index.ts +0 -70
|
@@ -1,28 +1,91 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import SIconX from './icons/SIconX.vue'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
label: string
|
|
6
|
+
value: string | number | boolean
|
|
7
|
+
disabled: boolean
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
defineEmits<{
|
|
11
|
+
(e: 'remove', value: string | number | boolean): void
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
1
15
|
<template>
|
|
2
|
-
<div class="SInputDropdownItemText" :class="{
|
|
3
|
-
<p class="text">{{
|
|
16
|
+
<div class="SInputDropdownItemText" :class="{ disabled }">
|
|
17
|
+
<p class="text">{{ label }}</p>
|
|
18
|
+
|
|
19
|
+
<div v-if="!disabled" class="remove" role="button" @click.stop="$emit('remove', value)">
|
|
20
|
+
<div class="remove-box">
|
|
21
|
+
<SIconX class="remove-icon" />
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
4
24
|
</div>
|
|
5
25
|
</template>
|
|
6
26
|
|
|
7
|
-
<
|
|
8
|
-
|
|
27
|
+
<style lang="postcss" scoped>
|
|
28
|
+
.SInputDropdownItemText {
|
|
29
|
+
display: flex;
|
|
30
|
+
border: 1px solid var(--c-divider-light);
|
|
31
|
+
border-radius: 14px;
|
|
32
|
+
padding: 0 0 0 12px;
|
|
33
|
+
background-color: var(--c-bg-mute);
|
|
34
|
+
}
|
|
9
35
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
disabled: { type: Boolean, default: false }
|
|
14
|
-
})
|
|
15
|
-
</script>
|
|
36
|
+
.SInputDropdownItemText.disabled {
|
|
37
|
+
padding: 0 10px 0;
|
|
38
|
+
background-color: var(--c-gray-light-4);
|
|
16
39
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
40
|
+
.text {
|
|
41
|
+
color: var(--c-text-2);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.dark .SInputDropdownItemText.disabled {
|
|
46
|
+
background-color: var(--c-gray-dark-2);
|
|
20
47
|
}
|
|
21
48
|
|
|
22
49
|
.text {
|
|
23
50
|
margin: 0;
|
|
24
|
-
|
|
25
|
-
font-size:
|
|
26
|
-
font-weight:
|
|
51
|
+
line-height: 26px;
|
|
52
|
+
font-size: 12px;
|
|
53
|
+
font-weight: 500;
|
|
54
|
+
white-space: nowrap;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.remove {
|
|
58
|
+
display: flex;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
align-items: center;
|
|
61
|
+
width: 26px;
|
|
62
|
+
height: 26px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.remove-box {
|
|
66
|
+
display: flex;
|
|
67
|
+
justify-content: center;
|
|
68
|
+
align-items: center;
|
|
69
|
+
border-radius: 50%;
|
|
70
|
+
width: 20px;
|
|
71
|
+
height: 20px;
|
|
72
|
+
color: var(--c-text-2);
|
|
73
|
+
transition: color 0.25s, background-color 0.25s;
|
|
74
|
+
|
|
75
|
+
.remove:hover & {
|
|
76
|
+
color: var(--c-text-1);
|
|
77
|
+
background-color: var(--c-gray-light-3)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.dark .remove:hover & {
|
|
81
|
+
color: var(--c-text-1);
|
|
82
|
+
background-color: var(--c-gray-dark-3)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.remove-icon {
|
|
87
|
+
width: 12px;
|
|
88
|
+
height: 12px;
|
|
89
|
+
fill: currentColor;
|
|
27
90
|
}
|
|
28
91
|
</style>
|
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import { Validatable } from '../composables/Validation'
|
|
4
|
+
import SInputBase from './SInputBase.vue'
|
|
5
|
+
|
|
6
|
+
export type Size = 'mini' | 'small' | 'medium'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
size?: Size
|
|
10
|
+
label?: string
|
|
11
|
+
text?: string
|
|
12
|
+
note?: string
|
|
13
|
+
help?: string
|
|
14
|
+
placeholder?: string
|
|
15
|
+
modelValue: File | null
|
|
16
|
+
hideError?: boolean
|
|
17
|
+
validation?: Validatable
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const emit = defineEmits<{
|
|
21
|
+
(e: 'update:modelValue', file: File | null): void
|
|
22
|
+
}>()
|
|
23
|
+
|
|
24
|
+
const input = ref<HTMLInputElement | null>(null)
|
|
25
|
+
|
|
26
|
+
const classes = computed(() => [props.size ?? 'small'])
|
|
27
|
+
|
|
28
|
+
const fileName = computed(() => {
|
|
29
|
+
return props.modelValue ? props.modelValue.name : null
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
function open(): void {
|
|
33
|
+
input.value!.click()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function handleChange(e: Event): void {
|
|
37
|
+
const file = (e.target as any).files[0]
|
|
38
|
+
|
|
39
|
+
emit('update:modelValue', file ?? null)
|
|
40
|
+
|
|
41
|
+
file && props.validation?.$touch()
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
1
45
|
<template>
|
|
2
46
|
<SInputBase
|
|
3
47
|
class="SInputFile"
|
|
@@ -5,7 +49,7 @@
|
|
|
5
49
|
:label="label"
|
|
6
50
|
:note="note"
|
|
7
51
|
:help="help"
|
|
8
|
-
:error
|
|
52
|
+
:hide-error="hideError"
|
|
9
53
|
:validation="validation"
|
|
10
54
|
>
|
|
11
55
|
<input
|
|
@@ -18,7 +62,7 @@
|
|
|
18
62
|
<div class="box" role="button" @click="open">
|
|
19
63
|
<div class="action">
|
|
20
64
|
<button class="button">
|
|
21
|
-
{{ text }}
|
|
65
|
+
{{ text ?? 'Choose File' }}
|
|
22
66
|
</button>
|
|
23
67
|
</div>
|
|
24
68
|
|
|
@@ -30,48 +74,6 @@
|
|
|
30
74
|
</SInputBase>
|
|
31
75
|
</template>
|
|
32
76
|
|
|
33
|
-
<script setup lang="ts">
|
|
34
|
-
import { PropType, ref, computed } from 'vue'
|
|
35
|
-
import { Validation, Validatable } from '../composables/Validation'
|
|
36
|
-
import SInputBase from './SInputBase.vue'
|
|
37
|
-
|
|
38
|
-
type Size = 'mini' | 'small' | 'medium'
|
|
39
|
-
|
|
40
|
-
const props = defineProps({
|
|
41
|
-
size: { type: String as PropType<Size>, default: 'small' },
|
|
42
|
-
label: { type: String, default: null },
|
|
43
|
-
note: { type: String, default: null },
|
|
44
|
-
text: { type: String, default: 'Choose File' },
|
|
45
|
-
help: { type: String, default: null },
|
|
46
|
-
placeholder: { type: String, default: null },
|
|
47
|
-
errorMessage: { type: Boolean, default: true },
|
|
48
|
-
modelValue: { type: Object as PropType<File | null>, default: null },
|
|
49
|
-
validation: { type: Object as PropType<Validatable>, default: null }
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
const emit = defineEmits(['update:modelValue'])
|
|
53
|
-
|
|
54
|
-
const input = ref<HTMLInputElement | null>(null)
|
|
55
|
-
|
|
56
|
-
const classes = computed(() => [props.size])
|
|
57
|
-
|
|
58
|
-
const fileName = computed(() => {
|
|
59
|
-
return props.modelValue ? props.modelValue.name : null
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
function open(): void {
|
|
63
|
-
input.value!.click()
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function handleChange(e: Event): void {
|
|
67
|
-
const file = (e.target as any).files[0]
|
|
68
|
-
|
|
69
|
-
emit('update:modelValue', file ?? null)
|
|
70
|
-
|
|
71
|
-
file && props.validation?.$touch()
|
|
72
|
-
}
|
|
73
|
-
</script>
|
|
74
|
-
|
|
75
77
|
<style lang="postcss" scoped>
|
|
76
78
|
.SInputFile.mini {
|
|
77
79
|
.action {
|
|
@@ -152,25 +154,22 @@ function handleChange(e: Event): void {
|
|
|
152
154
|
|
|
153
155
|
.box {
|
|
154
156
|
display: flex;
|
|
155
|
-
border: 1px solid var(--
|
|
157
|
+
border: 1px solid var(--c-divider);
|
|
156
158
|
border-radius: 4px;
|
|
159
|
+
background-color: var(--c-bg);
|
|
157
160
|
cursor: pointer;
|
|
158
161
|
transition: border-color .25s;
|
|
159
162
|
|
|
160
163
|
&:hover {
|
|
161
|
-
border-color: var(--
|
|
164
|
+
border-color: var(--c-black);
|
|
162
165
|
|
|
163
166
|
.button {
|
|
164
|
-
background-color: var(--c-
|
|
167
|
+
background-color: var(--c-bg-soft);
|
|
165
168
|
}
|
|
166
169
|
}
|
|
167
|
-
}
|
|
168
170
|
|
|
169
|
-
.dark
|
|
170
|
-
|
|
171
|
-
.button {
|
|
172
|
-
background-color: var(--c-gray-dark-3);
|
|
173
|
-
}
|
|
171
|
+
.dark &:hover {
|
|
172
|
+
border-color: var(--c-gray);
|
|
174
173
|
}
|
|
175
174
|
}
|
|
176
175
|
|
|
@@ -182,17 +181,13 @@ function handleChange(e: Event): void {
|
|
|
182
181
|
border: 1px solid var(--c-divider-light);
|
|
183
182
|
border-radius: 4px;
|
|
184
183
|
color: var(--c-text-1);
|
|
185
|
-
background-color: var(--c-
|
|
186
|
-
transition: background-color .25s;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
.dark .button {
|
|
190
|
-
background-color: var(--c-black-mute);
|
|
184
|
+
background-color: var(--c-bg-mute);
|
|
191
185
|
transition: background-color .25s;
|
|
192
186
|
}
|
|
193
187
|
|
|
194
188
|
.text {
|
|
195
189
|
flex-grow: 1;
|
|
190
|
+
font-weight: 500;
|
|
196
191
|
overflow: hidden;
|
|
197
192
|
}
|
|
198
193
|
|
|
@@ -207,6 +202,6 @@ function handleChange(e: Event): void {
|
|
|
207
202
|
}
|
|
208
203
|
|
|
209
204
|
.placeholder {
|
|
210
|
-
color: var(--
|
|
205
|
+
color: var(--c-text-2);
|
|
211
206
|
}
|
|
212
207
|
</style>
|
|
@@ -1,86 +1,37 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<SInputBase
|
|
3
|
-
class="SInputHMS"
|
|
4
|
-
:class="[size, { disabled }]"
|
|
5
|
-
:label="label"
|
|
6
|
-
:note="note"
|
|
7
|
-
:help="help"
|
|
8
|
-
:error-message="errorMessage"
|
|
9
|
-
:validation="validation"
|
|
10
|
-
>
|
|
11
|
-
<div class="container">
|
|
12
|
-
<input
|
|
13
|
-
v-if="hour"
|
|
14
|
-
class="input hour"
|
|
15
|
-
:value="modelValue?.hour ?? null"
|
|
16
|
-
placeholder="00"
|
|
17
|
-
:disabled="disabled"
|
|
18
|
-
@blur="updateHour"
|
|
19
|
-
>
|
|
20
|
-
<div v-if="hour && minute" class="separator" />
|
|
21
|
-
<input
|
|
22
|
-
v-if="minute"
|
|
23
|
-
class="input minute"
|
|
24
|
-
:value="modelValue?.minute ?? null"
|
|
25
|
-
placeholder="00"
|
|
26
|
-
:disabled="disabled"
|
|
27
|
-
@blur="updateMinute"
|
|
28
|
-
>
|
|
29
|
-
<div v-if="minute && second" class="separator" />
|
|
30
|
-
<input
|
|
31
|
-
v-if="second"
|
|
32
|
-
class="input second"
|
|
33
|
-
:value="modelValue?.second ?? null"
|
|
34
|
-
placeholder="00"
|
|
35
|
-
:disabled="disabled"
|
|
36
|
-
@blur="updateSecond"
|
|
37
|
-
>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<template #before-help>
|
|
41
|
-
<slot name="before-help" />
|
|
42
|
-
</template>
|
|
43
|
-
</SInputBase>
|
|
44
|
-
</template>
|
|
45
|
-
|
|
46
1
|
<script setup lang="ts">
|
|
47
|
-
import {
|
|
48
|
-
import { SyntheticInputEvent } from '../types/Utils'
|
|
2
|
+
import { ref } from 'vue'
|
|
49
3
|
import { Validatable } from '../composables/Validation'
|
|
50
4
|
import SInputBase from './SInputBase.vue'
|
|
51
5
|
|
|
52
|
-
type Size = 'mini' | 'small' | 'medium'
|
|
6
|
+
export type Size = 'mini' | 'small' | 'medium'
|
|
53
7
|
|
|
54
|
-
interface Value {
|
|
55
|
-
hour
|
|
56
|
-
minute
|
|
57
|
-
second
|
|
8
|
+
export interface Value {
|
|
9
|
+
hour: string | null
|
|
10
|
+
minute: string | null
|
|
11
|
+
second: string | null
|
|
58
12
|
}
|
|
59
13
|
|
|
60
|
-
type ValueType = 'hour' | 'minute' | 'second'
|
|
14
|
+
export type ValueType = 'hour' | 'minute' | 'second'
|
|
61
15
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
16
|
+
const props = defineProps<{
|
|
17
|
+
size?: Size
|
|
18
|
+
label?: string
|
|
19
|
+
note?: string
|
|
20
|
+
help?: string
|
|
21
|
+
noHour?: boolean
|
|
22
|
+
noMinute?: boolean
|
|
23
|
+
noSecond?: boolean
|
|
24
|
+
disabled?: boolean
|
|
25
|
+
hideError?: boolean
|
|
26
|
+
modelValue: Value
|
|
27
|
+
validation?: Validatable
|
|
28
|
+
}>()
|
|
67
29
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
placeholder: { type: String, default: null },
|
|
74
|
-
hour: { type: Boolean, default: true },
|
|
75
|
-
minute: { type: Boolean, default: true },
|
|
76
|
-
second: { type: Boolean, default: true },
|
|
77
|
-
disabled: { type: Boolean, default: false },
|
|
78
|
-
errorMessage: { type: Boolean, default: true },
|
|
79
|
-
modelValue: { type: Object as PropType<Value>, default: null },
|
|
80
|
-
validation: { type: Object as PropType<Validatable>, default: null }
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const emit = defineEmits(['update:modelValue'])
|
|
30
|
+
const emit = defineEmits<{
|
|
31
|
+
(e: 'update:modelValue', value: Value): void
|
|
32
|
+
}>()
|
|
33
|
+
|
|
34
|
+
const isFocused = ref(false)
|
|
84
35
|
|
|
85
36
|
const touched = {
|
|
86
37
|
hour: false,
|
|
@@ -88,53 +39,45 @@ const touched = {
|
|
|
88
39
|
second: false
|
|
89
40
|
}
|
|
90
41
|
|
|
91
|
-
function
|
|
92
|
-
|
|
42
|
+
function onFocus() {
|
|
43
|
+
isFocused.value = true
|
|
44
|
+
}
|
|
93
45
|
|
|
94
|
-
|
|
46
|
+
function blur() {
|
|
47
|
+
isFocused.value = false
|
|
95
48
|
}
|
|
96
49
|
|
|
97
|
-
function
|
|
98
|
-
|
|
50
|
+
function updateHour(e: FocusEvent): void {
|
|
51
|
+
update('hour', getValue((e.target as HTMLInputElement).value))
|
|
52
|
+
}
|
|
99
53
|
|
|
100
|
-
|
|
54
|
+
function updateMinute(e: FocusEvent): void {
|
|
55
|
+
update('minute', getValue((e.target as HTMLInputElement).value))
|
|
101
56
|
}
|
|
102
57
|
|
|
103
58
|
function updateSecond(e: FocusEvent): void {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
update('second', value ? value.padStart(2, '0') : undefined)
|
|
59
|
+
update('second', getValue((e.target as HTMLInputElement).value))
|
|
107
60
|
}
|
|
108
61
|
|
|
109
|
-
function update(type: ValueType, value
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
data.hour === undefined && data.minute === undefined && data.second === undefined
|
|
115
|
-
? emit('update:modelValue', null)
|
|
116
|
-
: emit('update:modelValue', data)
|
|
62
|
+
function update(type: ValueType, value: string | null) {
|
|
63
|
+
emit('update:modelValue', {
|
|
64
|
+
...props.modelValue,
|
|
65
|
+
[type]: value !== null ? value.padStart(2, '0') : null
|
|
66
|
+
})
|
|
117
67
|
|
|
118
68
|
emitTouch(type)
|
|
69
|
+
|
|
70
|
+
blur()
|
|
119
71
|
}
|
|
120
72
|
|
|
121
|
-
function getValue(value: string): string |
|
|
73
|
+
function getValue(value: string): string | null {
|
|
122
74
|
if (value === '') {
|
|
123
|
-
return
|
|
75
|
+
return null
|
|
124
76
|
}
|
|
125
77
|
|
|
126
78
|
const input = Number(value)
|
|
127
79
|
|
|
128
|
-
return isNaN(input) ?
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function setValue(data: Value, type: ValueType, value?: string): void {
|
|
132
|
-
if (value === undefined) {
|
|
133
|
-
delete data[type]
|
|
134
|
-
return
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
data[type] = value
|
|
80
|
+
return isNaN(input) ? null : String(input)
|
|
138
81
|
}
|
|
139
82
|
|
|
140
83
|
function emitTouch(type: ValueType): void {
|
|
@@ -153,7 +96,7 @@ function createRequiredTouched(): boolean[] {
|
|
|
153
96
|
const requiredTouched = [] as boolean[]
|
|
154
97
|
|
|
155
98
|
for (const key in touched) {
|
|
156
|
-
if ((props as any)[key]) {
|
|
99
|
+
if (!(props as any)[`no${key.charAt(0).toUpperCase() + key.slice(1)}`]) {
|
|
157
100
|
requiredTouched.push((touched as any)[key])
|
|
158
101
|
}
|
|
159
102
|
}
|
|
@@ -162,6 +105,54 @@ function createRequiredTouched(): boolean[] {
|
|
|
162
105
|
}
|
|
163
106
|
</script>
|
|
164
107
|
|
|
108
|
+
<template>
|
|
109
|
+
<SInputBase
|
|
110
|
+
class="SInputHMS"
|
|
111
|
+
:class="[size, { disabled }]"
|
|
112
|
+
:label="label"
|
|
113
|
+
:note="note"
|
|
114
|
+
:help="help"
|
|
115
|
+
:hide-error="hideError"
|
|
116
|
+
:validation="validation"
|
|
117
|
+
>
|
|
118
|
+
<div class="container" :class="{ focus: isFocused }">
|
|
119
|
+
<input
|
|
120
|
+
v-if="!noHour"
|
|
121
|
+
class="input hour"
|
|
122
|
+
:value="modelValue.hour"
|
|
123
|
+
placeholder="00"
|
|
124
|
+
:disabled="disabled"
|
|
125
|
+
@focus="onFocus"
|
|
126
|
+
@blur="updateHour"
|
|
127
|
+
>
|
|
128
|
+
<div v-if="!noHour && !noMinute" class="separator" />
|
|
129
|
+
<input
|
|
130
|
+
v-if="!noMinute"
|
|
131
|
+
class="input minute"
|
|
132
|
+
:value="modelValue.minute"
|
|
133
|
+
placeholder="00"
|
|
134
|
+
:disabled="disabled"
|
|
135
|
+
@focus="onFocus"
|
|
136
|
+
@blur="updateMinute"
|
|
137
|
+
>
|
|
138
|
+
<div v-if="!noMinute && !noSecond" class="separator" />
|
|
139
|
+
<input
|
|
140
|
+
v-if="!noSecond"
|
|
141
|
+
class="input second"
|
|
142
|
+
:value="modelValue.second"
|
|
143
|
+
placeholder="00"
|
|
144
|
+
:disabled="disabled"
|
|
145
|
+
@focus="onFocus"
|
|
146
|
+
@blur="updateSecond"
|
|
147
|
+
>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<template #before-help>
|
|
151
|
+
<slot name="before-help" />
|
|
152
|
+
</template>
|
|
153
|
+
</SInputBase>
|
|
154
|
+
</template>
|
|
155
|
+
|
|
165
156
|
<style lang="postcss" scoped>
|
|
166
157
|
.SInputHMS.mini {
|
|
167
158
|
.container {
|
|
@@ -253,22 +244,41 @@ function createRequiredTouched(): boolean[] {
|
|
|
253
244
|
|
|
254
245
|
.container {
|
|
255
246
|
display: inline-flex;
|
|
256
|
-
border: 1px solid var(--
|
|
257
|
-
border-radius:
|
|
258
|
-
|
|
247
|
+
border: 1px solid var(--c-divider);
|
|
248
|
+
border-radius: 6px;
|
|
249
|
+
background-color: var(--c-bg);
|
|
250
|
+
transition: border-color 0.25s;
|
|
259
251
|
|
|
260
252
|
&:hover {
|
|
261
|
-
border-color: var(--
|
|
253
|
+
border-color: var(--c-black);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
&.focus,
|
|
257
|
+
&:hover.focus {
|
|
258
|
+
border-color: var(--c-info);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.dark &:hover {
|
|
262
|
+
border-color: var(--c-gray);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.dark &.focus,
|
|
266
|
+
.dark &:hover.focus {
|
|
267
|
+
border-color: var(--c-info);
|
|
262
268
|
}
|
|
263
269
|
}
|
|
264
270
|
|
|
265
271
|
.input {
|
|
266
|
-
margin: 0;
|
|
267
272
|
background-color: transparent;
|
|
273
|
+
|
|
274
|
+
&::placeholder {
|
|
275
|
+
font-weight: 500;
|
|
276
|
+
color: var(--c-text-3);
|
|
277
|
+
}
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
.separator::before {
|
|
271
|
-
color: var(--c-text-
|
|
281
|
+
color: var(--c-text-3);
|
|
272
282
|
content: ":";
|
|
273
283
|
}
|
|
274
284
|
</style>
|
|
@@ -1,34 +1,45 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<SInputText
|
|
3
3
|
class="SInputNumber"
|
|
4
|
+
:name="name"
|
|
4
5
|
:size="size"
|
|
5
6
|
type="number"
|
|
6
7
|
:label="label"
|
|
7
8
|
:note="note"
|
|
8
9
|
:help="help"
|
|
10
|
+
:align="align"
|
|
9
11
|
:placeholder="placeholder"
|
|
10
12
|
:disabled="disabled"
|
|
11
13
|
:error-message="errorMessage"
|
|
12
|
-
:
|
|
14
|
+
:display-value="displayValue"
|
|
15
|
+
:model-value="String(modelValue)"
|
|
13
16
|
:validation="validation"
|
|
14
17
|
@update:model-value="emitUpdate"
|
|
15
|
-
|
|
18
|
+
>
|
|
19
|
+
<template #before-help>
|
|
20
|
+
<p v-if="helpFormat" class="help-text">
|
|
21
|
+
{{ valueWithSeparator }}
|
|
22
|
+
</p>
|
|
23
|
+
</template>
|
|
24
|
+
</SInputText>
|
|
16
25
|
</template>
|
|
17
26
|
|
|
18
27
|
<script setup lang="ts">
|
|
19
|
-
import { PropType } from 'vue'
|
|
28
|
+
import { computed, PropType } from 'vue'
|
|
29
|
+
import { Validatable } from '../composables/Validation'
|
|
20
30
|
import { isNullish } from '../support/Utils'
|
|
21
|
-
import {
|
|
22
|
-
import SInputText from './SInputText.vue'
|
|
31
|
+
import SInputText, { Size, Align } from './SInputText.vue'
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
defineProps({
|
|
33
|
+
const props = defineProps({
|
|
27
34
|
size: { type: String as PropType<Size>, default: 'small' },
|
|
35
|
+
name: { type: String, default: null },
|
|
28
36
|
label: { type: String, default: null },
|
|
29
37
|
note: { type: String, default: null },
|
|
30
38
|
help: { type: String, default: null },
|
|
31
39
|
placeholder: { type: String, default: null },
|
|
40
|
+
align: { type: String as PropType<Align>, default: null },
|
|
41
|
+
separator: { type: Boolean, default: false },
|
|
42
|
+
helpFormat: { type: Boolean, default: false },
|
|
32
43
|
disabled: { type: Boolean, default: false },
|
|
33
44
|
errorMessage: { type: Boolean, default: true },
|
|
34
45
|
modelValue: { type: Number as PropType<number | null>, default: null },
|
|
@@ -37,7 +48,25 @@ defineProps({
|
|
|
37
48
|
|
|
38
49
|
const emit = defineEmits(['update:modelValue'])
|
|
39
50
|
|
|
51
|
+
const valueWithSeparator = computed(() => {
|
|
52
|
+
if (isNullish(props.modelValue)) {
|
|
53
|
+
return '0'
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return props.modelValue >= 100000000000000000000
|
|
57
|
+
? 'The number is too big'
|
|
58
|
+
: props.modelValue.toLocaleString('en-US', { maximumSignificantDigits: 20 })
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const displayValue = computed(() => {
|
|
62
|
+
if (!props.separator || valueWithSeparator.value === '0') {
|
|
63
|
+
return null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return valueWithSeparator.value
|
|
67
|
+
})
|
|
68
|
+
|
|
40
69
|
function emitUpdate(value: string | null): void {
|
|
41
|
-
emit('update:modelValue', value ? Number(value): null)
|
|
70
|
+
emit('update:modelValue', value ? Number(value) : null)
|
|
42
71
|
}
|
|
43
72
|
</script>
|