@karyl-chan/ui 0.1.0 → 0.2.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karyl-chan/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared Vue UI primitives, composables, and design tokens used by karyl-chan's bot frontend and plugin webuis.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,13 +22,12 @@
|
|
|
22
22
|
"./use-drawer.css": "./src/composables/use-drawer.css",
|
|
23
23
|
"./use-popover.css": "./src/composables/use-popover.css"
|
|
24
24
|
},
|
|
25
|
-
"files": [
|
|
25
|
+
"files": [
|
|
26
|
+
"src"
|
|
27
|
+
],
|
|
26
28
|
"engines": {
|
|
27
29
|
"node": ">=22"
|
|
28
30
|
},
|
|
29
|
-
"scripts": {
|
|
30
|
-
"typecheck": "vue-tsc --noEmit"
|
|
31
|
-
},
|
|
32
31
|
"peerDependencies": {
|
|
33
32
|
"@iconify/vue": ">=5",
|
|
34
33
|
"@popperjs/core": ">=2",
|
|
@@ -38,7 +37,9 @@
|
|
|
38
37
|
"vue-router": ">=4"
|
|
39
38
|
},
|
|
40
39
|
"peerDependenciesMeta": {
|
|
41
|
-
"vue-router": {
|
|
40
|
+
"vue-router": {
|
|
41
|
+
"optional": true
|
|
42
|
+
}
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
45
|
"@iconify/vue": "^5.0.0",
|
|
@@ -54,5 +55,8 @@
|
|
|
54
55
|
"vue": "^3.5.13",
|
|
55
56
|
"vue-router": "^4.5.0",
|
|
56
57
|
"vue-tsc": "^2.2.0"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"typecheck": "vue-tsc --noEmit"
|
|
57
61
|
}
|
|
58
|
-
}
|
|
62
|
+
}
|
|
@@ -70,8 +70,8 @@ withDefaults(defineProps<{
|
|
|
70
70
|
/>
|
|
71
71
|
</slot>
|
|
72
72
|
|
|
73
|
-
<!-- 主要 label -->
|
|
74
|
-
<span class="app-btn-label"><slot /></span>
|
|
73
|
+
<!-- 主要 label — 略過時不渲染,避免 icon-only 按鈕產生多餘 gap -->
|
|
74
|
+
<span v-if="$slots.default" class="app-btn-label"><slot /></span>
|
|
75
75
|
|
|
76
76
|
<!-- 右側 slot -->
|
|
77
77
|
<slot name="trailing" />
|
|
@@ -19,6 +19,8 @@ const props = withDefaults(defineProps<{
|
|
|
19
19
|
maxlength?: number;
|
|
20
20
|
fullWidth?: boolean;
|
|
21
21
|
name?: string;
|
|
22
|
+
autofocus?: boolean;
|
|
23
|
+
required?: boolean;
|
|
22
24
|
}>(), {
|
|
23
25
|
label: '',
|
|
24
26
|
hint: '',
|
|
@@ -28,7 +30,9 @@ const props = withDefaults(defineProps<{
|
|
|
28
30
|
readonly: false,
|
|
29
31
|
rows: 3,
|
|
30
32
|
fullWidth: false,
|
|
31
|
-
name: ''
|
|
33
|
+
name: '',
|
|
34
|
+
autofocus: false,
|
|
35
|
+
required: false
|
|
32
36
|
});
|
|
33
37
|
|
|
34
38
|
const emit = defineEmits<{
|
|
@@ -64,6 +68,8 @@ const rootClass = computed(() => ({
|
|
|
64
68
|
:rows="rows"
|
|
65
69
|
:maxlength="maxlength"
|
|
66
70
|
:name="name || undefined"
|
|
71
|
+
:autofocus="autofocus"
|
|
72
|
+
:required="required"
|
|
67
73
|
@input="onInput"
|
|
68
74
|
@blur="emit('blur', $event)"
|
|
69
75
|
@focus="emit('focus', $event)"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script setup lang="ts" generic="V extends string | number | null">
|
|
1
|
+
<script setup lang="ts" generic="V extends string | number | null | undefined">
|
|
2
2
|
import { computed, useId } from 'vue';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -17,6 +17,8 @@ import { computed, useId } from 'vue';
|
|
|
17
17
|
|
|
18
18
|
const props = withDefaults(defineProps<{
|
|
19
19
|
modelValue: V;
|
|
20
|
+
/** v-model modifier bag (e.g. `.number`, `.trim`); Vue populates this. */
|
|
21
|
+
modelModifiers?: { number?: boolean; trim?: boolean; lazy?: boolean };
|
|
20
22
|
label?: string;
|
|
21
23
|
hint?: string;
|
|
22
24
|
error?: string;
|
|
@@ -70,7 +72,16 @@ const fieldId = useId();
|
|
|
70
72
|
|
|
71
73
|
function onInput(e: Event): void {
|
|
72
74
|
const target = e.target as HTMLInputElement;
|
|
73
|
-
|
|
75
|
+
let value: string | number = target.value;
|
|
76
|
+
if (props.modelModifiers?.trim) value = (value as string).trim();
|
|
77
|
+
if (props.modelModifiers?.number) {
|
|
78
|
+
const n = Number(value);
|
|
79
|
+
// Mirror Vue's `.number` semantics: only coerce when parseable;
|
|
80
|
+
// otherwise pass through the raw string so the input stays
|
|
81
|
+
// editable during typing (e.g. "1.").
|
|
82
|
+
if (!Number.isNaN(n) && value !== '') value = n;
|
|
83
|
+
}
|
|
84
|
+
emit('update:modelValue', value as V);
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
const rootClass = computed(() => ({
|