@brickflow/ui 0.0.54 → 0.0.55
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/dist/module.json +1 -1
- package/dist/runtime/components/Input/index.vue +18 -19
- package/dist/runtime/components/Input/size.demo.vue +5 -0
- package/dist/runtime/components/InputNumber/basic.demo.vue +12 -16
- package/dist/runtime/components/InputNumber/index.vue +77 -62
- package/dist/runtime/nuxt-components.d.ts +7 -0
- package/dist/runtime/utils/checkup.d.ts +32 -0
- package/dist/runtime/utils/checkup.js +67 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
disabled?: boolean
|
|
47
47
|
icon?: string
|
|
48
48
|
label?: string
|
|
49
|
-
onBlur?: (value:
|
|
50
|
-
|
|
49
|
+
onBlur?: (value: string, target: HTMLInputElement) => void
|
|
50
|
+
onChange?: (value: string, target: HTMLInputElement) => void
|
|
51
|
+
onFocus?: (value: string, target: HTMLInputElement | null) => void
|
|
51
52
|
onIconClick?: () => void
|
|
53
|
+
onInput?: (value: string, target: HTMLInputElement | null) => void
|
|
52
54
|
onTrailingIconClick?: () => void
|
|
53
|
-
onValueChange?: (value: null | string, target: HTMLInputElement) => void
|
|
54
|
-
onValueInput?: (value: null | string, target: HTMLInputElement | null) => void
|
|
55
55
|
placeholder?: string
|
|
56
56
|
readonly?: boolean
|
|
57
57
|
size?: InputSize
|
|
@@ -68,11 +68,11 @@
|
|
|
68
68
|
icon: undefined,
|
|
69
69
|
label: undefined,
|
|
70
70
|
onBlur: undefined,
|
|
71
|
+
onChange: undefined,
|
|
71
72
|
onFocus: undefined,
|
|
72
73
|
onIconClick: undefined,
|
|
74
|
+
onInput: undefined,
|
|
73
75
|
onTrailingIconClick: undefined,
|
|
74
|
-
onValueChange: undefined,
|
|
75
|
-
onValueInput: undefined,
|
|
76
76
|
placeholder: '',
|
|
77
77
|
readonly: false,
|
|
78
78
|
size: 'md',
|
|
@@ -83,8 +83,7 @@
|
|
|
83
83
|
},
|
|
84
84
|
)
|
|
85
85
|
|
|
86
|
-
const model = shallowRef
|
|
87
|
-
// const model = defineModel<null | number | string>({ default: '' })
|
|
86
|
+
const model = shallowRef('')
|
|
88
87
|
|
|
89
88
|
const attrs = useAttrs()
|
|
90
89
|
const slots = useSlots()
|
|
@@ -104,7 +103,7 @@
|
|
|
104
103
|
|
|
105
104
|
const fieldId = computed(() => String(attrs.id ?? generatedId))
|
|
106
105
|
const descriptionId = computed(() => `${fieldId.value}-description`)
|
|
107
|
-
const currentValue = computed(() => (props.value === undefined ? model.value : props.value))
|
|
106
|
+
const currentValue = computed(() => (props.value === undefined ? model.value : (props.value ?? '')))
|
|
108
107
|
const widthMeasureText = computed(() => currentValue.value || props.placeholder || ' ')
|
|
109
108
|
const isEmptyField = computed(() => {
|
|
110
109
|
return Boolean(currentValue.value)
|
|
@@ -177,23 +176,23 @@
|
|
|
177
176
|
props.onBlur?.(currentValue.value, event.target as HTMLInputElement)
|
|
178
177
|
}
|
|
179
178
|
|
|
179
|
+
function handleChange(event: Event): void {
|
|
180
|
+
const target = event.target as HTMLInputElement
|
|
181
|
+
props.onChange?.(target.value, target)
|
|
182
|
+
}
|
|
183
|
+
|
|
180
184
|
function handleFocus(event: FocusEvent): void {
|
|
181
185
|
hasFocus.value = true
|
|
182
186
|
props.onFocus?.(currentValue.value, event.target as HTMLInputElement)
|
|
183
187
|
}
|
|
184
188
|
|
|
185
|
-
function
|
|
186
|
-
const target = event.target as HTMLInputElement
|
|
187
|
-
props.onValueChange?.(target.value, target)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function onInput(event: Event): void {
|
|
189
|
+
function handleInput(event: Event): void {
|
|
191
190
|
setValue((event.target as HTMLInputElement).value)
|
|
192
191
|
}
|
|
193
192
|
|
|
194
|
-
function setValue(value:
|
|
193
|
+
function setValue(value: string): void {
|
|
195
194
|
model.value = value
|
|
196
|
-
props.
|
|
195
|
+
props.onInput?.(value, inputRef.value)
|
|
197
196
|
}
|
|
198
197
|
|
|
199
198
|
defineExpose({ clear, fieldId, focus, hasFocus, inputRef })
|
|
@@ -252,8 +251,8 @@
|
|
|
252
251
|
:aria-describedby="hasDescription ? descriptionId : undefined"
|
|
253
252
|
:class="fieldClasses"
|
|
254
253
|
:style="fieldStyle"
|
|
255
|
-
@input="
|
|
256
|
-
@change="
|
|
254
|
+
@input="handleInput"
|
|
255
|
+
@change="handleChange"
|
|
257
256
|
@focus="handleFocus"
|
|
258
257
|
@blur="handleBlur"
|
|
259
258
|
/>
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
7
|
<script lang="ts" setup>
|
|
8
|
+
import { ref } from 'vue'
|
|
9
|
+
|
|
8
10
|
import { firstIconName, uiConfig } from '#brickflow-ui'
|
|
9
11
|
|
|
10
12
|
import Button from '../Button/index.vue'
|
|
@@ -15,6 +17,7 @@
|
|
|
15
17
|
function copy(): void {
|
|
16
18
|
console.log('Click')
|
|
17
19
|
}
|
|
20
|
+
const text = ref('')
|
|
18
21
|
</script>
|
|
19
22
|
|
|
20
23
|
<template>
|
|
@@ -26,6 +29,7 @@
|
|
|
26
29
|
style="grid-template-columns: minmax(0, 24rem) max-content; grid-template-rows: repeat(3, auto)"
|
|
27
30
|
>
|
|
28
31
|
<Input
|
|
32
|
+
:value="text"
|
|
29
33
|
:size="size"
|
|
30
34
|
:icon="firstIconName"
|
|
31
35
|
:trailingIcon="firstIconName"
|
|
@@ -34,6 +38,7 @@
|
|
|
34
38
|
:label="`Size: ${size}`"
|
|
35
39
|
class="row-span-3 grid! grid-rows-subgrid"
|
|
36
40
|
@iconClick="copy"
|
|
41
|
+
@input="text = $event"
|
|
37
42
|
/>
|
|
38
43
|
<Button
|
|
39
44
|
:size="size"
|
|
@@ -9,29 +9,25 @@
|
|
|
9
9
|
|
|
10
10
|
import InputNumber from './index.vue'
|
|
11
11
|
|
|
12
|
-
const
|
|
13
|
-
|
|
12
|
+
const price = ref<number>(25)
|
|
13
|
+
function handleInput(event: number): void {
|
|
14
|
+
price.value = event
|
|
15
|
+
}
|
|
14
16
|
</script>
|
|
15
17
|
|
|
16
18
|
<template>
|
|
17
19
|
<div class="flex max-w-sm flex-col gap-4">
|
|
18
20
|
<InputNumber
|
|
19
|
-
|
|
20
|
-
label="Quantity"
|
|
21
|
-
description="Use ↑ and ↓ to change by one."
|
|
22
|
-
:min="0"
|
|
23
|
-
:max="20"
|
|
24
|
-
block
|
|
25
|
-
/>
|
|
26
|
-
<InputNumber
|
|
27
|
-
v-model="price"
|
|
21
|
+
:value="price"
|
|
28
22
|
label="Price"
|
|
29
|
-
description="
|
|
23
|
+
description="Min: 0 — Max: 200"
|
|
30
24
|
:min="0"
|
|
31
|
-
:max="
|
|
25
|
+
:max="200"
|
|
32
26
|
:step="5"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
@input="handleInput"
|
|
28
|
+
>
|
|
29
|
+
<template #leading><span class="text-green-400">$</span></template>
|
|
30
|
+
</InputNumber>
|
|
31
|
+
<p class="text-gray-500">Value: {{ price }}</p>
|
|
36
32
|
</div>
|
|
37
33
|
</template>
|
|
@@ -1,79 +1,95 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import {
|
|
1
|
+
<script setup lang="ts" generic="T extends boolean = false">
|
|
2
|
+
import { shallowRef, watch } from 'vue'
|
|
3
3
|
|
|
4
|
+
import { isEmpty } from '../../utils/checkup.js'
|
|
4
5
|
import Input from '../Input/index.vue'
|
|
5
6
|
|
|
6
7
|
defineOptions({ inheritAttrs: false })
|
|
7
8
|
|
|
8
9
|
const props = withDefaults(
|
|
9
10
|
defineProps<{
|
|
11
|
+
denominator?: number
|
|
12
|
+
description?: string
|
|
13
|
+
disabled?: boolean
|
|
14
|
+
label?: string
|
|
10
15
|
max?: number
|
|
11
16
|
min?: number
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
nullable?: T
|
|
18
|
+
onBlur?: (value: true extends NoInfer<T> ? null | number : number) => void
|
|
19
|
+
onFocus?: (value: true extends NoInfer<T> ? null | number : number) => void
|
|
20
|
+
onInput?: (value: true extends NoInfer<T> ? null | number : number) => void
|
|
21
|
+
onKeydown?: (event: KeyboardEvent) => void
|
|
14
22
|
step?: number
|
|
15
|
-
value
|
|
23
|
+
value: true extends NoInfer<T> ? null | number : number
|
|
16
24
|
}>(),
|
|
17
25
|
{
|
|
26
|
+
denominator: 0,
|
|
27
|
+
description: undefined,
|
|
28
|
+
disabled: false,
|
|
29
|
+
label: undefined,
|
|
18
30
|
max: undefined,
|
|
19
31
|
min: undefined,
|
|
32
|
+
nullable: undefined,
|
|
33
|
+
onBlur: undefined,
|
|
34
|
+
onFocus: undefined,
|
|
35
|
+
onInput: undefined,
|
|
36
|
+
onKeydown: undefined,
|
|
20
37
|
onValueChange: undefined,
|
|
21
|
-
onValueInput: undefined,
|
|
22
38
|
step: 1,
|
|
23
|
-
value: undefined,
|
|
24
39
|
},
|
|
25
40
|
)
|
|
26
41
|
|
|
27
|
-
const
|
|
28
|
-
const rawValue = ref<null | string>(null)
|
|
29
|
-
const currentValue = computed(() => (props.value === undefined ? model.value : props.value))
|
|
30
|
-
const inputValue = computed(
|
|
31
|
-
() => rawValue.value ?? (currentValue.value === null ? '' : String(currentValue.value)),
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
function clamp(value: number): number {
|
|
35
|
-
return Math.min(props.max ?? Infinity, Math.max(props.min ?? -Infinity, value))
|
|
36
|
-
}
|
|
42
|
+
const inputValue = shallowRef(prepareValue(props.value))
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
watch(
|
|
45
|
+
() => props.value,
|
|
46
|
+
() => {
|
|
47
|
+
inputValue.value = prepareValue(props.value)
|
|
48
|
+
},
|
|
49
|
+
)
|
|
41
50
|
|
|
42
|
-
function
|
|
43
|
-
if (
|
|
51
|
+
function handleBlur(value: string, target: HTMLInputElement): void {
|
|
52
|
+
if (!target) {
|
|
44
53
|
return
|
|
45
54
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
rawValue.value = String(value)
|
|
51
|
-
model.value = value
|
|
52
|
-
props.onValueInput?.(value, event.target as HTMLInputElement)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function handleValueChange(value: null | string, target: HTMLInputElement): void {
|
|
56
|
-
const parsed = toNumber(value)
|
|
57
|
-
const bounded = parsed === null ? null : clamp(parsed)
|
|
58
|
-
rawValue.value = null
|
|
59
|
-
model.value = bounded
|
|
60
|
-
props.onValueChange?.(bounded, target)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function handleValueInput(value: null | string, target: HTMLInputElement | null): void {
|
|
64
|
-
rawValue.value = value ?? ''
|
|
65
|
-
const number = toNumber(value)
|
|
66
|
-
model.value = number
|
|
67
|
-
props.onValueInput?.(number, target)
|
|
55
|
+
const nextValue = prepareValue(props.value)
|
|
56
|
+
target.value = nextValue
|
|
57
|
+
inputValue.value = nextValue
|
|
58
|
+
props.onBlur?.(props.value)
|
|
68
59
|
}
|
|
60
|
+
const allowedRegexp = /^-?\d*(?:\.\d*)?$/
|
|
61
|
+
const validNumberRegexp = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/
|
|
69
62
|
|
|
70
|
-
function
|
|
71
|
-
if (
|
|
72
|
-
return
|
|
63
|
+
function handleInput(rawValue: string, target: HTMLInputElement | null): void {
|
|
64
|
+
if (!target) {
|
|
65
|
+
return
|
|
73
66
|
}
|
|
67
|
+
const nextValue = rawValue.replace(/,/, '.')
|
|
68
|
+
target.value = nextValue
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
if (isEmpty(nextValue)) {
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
if (!allowedRegexp.test(nextValue)) {
|
|
74
|
+
target.value = inputValue.value
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
if (!validNumberRegexp.test(nextValue)) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
let nextValueNumber = Number(nextValue)
|
|
81
|
+
if (!isEmpty(props.min) && nextValueNumber < props.min) {
|
|
82
|
+
target.value = prepareValue(props.min)
|
|
83
|
+
nextValueNumber = props.min
|
|
84
|
+
}
|
|
85
|
+
if (!isEmpty(props.max) && nextValueNumber > props.max) {
|
|
86
|
+
target.value = prepareValue(props.max)
|
|
87
|
+
nextValueNumber = props.max
|
|
88
|
+
}
|
|
89
|
+
props.onInput?.(nextValueNumber)
|
|
90
|
+
}
|
|
91
|
+
function prepareValue(value: typeof props.value): string {
|
|
92
|
+
return value === null ? '' : String(value)
|
|
77
93
|
}
|
|
78
94
|
</script>
|
|
79
95
|
|
|
@@ -81,16 +97,15 @@
|
|
|
81
97
|
<Input
|
|
82
98
|
v-bind="{
|
|
83
99
|
...$attrs,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
onBlur: handleBlur,
|
|
87
|
-
onKeydown: handleKeydown,
|
|
100
|
+
// onBlur: handleBlur,
|
|
101
|
+
// onKeydown: handleKeydown,
|
|
88
102
|
}"
|
|
89
103
|
:value="inputValue"
|
|
104
|
+
:label="props.label"
|
|
105
|
+
:description="props.description"
|
|
90
106
|
type="decimal"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
:step="props.step"
|
|
107
|
+
@input="handleInput"
|
|
108
|
+
@blur="handleBlur"
|
|
94
109
|
>
|
|
95
110
|
<template
|
|
96
111
|
v-if="$slots.label"
|
|
@@ -99,16 +114,16 @@
|
|
|
99
114
|
<slot name="label" />
|
|
100
115
|
</template>
|
|
101
116
|
<template
|
|
102
|
-
v-if="$slots.
|
|
103
|
-
#
|
|
117
|
+
v-if="$slots.leading"
|
|
118
|
+
#leading
|
|
104
119
|
>
|
|
105
|
-
<slot name="
|
|
120
|
+
<slot name="leading" />
|
|
106
121
|
</template>
|
|
107
122
|
<template
|
|
108
|
-
v-if="$slots.
|
|
109
|
-
#
|
|
123
|
+
v-if="$slots.trailing"
|
|
124
|
+
#trailing
|
|
110
125
|
>
|
|
111
|
-
<slot name="
|
|
126
|
+
<slot name="trailing" />
|
|
112
127
|
</template>
|
|
113
128
|
<template
|
|
114
129
|
v-if="$slots.error"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @returns isEmpty('') => true
|
|
3
|
+
* @returns isEmpty([]) => true
|
|
4
|
+
* @returns isEmpty([1]) => false
|
|
5
|
+
* @returns isEmpty([null]) => false
|
|
6
|
+
* @returns isEmpty({}) => true
|
|
7
|
+
* @returns isEmpty({ key: '' }) => false
|
|
8
|
+
* @returns isEmpty(undefined) => true
|
|
9
|
+
* @returns isEmpty(null) => true
|
|
10
|
+
* @returns isEmpty(new Date()) => false
|
|
11
|
+
* @returns isEmpty(new Date('Invalid Date')) => false
|
|
12
|
+
* @returns isEmpty(true) => false
|
|
13
|
+
* @returns isEmpty(false) => false
|
|
14
|
+
* @returns isEmpty(0), 0, false
|
|
15
|
+
* @returns isEmpty(() => undefined) => false
|
|
16
|
+
* @returns isEmpty(Infinity) => false
|
|
17
|
+
* @returns isEmpty(-Infinity) => false
|
|
18
|
+
* @returns isEmpty(new Promise((resolve) => resolve(''))) => true
|
|
19
|
+
*/
|
|
20
|
+
export declare function isEmpty<T>(value: T): value is Extract<T, [] | null | undefined>;
|
|
21
|
+
export declare function isFloat(value: number): boolean;
|
|
22
|
+
export declare function isNumber(value: unknown): value is number;
|
|
23
|
+
export declare function isPromise<T>(value: T): value is T extends Promise<unknown> ? T : never;
|
|
24
|
+
export declare function isString(value: unknown): value is string;
|
|
25
|
+
export declare function isValidDate(date: Date | number | string): boolean;
|
|
26
|
+
export declare const isNonNullable: <T>(value: T) => value is NonNullable<T>;
|
|
27
|
+
export declare function isElement<T>(value: T): value is Extract<T, Element>;
|
|
28
|
+
export declare function isExternalLink(link: string): boolean;
|
|
29
|
+
export declare function isFormData(value?: FormData | Record<string, unknown> | unknown): value is FormData;
|
|
30
|
+
export declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
|
|
31
|
+
export declare function isTouchDevice(): boolean;
|
|
32
|
+
//# sourceMappingURL=checkup.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export function isEmpty(value) {
|
|
2
|
+
if (typeof value === "boolean" || typeof value === "function") {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
if (typeof value === "undefined" || value === null || typeof value === "string" && value.length === 0) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (isDate(value)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return Object.keys(value).length === 0;
|
|
18
|
+
}
|
|
19
|
+
export function isFloat(value) {
|
|
20
|
+
return Number(value) === value && value % 1 !== 0;
|
|
21
|
+
}
|
|
22
|
+
export function isNumber(value) {
|
|
23
|
+
return typeof value === "number";
|
|
24
|
+
}
|
|
25
|
+
export function isPromise(value) {
|
|
26
|
+
return Boolean(value) && (typeof value === "object" || typeof value === "function") && typeof value?.then === "function";
|
|
27
|
+
}
|
|
28
|
+
export function isString(value) {
|
|
29
|
+
return typeof value === "string";
|
|
30
|
+
}
|
|
31
|
+
export function isValidDate(date) {
|
|
32
|
+
if (typeof date === "string") {
|
|
33
|
+
return Boolean(Date.parse(date));
|
|
34
|
+
}
|
|
35
|
+
if (isNaN(date)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return typeof date === "number" || date instanceof Date;
|
|
39
|
+
}
|
|
40
|
+
function isDate(value) {
|
|
41
|
+
if (Object.prototype.toString.call(value) === "[object Date]") {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
export const isNonNullable = (value) => {
|
|
47
|
+
return value !== void 0 && value !== null;
|
|
48
|
+
};
|
|
49
|
+
export function isElement(value) {
|
|
50
|
+
return value instanceof Element;
|
|
51
|
+
}
|
|
52
|
+
export function isExternalLink(link) {
|
|
53
|
+
const EXTERNAL_LINK_REGEX = /^(?:https?:\/\/|mailto:|tel:)/;
|
|
54
|
+
return EXTERNAL_LINK_REGEX.test(link);
|
|
55
|
+
}
|
|
56
|
+
export function isFormData(value) {
|
|
57
|
+
if (!value) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return typeof value === "object" && typeof value.append === "function" && typeof value.has === "function";
|
|
61
|
+
}
|
|
62
|
+
export function isFunction(value) {
|
|
63
|
+
return typeof value === "function";
|
|
64
|
+
}
|
|
65
|
+
export function isTouchDevice() {
|
|
66
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.maxTouchPoints > 0;
|
|
67
|
+
}
|