@sakoa/ui 0.1.1 → 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/dist/cli/index.js +8 -0
- package/dist/components/ui/SAlert.d.ts +3 -2
- package/dist/components/ui/SButton.d.ts +6 -5
- package/dist/components/ui/SCheckbox.d.ts +4 -3
- package/dist/components/ui/SDatePicker.d.ts +3 -3
- package/dist/components/ui/SGlassButton.d.ts +6 -5
- package/dist/components/ui/SInput.d.ts +6 -5
- package/dist/components/ui/SSelect.d.ts +5 -4
- package/dist/components/ui/SSwitch.d.ts +6 -5
- package/dist/components/ui/accordion/SAccordionItem.d.ts +7 -6
- package/dist/components/ui/card/SCardHeader.d.ts +4 -3
- package/dist/components/ui/dropdown/SDropdownGroup.d.ts +3 -2
- package/dist/components/ui/dropdown/SDropdownItem.d.ts +7 -6
- package/dist/components/ui/option/SOption.d.ts +3 -2
- package/dist/components/ui/otp/SOTP.d.ts +1 -1
- package/dist/components/ui/pagination/SPagination.d.ts +1 -1
- package/dist/components/ui/progress/SProgress.d.ts +1 -1
- package/dist/components/ui/progress/SProgressRange.d.ts +1 -1
- package/dist/components/ui/radio/SRadio.d.ts +4 -3
- package/dist/components/ui/radio/SRadioGroup.d.ts +1 -1
- package/dist/components/ui/stepper/SStepper.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/lib/icon.d.ts +10 -0
- package/dist/saka-ui.css +1 -1
- package/dist/saka-ui.js +5355 -5252
- package/dist/saka-ui.umd.cjs +11 -11
- package/dist/views/docs/CLIView.d.ts +2 -0
- package/dist/views/docs/GettingStartedView.d.ts +2 -0
- package/dist/views/docs/IconsGuideView.d.ts +2 -0
- package/dist/views/docs/UseClickOutsideView.d.ts +9 -9
- package/dist/views/docs/UseHotkeyView.d.ts +10 -10
- package/dist/views/ui/OTPView.d.ts +3 -3
- package/package.json +1 -1
- package/registry/source/components/ui/SAlert.vue +9 -5
- package/registry/source/components/ui/SButton.vue +12 -10
- package/registry/source/components/ui/SCheckbox.vue +4 -2
- package/registry/source/components/ui/SGlassButton.vue +11 -10
- package/registry/source/components/ui/SInput.vue +12 -4
- package/registry/source/components/ui/SSelect.vue +30 -8
- package/registry/source/components/ui/SSwitch.vue +7 -4
- package/registry/source/components/ui/accordion/SAccordionItem.vue +19 -5
- package/registry/source/components/ui/card/SCardHeader.vue +8 -5
- package/registry/source/components/ui/drawer/SDrawerClose.vue +4 -2
- package/registry/source/components/ui/dropdown/SDropdown.vue +11 -7
- package/registry/source/components/ui/dropdown/SDropdownGroup.vue +4 -2
- package/registry/source/components/ui/dropdown/SDropdownItem.vue +10 -7
- package/registry/source/components/ui/option/SOption.vue +9 -2
- package/registry/source/components/ui/radio/SRadio.vue +11 -3
- package/registry/source/components/ui/tabs/STabs.vue +5 -2
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
2
|
+
export default _default;
|
|
@@ -12,8 +12,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
12
12
|
readonly preserveSize?: boolean | undefined;
|
|
13
13
|
readonly block?: boolean | undefined;
|
|
14
14
|
readonly rounded?: "none" | "sm" | "md" | "lg" | "full" | undefined;
|
|
15
|
-
readonly iconLeft?:
|
|
16
|
-
readonly iconRight?:
|
|
15
|
+
readonly iconLeft?: import('../../index').IconProp | undefined;
|
|
16
|
+
readonly iconRight?: import('../../index').IconProp | undefined;
|
|
17
17
|
readonly iconOnly?: boolean | undefined;
|
|
18
18
|
readonly tag?: string | undefined;
|
|
19
19
|
readonly href?: string | undefined;
|
|
@@ -45,8 +45,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
45
45
|
}>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
46
46
|
click: (event: MouseEvent) => any;
|
|
47
47
|
}, string, {
|
|
48
|
-
type: "button" | "submit" | "reset";
|
|
49
48
|
size: "xs" | "small" | "medium" | "large" | "xl";
|
|
49
|
+
type: "button" | "submit" | "reset";
|
|
50
50
|
disabled: boolean;
|
|
51
51
|
color: string;
|
|
52
52
|
variant: "filled" | "outlined" | "light" | "ghost" | "link";
|
|
@@ -55,8 +55,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
55
55
|
rounded: "none" | "sm" | "md" | "lg" | "full";
|
|
56
56
|
preserveSize: boolean;
|
|
57
57
|
block: boolean;
|
|
58
|
-
iconLeft:
|
|
59
|
-
iconRight:
|
|
58
|
+
iconLeft: import('../../index').IconProp;
|
|
59
|
+
iconRight: import('../../index').IconProp;
|
|
60
60
|
iconOnly: boolean;
|
|
61
61
|
tag: string;
|
|
62
62
|
href: string;
|
|
@@ -86,8 +86,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
86
86
|
$nextTick: typeof import('vue').nextTick;
|
|
87
87
|
$watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
|
|
88
88
|
} & Readonly<{
|
|
89
|
-
type: "button" | "submit" | "reset";
|
|
90
89
|
size: "xs" | "small" | "medium" | "large" | "xl";
|
|
90
|
+
type: "button" | "submit" | "reset";
|
|
91
91
|
disabled: boolean;
|
|
92
92
|
color: string;
|
|
93
93
|
variant: "filled" | "outlined" | "light" | "ghost" | "link";
|
|
@@ -96,8 +96,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
96
96
|
rounded: "none" | "sm" | "md" | "lg" | "full";
|
|
97
97
|
preserveSize: boolean;
|
|
98
98
|
block: boolean;
|
|
99
|
-
iconLeft:
|
|
100
|
-
iconRight:
|
|
99
|
+
iconLeft: import('../../index').IconProp;
|
|
100
|
+
iconRight: import('../../index').IconProp;
|
|
101
101
|
iconOnly: boolean;
|
|
102
102
|
tag: string;
|
|
103
103
|
href: string;
|
|
@@ -108,7 +108,7 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
108
108
|
iconClass: string;
|
|
109
109
|
}> & Omit<Readonly<import('../../components/ui/SButton').Props> & Readonly<{
|
|
110
110
|
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
111
|
-
}>, "
|
|
111
|
+
}>, "size" | "type" | "disabled" | "color" | "variant" | "contentClass" | "loading" | "rounded" | "preserveSize" | "block" | "iconLeft" | "iconRight" | "iconOnly" | "tag" | "href" | "to" | "ripple" | "animationType" | "animateInactive" | "iconClass"> & import('vue').ShallowUnwrapRef<{}> & {} & import('vue').ComponentCustomProperties & {} & {
|
|
112
112
|
$slots: {
|
|
113
113
|
'icon-left'?(_: {}): any;
|
|
114
114
|
default?(_: {}): any;
|
|
@@ -13,8 +13,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
13
13
|
readonly placeholder?: string | undefined;
|
|
14
14
|
readonly labelPlacement?: "top" | "top-left" | "top-center" | "top-right" | "bottom" | "left" | "right" | "floating" | "inside" | undefined;
|
|
15
15
|
readonly labelAnimation?: "morph" | "slide" | "fade" | "none" | undefined;
|
|
16
|
-
readonly iconLeft?:
|
|
17
|
-
readonly iconRight?:
|
|
16
|
+
readonly iconLeft?: import('../../index').IconProp | undefined;
|
|
17
|
+
readonly iconRight?: import('../../index').IconProp | undefined;
|
|
18
18
|
readonly iconColor?: string | undefined;
|
|
19
19
|
readonly disabled?: boolean | undefined;
|
|
20
20
|
readonly readonly?: boolean | undefined;
|
|
@@ -54,8 +54,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
54
54
|
readonly inputClass?: string | undefined;
|
|
55
55
|
readonly labelClass?: string | undefined;
|
|
56
56
|
readonly wrapperClass?: string | undefined;
|
|
57
|
-
readonly "onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
58
57
|
readonly onClear?: (() => any) | undefined;
|
|
58
|
+
readonly "onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
59
59
|
readonly onInput?: ((event: Event) => any) | undefined;
|
|
60
60
|
readonly onChange?: ((value: string | number, event: Event) => any) | undefined;
|
|
61
61
|
readonly onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
@@ -80,11 +80,11 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
80
80
|
$root: import('vue').ComponentPublicInstance | null;
|
|
81
81
|
$parent: import('vue').ComponentPublicInstance | null;
|
|
82
82
|
$host: Element | null;
|
|
83
|
-
$emit: ((event: "
|
|
83
|
+
$emit: ((event: "clear") => void) & ((event: "update:modelValue", value: string | number) => void) & ((event: "input", event: Event) => void) & ((event: "change", value: string | number, event: Event) => void) & ((event: "blur", event: FocusEvent) => void) & ((event: "focus", event: FocusEvent) => void) & ((event: "update:error", error: string | null) => void) & ((event: "enter", event: KeyboardEvent) => void) & ((event: "validate", isValid: boolean, error: string | null) => void) & ((event: "select-suggestion", suggestion: string) => void);
|
|
84
84
|
$el: any;
|
|
85
85
|
$options: import('vue').ComponentOptionsBase<Readonly<import('../../components/ui/SInput').Props> & Readonly<{
|
|
86
|
-
"onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
87
86
|
onClear?: (() => any) | undefined;
|
|
87
|
+
"onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
88
88
|
onInput?: ((event: Event) => any) | undefined;
|
|
89
89
|
onChange?: ((value: string | number, event: Event) => any) | undefined;
|
|
90
90
|
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
@@ -99,8 +99,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
99
99
|
validate: () => Promise<void>;
|
|
100
100
|
inputElement: import('vue').Ref<HTMLInputElement | HTMLTextAreaElement | null, HTMLInputElement | HTMLTextAreaElement | null>;
|
|
101
101
|
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
102
|
-
"update:modelValue": (value: string | number) => any;
|
|
103
102
|
clear: () => any;
|
|
103
|
+
"update:modelValue": (value: string | number) => any;
|
|
104
104
|
input: (event: Event) => any;
|
|
105
105
|
change: (value: string | number, event: Event) => any;
|
|
106
106
|
blur: (event: FocusEvent) => any;
|
|
@@ -110,9 +110,9 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
110
110
|
validate: (isValid: boolean, error: string | null) => any;
|
|
111
111
|
"select-suggestion": (suggestion: string) => any;
|
|
112
112
|
}, string, {
|
|
113
|
+
size: "small" | "medium" | "large";
|
|
113
114
|
modelValue: string | number;
|
|
114
115
|
type: "text" | "email" | "password" | "number" | "tel" | "url" | "search" | "textarea";
|
|
115
|
-
size: "small" | "medium" | "large";
|
|
116
116
|
disabled: boolean;
|
|
117
117
|
required: boolean;
|
|
118
118
|
color: string;
|
|
@@ -155,9 +155,9 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
155
155
|
$nextTick: typeof import('vue').nextTick;
|
|
156
156
|
$watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
|
|
157
157
|
} & Readonly<{
|
|
158
|
+
size: "small" | "medium" | "large";
|
|
158
159
|
modelValue: string | number;
|
|
159
160
|
type: "text" | "email" | "password" | "number" | "tel" | "url" | "search" | "textarea";
|
|
160
|
-
size: "small" | "medium" | "large";
|
|
161
161
|
disabled: boolean;
|
|
162
162
|
required: boolean;
|
|
163
163
|
color: string;
|
|
@@ -180,8 +180,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
180
180
|
allowOnly: "digits" | "letters" | "alphanumeric" | RegExp | ((char: string) => boolean);
|
|
181
181
|
decimalPlaces: number;
|
|
182
182
|
}> & Omit<Readonly<import('../../components/ui/SInput').Props> & Readonly<{
|
|
183
|
-
"onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
184
183
|
onClear?: (() => any) | undefined;
|
|
184
|
+
"onUpdate:modelValue"?: ((value: string | number) => any) | undefined;
|
|
185
185
|
onInput?: ((event: Event) => any) | undefined;
|
|
186
186
|
onChange?: ((value: string | number, event: Event) => any) | undefined;
|
|
187
187
|
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
@@ -190,7 +190,7 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
190
190
|
onEnter?: ((event: KeyboardEvent) => any) | undefined;
|
|
191
191
|
onValidate?: ((isValid: boolean, error: string | null) => any) | undefined;
|
|
192
192
|
"onSelect-suggestion"?: ((suggestion: string) => any) | undefined;
|
|
193
|
-
}>, "blur" | "focus" | "validate" | "inputElement" | ("
|
|
193
|
+
}>, "blur" | "focus" | "validate" | "inputElement" | ("size" | "modelValue" | "type" | "disabled" | "required" | "color" | "variant" | "loading" | "rounded" | "resize" | "clearable" | "labelPlacement" | "readonly" | "labelAnimation" | "validateOn" | "autofocus" | "spellcheck" | "showPasswordToggle" | "counter" | "rows" | "suggestions" | "showSuggestionsOnFocus" | "allowOnly" | "decimalPlaces")> & import('vue').ShallowUnwrapRef<{
|
|
194
194
|
focus: () => void;
|
|
195
195
|
blur: () => void;
|
|
196
196
|
validate: () => Promise<void>;
|
|
@@ -98,8 +98,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
98
98
|
complete: (value: string) => any;
|
|
99
99
|
resend: () => any;
|
|
100
100
|
}, string, {
|
|
101
|
-
modelValue: string;
|
|
102
101
|
size: import('../../components/ui/otp').SOTPSize;
|
|
102
|
+
modelValue: string;
|
|
103
103
|
disabled: boolean;
|
|
104
104
|
mode: import('../../components/ui/otp').SOTPMode;
|
|
105
105
|
animation: import('../../components/ui/otp').SOTPAnimation;
|
|
@@ -148,8 +148,8 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
148
148
|
$nextTick: typeof import('vue').nextTick;
|
|
149
149
|
$watch<T extends string | ((...args: any) => any)>(source: T, cb: T extends (...args: any) => infer R ? (...args: [R, R, import('@vue/reactivity').OnCleanup]) => any : (...args: [any, any, import('@vue/reactivity').OnCleanup]) => any, options?: import('vue').WatchOptions): import('vue').WatchStopHandle;
|
|
150
150
|
} & Readonly<{
|
|
151
|
-
modelValue: string;
|
|
152
151
|
size: import('../../components/ui/otp').SOTPSize;
|
|
152
|
+
modelValue: string;
|
|
153
153
|
disabled: boolean;
|
|
154
154
|
mode: import('../../components/ui/otp').SOTPMode;
|
|
155
155
|
animation: import('../../components/ui/otp').SOTPAnimation;
|
|
@@ -188,7 +188,7 @@ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import
|
|
|
188
188
|
onSuccess?: (() => any) | undefined;
|
|
189
189
|
onComplete?: ((value: string) => any) | undefined;
|
|
190
190
|
onResend?: (() => any) | undefined;
|
|
191
|
-
}>, "clear" | "blur" | "focus" | "focusInput" | "triggerError" | "getValue" | "isComplete" | ("
|
|
191
|
+
}>, "clear" | "blur" | "focus" | "focusInput" | "triggerError" | "getValue" | "isComplete" | ("size" | "modelValue" | "disabled" | "mode" | "animation" | "color" | "variant" | "loading" | "rounded" | "separator" | "gap" | "readonly" | "maxlength" | "autoFocus" | "entryAnimation" | "inputAnimation" | "successAnimation" | "errorAnimation" | "morphText" | "morphDuration" | "showPlaceholder" | "placeholderChar" | "maskChar" | "autoSubmit" | "masked" | "clearOnError" | "allowPaste" | "countdown" | "resendText")> & import('vue').ShallowUnwrapRef<{
|
|
192
192
|
clear: () => void;
|
|
193
193
|
focusInput: (index: number) => void;
|
|
194
194
|
focus: () => void;
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
|
|
3
3
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
4
|
import { cn } from '../../lib/utils'
|
|
5
|
+
import { type IconProp, isIconComponent } from '../../lib/icon'
|
|
5
6
|
|
|
6
7
|
defineOptions({ inheritAttrs: false })
|
|
7
8
|
|
|
@@ -66,7 +67,7 @@ export interface Props {
|
|
|
66
67
|
size?: 'small' | 'medium' | 'large'
|
|
67
68
|
title?: string
|
|
68
69
|
description?: string
|
|
69
|
-
icon?:
|
|
70
|
+
icon?: IconProp | boolean
|
|
70
71
|
closable?: boolean
|
|
71
72
|
autoDismiss?: boolean
|
|
72
73
|
duration?: number
|
|
@@ -125,8 +126,10 @@ const defaultIcons = computed(() => ({
|
|
|
125
126
|
|
|
126
127
|
const displayIcon = computed(() => {
|
|
127
128
|
if (props.icon === false) return null
|
|
128
|
-
if (
|
|
129
|
-
|
|
129
|
+
if (props.icon === true || props.icon === undefined) {
|
|
130
|
+
return defaultIcons.value[props.variant as keyof typeof defaultIcons.value] || 'information'
|
|
131
|
+
}
|
|
132
|
+
return props.icon // could be string or Component
|
|
130
133
|
})
|
|
131
134
|
|
|
132
135
|
const sizes = computed(() => sizeConfig[props.size])
|
|
@@ -302,9 +305,10 @@ defineExpose({
|
|
|
302
305
|
>
|
|
303
306
|
<div class="flex items-start" :class="sizes.gap">
|
|
304
307
|
<!-- Icon -->
|
|
305
|
-
<div v-if="displayIcon" class="shrink-0" :class="[variantIconColors[variant], iconClass]">
|
|
308
|
+
<div v-if="displayIcon != null" class="shrink-0" :class="[variantIconColors[variant], iconClass]">
|
|
306
309
|
<slot name="icon">
|
|
307
|
-
<
|
|
310
|
+
<component v-if="isIconComponent(displayIcon)" :is="displayIcon" :class="[sizes.iconSize]" />
|
|
311
|
+
<span v-else class="mdi" :class="[`mdi-${displayIcon}`, sizes.iconSize]" />
|
|
308
312
|
</slot>
|
|
309
313
|
</div>
|
|
310
314
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
|
+
import type { IconProp } from '../../lib/icon'
|
|
3
4
|
|
|
4
5
|
export const buttonVariants = cva(
|
|
5
6
|
'relative inline-flex items-center justify-center font-medium transition-all duration-200 ease-out overflow-hidden select-none focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 border-[1.5px] border-transparent',
|
|
@@ -46,8 +47,8 @@ export interface Props {
|
|
|
46
47
|
preserveSize?: boolean
|
|
47
48
|
block?: boolean
|
|
48
49
|
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'full'
|
|
49
|
-
iconLeft?:
|
|
50
|
-
iconRight?:
|
|
50
|
+
iconLeft?: IconProp
|
|
51
|
+
iconRight?: IconProp
|
|
51
52
|
iconOnly?: boolean
|
|
52
53
|
tag?: string
|
|
53
54
|
href?: string
|
|
@@ -64,6 +65,7 @@ export interface Props {
|
|
|
64
65
|
<script setup lang="ts">
|
|
65
66
|
import { computed, ref, useSlots, type CSSProperties } from 'vue'
|
|
66
67
|
import { cn } from '../../lib/utils'
|
|
68
|
+
import { isIconComponent } from '../../lib/icon'
|
|
67
69
|
|
|
68
70
|
const iconOnlySizes: Record<string, string> = {
|
|
69
71
|
xs: 'w-6 h-6 text-xs',
|
|
@@ -257,10 +259,10 @@ const componentBindings = computed(() => {
|
|
|
257
259
|
>
|
|
258
260
|
<template v-if="!loading || preserveSize">
|
|
259
261
|
<slot name="icon-left">
|
|
260
|
-
<
|
|
261
|
-
v-if="iconLeft"
|
|
262
|
-
:class="['mdi', `mdi-${iconLeft}`, iconSizes, iconClass]"
|
|
263
|
-
|
|
262
|
+
<template v-if="iconLeft">
|
|
263
|
+
<component v-if="isIconComponent(iconLeft)" :is="iconLeft" :class="[iconSizes, iconClass]" />
|
|
264
|
+
<span v-else :class="['mdi', `mdi-${iconLeft}`, iconSizes, iconClass]" />
|
|
265
|
+
</template>
|
|
264
266
|
</slot>
|
|
265
267
|
</template>
|
|
266
268
|
|
|
@@ -274,10 +276,10 @@ const componentBindings = computed(() => {
|
|
|
274
276
|
|
|
275
277
|
<template v-if="!loading || preserveSize">
|
|
276
278
|
<slot name="icon-right">
|
|
277
|
-
<
|
|
278
|
-
v-if="iconRight"
|
|
279
|
-
:class="['mdi', `mdi-${iconRight}`, iconSizes, iconClass]"
|
|
280
|
-
|
|
279
|
+
<template v-if="iconRight">
|
|
280
|
+
<component v-if="isIconComponent(iconRight)" :is="iconRight" :class="[iconSizes, iconClass]" />
|
|
281
|
+
<span v-else :class="['mdi', `mdi-${iconRight}`, iconSizes, iconClass]" />
|
|
282
|
+
</template>
|
|
281
283
|
</slot>
|
|
282
284
|
</template>
|
|
283
285
|
</span>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { computed, ref, type CSSProperties } from 'vue'
|
|
3
3
|
import { cva, type VariantProps } from 'class-variance-authority'
|
|
4
4
|
import { cn } from '../../lib/utils'
|
|
5
|
+
import { type IconProp, isIconComponent } from '../../lib/icon'
|
|
5
6
|
|
|
6
7
|
defineOptions({ inheritAttrs: false })
|
|
7
8
|
|
|
@@ -34,7 +35,7 @@ export interface Props {
|
|
|
34
35
|
label?: string
|
|
35
36
|
labelPosition?: 'left' | 'right'
|
|
36
37
|
rounded?: boolean
|
|
37
|
-
icon?:
|
|
38
|
+
icon?: IconProp
|
|
38
39
|
required?: boolean
|
|
39
40
|
name?: string
|
|
40
41
|
error?: string
|
|
@@ -246,7 +247,8 @@ const rounded = computed(() => props.rounded)
|
|
|
246
247
|
:class="cn('absolute inset-0 flex items-center justify-center', color ? 'text-white' : 'text-primary-foreground', sizeConfig.icon)"
|
|
247
248
|
>
|
|
248
249
|
<slot name="icon">
|
|
249
|
-
<
|
|
250
|
+
<component v-if="isIconComponent(displayIcon)" :is="displayIcon" />
|
|
251
|
+
<span v-else :class="['mdi', `mdi-${displayIcon}`]" />
|
|
250
252
|
</slot>
|
|
251
253
|
</span>
|
|
252
254
|
</Transition>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { computed, ref, useSlots, onMounted, onUnmounted } from 'vue'
|
|
3
3
|
import { useTheme } from '../../composables/useTheme'
|
|
4
4
|
import { cn } from '../../lib/utils'
|
|
5
|
+
import { type IconProp, isIconComponent } from '../../lib/icon'
|
|
5
6
|
|
|
6
7
|
defineOptions({ inheritAttrs: false })
|
|
7
8
|
|
|
@@ -13,8 +14,8 @@ export interface Props {
|
|
|
13
14
|
preserveSize?: boolean
|
|
14
15
|
block?: boolean
|
|
15
16
|
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'full'
|
|
16
|
-
iconLeft?:
|
|
17
|
-
iconRight?:
|
|
17
|
+
iconLeft?: IconProp
|
|
18
|
+
iconRight?: IconProp
|
|
18
19
|
iconOnly?: boolean
|
|
19
20
|
tag?: string
|
|
20
21
|
href?: string
|
|
@@ -356,10 +357,10 @@ const componentBindings = computed(() => {
|
|
|
356
357
|
<!-- Left icon -->
|
|
357
358
|
<template v-if="!loading || preserveSize">
|
|
358
359
|
<slot name="icon-left">
|
|
359
|
-
<
|
|
360
|
-
v-if="iconLeft"
|
|
361
|
-
:class="['mdi', `mdi-${iconLeft}`, iconSizes]"
|
|
362
|
-
|
|
360
|
+
<template v-if="iconLeft">
|
|
361
|
+
<component v-if="isIconComponent(iconLeft)" :is="iconLeft" :class="[iconSizes]" />
|
|
362
|
+
<span v-else :class="['mdi', `mdi-${iconLeft}`, iconSizes]" />
|
|
363
|
+
</template>
|
|
363
364
|
</slot>
|
|
364
365
|
</template>
|
|
365
366
|
|
|
@@ -376,10 +377,10 @@ const componentBindings = computed(() => {
|
|
|
376
377
|
<!-- Right icon -->
|
|
377
378
|
<template v-if="!loading || preserveSize">
|
|
378
379
|
<slot name="icon-right">
|
|
379
|
-
<
|
|
380
|
-
v-if="iconRight"
|
|
381
|
-
:class="['mdi', `mdi-${iconRight}`, iconSizes]"
|
|
382
|
-
|
|
380
|
+
<template v-if="iconRight">
|
|
381
|
+
<component v-if="isIconComponent(iconRight)" :is="iconRight" :class="[iconSizes]" />
|
|
382
|
+
<span v-else :class="['mdi', `mdi-${iconRight}`, iconSizes]" />
|
|
383
|
+
</template>
|
|
383
384
|
</slot>
|
|
384
385
|
</template>
|
|
385
386
|
</span>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch, nextTick, onMounted, type CSSProperties } from 'vue'
|
|
3
3
|
import { cn } from '../../lib/utils'
|
|
4
|
+
import { type IconProp, isIconComponent } from '../../lib/icon'
|
|
4
5
|
|
|
5
6
|
defineOptions({ inheritAttrs: false })
|
|
6
7
|
|
|
@@ -23,8 +24,8 @@ export interface Props {
|
|
|
23
24
|
labelAnimation?: 'morph' | 'slide' | 'fade' | 'none'
|
|
24
25
|
|
|
25
26
|
// Icons
|
|
26
|
-
iconLeft?:
|
|
27
|
-
iconRight?:
|
|
27
|
+
iconLeft?: IconProp
|
|
28
|
+
iconRight?: IconProp
|
|
28
29
|
iconColor?: string
|
|
29
30
|
|
|
30
31
|
// States
|
|
@@ -743,7 +744,8 @@ watch(() => props.error, (newError) => {
|
|
|
743
744
|
:style="iconColor ? { color: iconColor } : iconFocusStyle"
|
|
744
745
|
>
|
|
745
746
|
<slot name="prefix">
|
|
746
|
-
<
|
|
747
|
+
<component v-if="iconLeft && isIconComponent(iconLeft)" :is="iconLeft" />
|
|
748
|
+
<span v-else-if="iconLeft" :class="['mdi', `mdi-${iconLeft}`]" />
|
|
747
749
|
<span v-if="prefix" class="text-muted-foreground text-sm">{{ prefix }}</span>
|
|
748
750
|
</slot>
|
|
749
751
|
</span>
|
|
@@ -905,8 +907,14 @@ watch(() => props.error, (newError) => {
|
|
|
905
907
|
|
|
906
908
|
<!-- Custom suffix -->
|
|
907
909
|
<slot name="suffix">
|
|
910
|
+
<component
|
|
911
|
+
v-if="iconRight && isIconComponent(iconRight)"
|
|
912
|
+
:is="iconRight"
|
|
913
|
+
:class="[iconColorClass]"
|
|
914
|
+
:style="iconColor ? { color: iconColor } : iconFocusStyle"
|
|
915
|
+
/>
|
|
908
916
|
<span
|
|
909
|
-
v-if="iconRight"
|
|
917
|
+
v-else-if="iconRight"
|
|
910
918
|
:class="['mdi', `mdi-${iconRight}`, iconColorClass]"
|
|
911
919
|
:style="iconColor ? { color: iconColor } : iconFocusStyle"
|
|
912
920
|
/>
|
|
@@ -3,12 +3,13 @@ defineOptions({ inheritAttrs: false })
|
|
|
3
3
|
|
|
4
4
|
import { ref, computed, watch, provide, onMounted, onBeforeUnmount, nextTick, type CSSProperties } from 'vue'
|
|
5
5
|
import { cn } from '../../lib/utils'
|
|
6
|
+
import { type IconProp, isIconComponent } from '../../lib/icon'
|
|
6
7
|
|
|
7
8
|
export interface SelectOption {
|
|
8
9
|
value: any
|
|
9
10
|
label?: string
|
|
10
11
|
disabled?: boolean
|
|
11
|
-
icon?:
|
|
12
|
+
icon?: IconProp
|
|
12
13
|
image?: string
|
|
13
14
|
description?: string
|
|
14
15
|
color?: string
|
|
@@ -40,7 +41,7 @@ export interface Props {
|
|
|
40
41
|
teleport?: boolean | string
|
|
41
42
|
placement?: 'bottom' | 'top' | 'auto'
|
|
42
43
|
// New props
|
|
43
|
-
arrowIcon?:
|
|
44
|
+
arrowIcon?: IconProp
|
|
44
45
|
menuWidth?: string | number
|
|
45
46
|
menuAlign?: 'start' | 'end' | 'center'
|
|
46
47
|
creatable?: boolean
|
|
@@ -872,6 +873,7 @@ const resolvedColor = computed(() => props.color ?? 'var(--s-primary)')
|
|
|
872
873
|
:alt="selectedOptions[0].label"
|
|
873
874
|
class="w-5 h-5 rounded-full object-cover shrink-0"
|
|
874
875
|
/>
|
|
876
|
+
<component v-else-if="selectedOptions[0]?.icon && isIconComponent(selectedOptions[0].icon)" :is="selectedOptions[0].icon" class="text-muted-foreground" />
|
|
875
877
|
<span v-else-if="selectedOptions[0]?.icon" :class="['mdi', `mdi-${selectedOptions[0].icon}`, 'text-muted-foreground']" />
|
|
876
878
|
<span class="truncate text-foreground">{{ displayValue }}</span>
|
|
877
879
|
</slot>
|
|
@@ -907,8 +909,14 @@ const resolvedColor = computed(() => props.color ?? 'var(--s-primary)')
|
|
|
907
909
|
|
|
908
910
|
<!-- Dropdown arrow -->
|
|
909
911
|
<slot name="arrow" :is-open="isOpen">
|
|
910
|
-
<
|
|
911
|
-
v-if="!loading"
|
|
912
|
+
<component
|
|
913
|
+
v-if="!loading && isIconComponent(arrowIcon)"
|
|
914
|
+
:is="arrowIcon"
|
|
915
|
+
class="text-muted-foreground transition-transform duration-200 shrink-0"
|
|
916
|
+
:class="[sizeConfig.icon, { 'rotate-180': isOpen }]"
|
|
917
|
+
/>
|
|
918
|
+
<span
|
|
919
|
+
v-else-if="!loading"
|
|
912
920
|
class="text-muted-foreground transition-transform duration-200 shrink-0"
|
|
913
921
|
:class="['mdi', `mdi-${arrowIcon}`, sizeConfig.icon, { 'rotate-180': isOpen }]"
|
|
914
922
|
/>
|
|
@@ -1030,8 +1038,15 @@ const resolvedColor = computed(() => props.color ?? 'var(--s-primary)')
|
|
|
1030
1038
|
class="relative z-10 w-6 h-6 rounded-full object-cover shrink-0 mr-2.5"
|
|
1031
1039
|
/>
|
|
1032
1040
|
<!-- Icon -->
|
|
1033
|
-
<
|
|
1034
|
-
v-else-if="option.icon"
|
|
1041
|
+
<component
|
|
1042
|
+
v-else-if="option.icon && isIconComponent(option.icon)"
|
|
1043
|
+
:is="option.icon"
|
|
1044
|
+
class="relative z-10 shrink-0 mr-2.5"
|
|
1045
|
+
:class="[sizeConfig.icon]"
|
|
1046
|
+
:style="isSelected(option.value) ? { color: option.color ?? resolvedColor } : {}"
|
|
1047
|
+
/>
|
|
1048
|
+
<span
|
|
1049
|
+
v-else-if="option.icon"
|
|
1035
1050
|
class="relative z-10 shrink-0 mr-2.5"
|
|
1036
1051
|
:class="['mdi', `mdi-${option.icon}`, sizeConfig.icon]"
|
|
1037
1052
|
:style="isSelected(option.value) ? { color: option.color ?? resolvedColor } : {}"
|
|
@@ -1098,8 +1113,15 @@ const resolvedColor = computed(() => props.color ?? 'var(--s-primary)')
|
|
|
1098
1113
|
class="relative z-10 w-6 h-6 rounded-full object-cover shrink-0 mr-2.5"
|
|
1099
1114
|
/>
|
|
1100
1115
|
<!-- Icon -->
|
|
1101
|
-
<
|
|
1102
|
-
v-else-if="option.icon"
|
|
1116
|
+
<component
|
|
1117
|
+
v-else-if="option.icon && isIconComponent(option.icon)"
|
|
1118
|
+
:is="option.icon"
|
|
1119
|
+
class="relative z-10 shrink-0 mr-2.5"
|
|
1120
|
+
:class="[sizeConfig.icon]"
|
|
1121
|
+
:style="isSelected(option.value) ? { color: option.color ?? resolvedColor } : {}"
|
|
1122
|
+
/>
|
|
1123
|
+
<span
|
|
1124
|
+
v-else-if="option.icon"
|
|
1103
1125
|
class="relative z-10 shrink-0 mr-2.5"
|
|
1104
1126
|
:class="['mdi', `mdi-${option.icon}`, sizeConfig.icon]"
|
|
1105
1127
|
:style="isSelected(option.value) ? { color: option.color ?? resolvedColor } : {}"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, useAttrs, type CSSProperties } from 'vue'
|
|
3
3
|
import { cn } from '../../lib/utils'
|
|
4
|
+
import { type IconProp, isIconComponent } from '../../lib/icon'
|
|
4
5
|
|
|
5
6
|
defineOptions({ inheritAttrs: false })
|
|
6
7
|
|
|
@@ -17,8 +18,8 @@ export interface Props {
|
|
|
17
18
|
uncheckedValue?: boolean | string | number
|
|
18
19
|
labelBefore?: string
|
|
19
20
|
labelAfter?: string
|
|
20
|
-
checkedIcon?:
|
|
21
|
-
uncheckedIcon?:
|
|
21
|
+
checkedIcon?: IconProp
|
|
22
|
+
uncheckedIcon?: IconProp
|
|
22
23
|
checkedText?: string
|
|
23
24
|
uncheckedText?: string
|
|
24
25
|
trackClass?: string
|
|
@@ -232,16 +233,18 @@ const thumbClasses = computed(() => {
|
|
|
232
233
|
<!-- Custom Icons via Slots -->
|
|
233
234
|
<template v-else>
|
|
234
235
|
<slot v-if="isChecked" name="checked-icon">
|
|
236
|
+
<component v-if="checkedIcon && isIconComponent(checkedIcon)" :is="checkedIcon" :class="[sizeConfig.icon]" :style="checkedIconStyle" />
|
|
235
237
|
<span
|
|
236
|
-
v-if="checkedIcon"
|
|
238
|
+
v-else-if="checkedIcon"
|
|
237
239
|
:class="['mdi', `mdi-${checkedIcon}`, sizeConfig.icon]"
|
|
238
240
|
:style="checkedIconStyle"
|
|
239
241
|
:data-no-color="!color ? '' : undefined"
|
|
240
242
|
></span>
|
|
241
243
|
</slot>
|
|
242
244
|
<slot v-else name="unchecked-icon">
|
|
245
|
+
<component v-if="uncheckedIcon && isIconComponent(uncheckedIcon)" :is="uncheckedIcon" :class="[sizeConfig.icon, 'text-muted-foreground']" />
|
|
243
246
|
<span
|
|
244
|
-
v-if="uncheckedIcon"
|
|
247
|
+
v-else-if="uncheckedIcon"
|
|
245
248
|
:class="['mdi', `mdi-${uncheckedIcon}`, sizeConfig.icon, 'text-muted-foreground']"
|
|
246
249
|
></span>
|
|
247
250
|
</slot>
|
|
@@ -3,6 +3,7 @@ defineOptions({ inheritAttrs: false })
|
|
|
3
3
|
|
|
4
4
|
import { inject, ref, computed, onMounted, onBeforeUnmount, watch, nextTick, provide, useSlots } from 'vue'
|
|
5
5
|
import { cn } from '../../../lib/utils'
|
|
6
|
+
import { type IconProp, isIconComponent } from '../../../lib/icon'
|
|
6
7
|
import { SAccordionContextKey, SAccordionItemContextKey, type SAccordionContext } from './SAccordion.vue'
|
|
7
8
|
|
|
8
9
|
export interface Props {
|
|
@@ -12,10 +13,10 @@ export interface Props {
|
|
|
12
13
|
title?: string
|
|
13
14
|
/** Optional subtitle text */
|
|
14
15
|
subtitle?: string
|
|
15
|
-
/** MDI icon name for header */
|
|
16
|
-
icon?:
|
|
17
|
-
/** Custom expand icon (MDI icon name, replaces default chevron) */
|
|
18
|
-
expandIcon?:
|
|
16
|
+
/** MDI icon name or Vue component for header */
|
|
17
|
+
icon?: IconProp
|
|
18
|
+
/** Custom expand icon (MDI icon name or Vue component, replaces default chevron) */
|
|
19
|
+
expandIcon?: IconProp
|
|
19
20
|
/** Disable this item */
|
|
20
21
|
disabled?: boolean
|
|
21
22
|
/** Lazy render content */
|
|
@@ -272,8 +273,14 @@ provide(SAccordionItemContextKey, {
|
|
|
272
273
|
:disabled="disabled"
|
|
273
274
|
>
|
|
274
275
|
<!-- Icon -->
|
|
276
|
+
<component
|
|
277
|
+
v-if="icon && isIconComponent(icon)"
|
|
278
|
+
:is="icon"
|
|
279
|
+
:class="[sizeConfig.icon, 'shrink-0 text-muted-foreground']"
|
|
280
|
+
:style="isExpanded ? { color: context?.color } : {}"
|
|
281
|
+
/>
|
|
275
282
|
<span
|
|
276
|
-
v-if="icon"
|
|
283
|
+
v-else-if="icon"
|
|
277
284
|
:class="['mdi', `mdi-${icon}`, sizeConfig.icon, 'shrink-0 text-muted-foreground']"
|
|
278
285
|
:style="isExpanded ? { color: context?.color } : {}"
|
|
279
286
|
/>
|
|
@@ -304,7 +311,14 @@ provide(SAccordionItemContextKey, {
|
|
|
304
311
|
|
|
305
312
|
<!-- Expand Icon -->
|
|
306
313
|
<slot name="icon" :expanded="isExpanded">
|
|
314
|
+
<component
|
|
315
|
+
v-if="expandIcon && isIconComponent(expandIcon)"
|
|
316
|
+
:is="expandIcon"
|
|
317
|
+
:class="[sizeConfig.expandIcon, 'text-muted-foreground shrink-0']"
|
|
318
|
+
:style="expandIconStyle"
|
|
319
|
+
/>
|
|
307
320
|
<span
|
|
321
|
+
v-else
|
|
308
322
|
:class="['mdi shrink-0', `mdi-${expandIcon || 'chevron-down'}`, sizeConfig.expandIcon, 'text-muted-foreground']"
|
|
309
323
|
:style="expandIconStyle"
|
|
310
324
|
/>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, inject } from 'vue'
|
|
3
3
|
import { cn } from '../../../lib/utils'
|
|
4
|
+
import { type IconProp, isIconComponent } from '../../../lib/icon'
|
|
4
5
|
import { cardContextKey, type CardContext } from './index'
|
|
5
6
|
|
|
6
7
|
defineOptions({ inheritAttrs: false })
|
|
@@ -14,8 +15,8 @@ export interface Props {
|
|
|
14
15
|
avatar?: string
|
|
15
16
|
/** Avatar fallback text (initials) */
|
|
16
17
|
avatarFallback?: string
|
|
17
|
-
/** Icon name (MDI) */
|
|
18
|
-
icon?:
|
|
18
|
+
/** Icon name (MDI) or Vue component */
|
|
19
|
+
icon?: IconProp
|
|
19
20
|
/** Icon color */
|
|
20
21
|
iconColor?: string
|
|
21
22
|
/** Show divider below header */
|
|
@@ -109,11 +110,13 @@ const computedStyle = computed(() => {
|
|
|
109
110
|
</div>
|
|
110
111
|
|
|
111
112
|
<!-- Icon -->
|
|
112
|
-
<div
|
|
113
|
-
v-else-if="icon"
|
|
113
|
+
<div
|
|
114
|
+
v-else-if="icon"
|
|
114
115
|
class="w-10 h-10 rounded-xl bg-primary/15 flex items-center justify-center"
|
|
115
116
|
>
|
|
116
|
-
<
|
|
117
|
+
<component v-if="isIconComponent(icon)" :is="icon" :style="{ color: iconColor }" />
|
|
118
|
+
<span
|
|
119
|
+
v-else
|
|
117
120
|
class="mdi text-xl"
|
|
118
121
|
:class="`mdi-${icon}`"
|
|
119
122
|
:style="{ color: iconColor }"
|