@vc-shell/framework 1.1.57 → 1.1.59
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/CHANGELOG.md +13 -0
- package/core/services/widget-service.ts +6 -4
- package/dist/assets/154365acf3010d96.woff2 +0 -0
- package/dist/assets/475937116ee3314a.woff2 +0 -0
- package/dist/assets/49791943b3872376.woff2 +0 -0
- package/dist/assets/7a5aa5abd625137f.ttf +0 -0
- package/dist/assets/ac1a99b3d05d8232.woff +0 -0
- package/dist/assets/ccc878931d74181b.woff2 +0 -0
- package/dist/assets/ee6983981ffcbb41.woff2 +0 -0
- package/dist/core/services/widget-service.d.ts +2 -2
- package/dist/core/services/widget-service.d.ts.map +1 -1
- package/dist/framework.js +3535 -3506
- package/dist/index.css +9 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts +5 -0
- package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts.map +1 -1
- package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts +6 -1
- package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts.map +1 -1
- package/dist/{vendor-intlify-core-base-Bvt2vJFV.js → vendor-intlify-core-base-DZ8xhqFL.js} +4 -4
- package/dist/{vendor-intlify-message-compiler-1VxNzq21.js → vendor-intlify-message-compiler-8PCyu80g.js} +2 -2
- package/dist/{vendor-intlify-shared-D7kiPMOG.js → vendor-intlify-shared-BBJw7VuB.js} +1 -1
- package/dist/vendor-lucide-vue-next-m0L4DzUL.js +29780 -0
- package/dist/{vendor-vue-i18n-DPtOLen3.js → vendor-vue-i18n-CXIkMpzB.js} +5 -5
- package/package.json +8 -5
- package/ui/components/atoms/vc-icon/composables/use-icon.ts +1 -1
- package/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue +5 -6
- package/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue +31 -37
- package/ui/components/atoms/vc-icon/vc-icon.vue +186 -43
- package/ui/components/atoms/vc-icon/vc-lucide-icon.vue +70 -23
- package/ui/components/atoms/vc-icon/vc-material-icon.vue +37 -45
- package/dist/vendor-iconify-vue-D4fihzvl.js +0 -1205
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { C as Yt, D as qe, u as B, c as jt, a as Ce, b as De, i as K, A as Bt, s as Xt, g as Jt, N as Kt, d as zt, e as qt, f as Qe, h as Qt, j as Se, p as ye, t as Ve, M as Me, k as Ue, l as We, m as $e, n as we, o as Zt, q as ea, r as ta, v as aa, w as na, x as sa, y as la, z as ra, B as oa } from "./vendor-intlify-core-base-
|
|
2
|
-
import { w as Ze, e as N, l as ia, A as S, a as F, B as Ne, b, i as P, f as le, r as re, d as C, c as A, C as se, k as oe, j as R, g as $, n as z, h as Te, o as ca, m as J } from "./vendor-intlify-shared-
|
|
1
|
+
import { C as Yt, D as qe, u as B, c as jt, a as Ce, b as De, i as K, A as Bt, s as Xt, g as Jt, N as Kt, d as zt, e as qt, f as Qe, h as Qt, j as Se, p as ye, t as Ve, M as Me, k as Ue, l as We, m as $e, n as we, o as Zt, q as ea, r as ta, v as aa, w as na, x as sa, y as la, z as ra, B as oa } from "./vendor-intlify-core-base-DZ8xhqFL.js";
|
|
2
|
+
import { w as Ze, e as N, l as ia, A as S, a as F, B as Ne, b, i as P, f as le, r as re, d as C, c as A, C as se, k as oe, j as R, g as $, n as z, h as Te, o as ca, m as J } from "./vendor-intlify-shared-BBJw7VuB.js";
|
|
3
3
|
import { effectScope as _a, ref as ua, shallowRef as ma, computed as X, watch as ge, isRef as fa, defineComponent as Le, getCurrentInstance as q, h as et, Fragment as tt, inject as ga, onMounted as Ea, onUnmounted as da, createVNode as ba, Text as va } from "vue";
|
|
4
4
|
import { s as Ia } from "./vendor-vue-devtools-api-aVYGocXp.js";
|
|
5
|
-
import { c as pa } from "./vendor-intlify-message-compiler-
|
|
5
|
+
import { c as pa } from "./vendor-intlify-message-compiler-8PCyu80g.js";
|
|
6
6
|
/*!
|
|
7
|
-
* vue-i18n v11.1.
|
|
7
|
+
* vue-i18n v11.1.9
|
|
8
8
|
* (c) 2025 kazuya kawaguchi
|
|
9
9
|
* Released under the MIT License.
|
|
10
10
|
*/
|
|
11
|
-
const at = "11.1.
|
|
11
|
+
const at = "11.1.9";
|
|
12
12
|
function Na() {
|
|
13
13
|
typeof __VUE_I18N_FULL_INSTALL__ != "boolean" && (J().__VUE_I18N_FULL_INSTALL__ = !0), typeof __VUE_I18N_LEGACY_API__ != "boolean" && (J().__VUE_I18N_LEGACY_API__ = !0), typeof __INTLIFY_DROP_MESSAGE_COMPILER__ != "boolean" && (J().__INTLIFY_DROP_MESSAGE_COMPILER__ = !1), typeof __INTLIFY_PROD_DEVTOOLS__ != "boolean" && (J().__INTLIFY_PROD_DEVTOOLS__ = !1);
|
|
14
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vc-shell/framework",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.59",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/framework.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -41,8 +41,9 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@floating-ui/vue": "^1.0.6",
|
|
43
43
|
"@fontsource/plus-jakarta-sans": "^5.1.0",
|
|
44
|
+
"@fortawesome/fontawesome-free": "^6.7.2",
|
|
44
45
|
"@headlessui/vue": "^1.7.19",
|
|
45
|
-
"@
|
|
46
|
+
"@material-symbols/font-300": "^0.32.0",
|
|
46
47
|
"@microsoft/signalr": "^8.0.0",
|
|
47
48
|
"@tiptap/extension-image": "^2.25.0",
|
|
48
49
|
"@tiptap/extension-link": "^2.25.0",
|
|
@@ -61,9 +62,11 @@
|
|
|
61
62
|
"@vueuse/components": "^10.7.1",
|
|
62
63
|
"@vueuse/core": "^10.7.1",
|
|
63
64
|
"@vueuse/integrations": "^10.7.1",
|
|
65
|
+
"bootstrap-icons": "^1.11.3",
|
|
64
66
|
"core-js": "^3.35.0",
|
|
65
67
|
"dompurify": "^3.0.11",
|
|
66
68
|
"iso-639-1": "^3.1.0",
|
|
69
|
+
"lucide-vue-next": "^0.503.0",
|
|
67
70
|
"moment": "^2.30.1",
|
|
68
71
|
"normalize.css": "^8.0.1",
|
|
69
72
|
"swiper": "^6.8.4",
|
|
@@ -82,9 +85,9 @@
|
|
|
82
85
|
"@fullhuman/postcss-purgecss": "^7.0.2",
|
|
83
86
|
"@laynezh/vite-plugin-lib-assets": "v1.1.0",
|
|
84
87
|
"@types/dompurify": "^3.0.5",
|
|
85
|
-
"@vc-shell/api-client-generator": "^1.1.
|
|
86
|
-
"@vc-shell/config-generator": "^1.1.
|
|
87
|
-
"@vc-shell/ts-config": "^1.1.
|
|
88
|
+
"@vc-shell/api-client-generator": "^1.1.59",
|
|
89
|
+
"@vc-shell/config-generator": "^1.1.59",
|
|
90
|
+
"@vc-shell/ts-config": "^1.1.59",
|
|
88
91
|
"@vitejs/plugin-vue": "^5.2.3",
|
|
89
92
|
"@vue/test-utils": "^2.4.5",
|
|
90
93
|
"cypress-signalr-mock": "^1.5.0",
|
|
@@ -90,7 +90,7 @@ export function useIcon(options: UseIconOptions) {
|
|
|
90
90
|
const styles: Record<string, string> = {};
|
|
91
91
|
|
|
92
92
|
// For SVG and Lucide icons, we need width and height
|
|
93
|
-
if (type === "svg") {
|
|
93
|
+
if (type === "svg" || type === "lucide") {
|
|
94
94
|
styles.width = "1em";
|
|
95
95
|
styles.height = "1em";
|
|
96
96
|
}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:icon="iconName"
|
|
2
|
+
<i
|
|
4
3
|
:class="[
|
|
5
4
|
'vc-bootstrap-icon',
|
|
6
5
|
!hasCustomSize && `vc-bootstrap-icon--${size}`,
|
|
6
|
+
iconClass,
|
|
7
7
|
variant ? `vc-bootstrap-icon--${variant}` : '',
|
|
8
8
|
]"
|
|
9
9
|
:style="mergedStyle"
|
|
10
10
|
aria-hidden="true"
|
|
11
|
-
|
|
11
|
+
></i>
|
|
12
12
|
</template>
|
|
13
13
|
|
|
14
14
|
<script lang="ts" setup>
|
|
15
15
|
import { computed } from "vue";
|
|
16
|
-
import { Icon } from "@iconify/vue";
|
|
17
16
|
import type { IconSize, IconVariant } from "./types";
|
|
18
17
|
import { useIcon } from "./composables";
|
|
19
18
|
|
|
@@ -67,11 +66,11 @@ const mergedStyle = computed(() => {
|
|
|
67
66
|
});
|
|
68
67
|
|
|
69
68
|
// Compute proper Bootstrap icon class
|
|
70
|
-
const
|
|
69
|
+
const iconClass = computed(() => {
|
|
71
70
|
if (!props.icon) return "";
|
|
72
71
|
|
|
73
72
|
const icon = props.icon.startsWith("bi-") ? props.icon.substring(3) : props.icon;
|
|
74
|
-
return `bi
|
|
73
|
+
return `bi-${icon}`;
|
|
75
74
|
});
|
|
76
75
|
</script>
|
|
77
76
|
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:
|
|
4
|
-
|
|
2
|
+
<i
|
|
3
|
+
:class="[
|
|
4
|
+
'vc-fa-icon',
|
|
5
|
+
!hasCustomSize && `vc-fa-icon--${size}`,
|
|
6
|
+
iconClasses,
|
|
7
|
+
variant ? `vc-fa-icon--${variant}` : '',
|
|
8
|
+
]"
|
|
5
9
|
:style="mergedStyle"
|
|
6
10
|
aria-hidden="true"
|
|
7
|
-
|
|
11
|
+
></i>
|
|
8
12
|
</template>
|
|
9
13
|
|
|
10
14
|
<script lang="ts" setup>
|
|
11
15
|
import { computed } from "vue";
|
|
12
|
-
import { Icon } from "@iconify/vue";
|
|
13
16
|
import type { IconSize, IconVariant } from "./types";
|
|
14
17
|
import { useIcon } from "./composables";
|
|
15
18
|
|
|
@@ -62,40 +65,31 @@ const mergedStyle = computed(() => {
|
|
|
62
65
|
return styles;
|
|
63
66
|
});
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
style = "solid";
|
|
77
|
-
break;
|
|
78
|
-
case "far":
|
|
79
|
-
style = "regular";
|
|
80
|
-
break;
|
|
81
|
-
case "fab":
|
|
82
|
-
style = "brands";
|
|
83
|
-
break;
|
|
84
|
-
case "fal":
|
|
85
|
-
style = "light";
|
|
86
|
-
break;
|
|
87
|
-
case "fad":
|
|
88
|
-
style = "duotone";
|
|
89
|
-
break;
|
|
90
|
-
default:
|
|
91
|
-
// Use the already processed name from slice(1), not the original props.icon
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
name = name.replace("fa-", "");
|
|
68
|
+
// Compute the FontAwesome class from the icon string
|
|
69
|
+
const iconClasses = computed(() => {
|
|
70
|
+
// If icon already has a style prefix (fas, far, fal, fab), use it as is
|
|
71
|
+
if (
|
|
72
|
+
props.icon.startsWith("fas ") ||
|
|
73
|
+
props.icon.startsWith("far ") ||
|
|
74
|
+
props.icon.startsWith("fal ") ||
|
|
75
|
+
props.icon.startsWith("fab ") ||
|
|
76
|
+
props.icon.startsWith("fad ")
|
|
77
|
+
) {
|
|
78
|
+
return props.icon;
|
|
96
79
|
}
|
|
97
80
|
|
|
98
|
-
|
|
81
|
+
// If icon starts with fa-, add the default style prefix
|
|
82
|
+
if (props.icon.startsWith("fa-")) {
|
|
83
|
+
return `fas ${props.icon}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// If icon contains fa- but doesn't start with a style prefix, assume the style prefix is included
|
|
87
|
+
if (props.icon.includes("fa-")) {
|
|
88
|
+
return props.icon;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Otherwise, assume it's a bare icon name and add both the style prefix and fa- prefix
|
|
92
|
+
return `fas fa-${props.icon}`;
|
|
99
93
|
});
|
|
100
94
|
</script>
|
|
101
95
|
|
|
@@ -110,6 +110,16 @@ const sizeMap = {
|
|
|
110
110
|
xxxl: 64,
|
|
111
111
|
} as const;
|
|
112
112
|
|
|
113
|
+
// Scaling factors for different icon types to make them visually equal
|
|
114
|
+
const scalingFactors = {
|
|
115
|
+
fontawesome: 1, // base reference
|
|
116
|
+
material: 1.1,
|
|
117
|
+
bootstrap: 0.95,
|
|
118
|
+
lucide: 1.2,
|
|
119
|
+
custom: 1,
|
|
120
|
+
svg: 1,
|
|
121
|
+
};
|
|
122
|
+
|
|
113
123
|
// Function to detect icon type if not explicitly specified
|
|
114
124
|
const detectIconType = computed((): IconType => {
|
|
115
125
|
if (typeof props.icon !== "string") {
|
|
@@ -152,16 +162,16 @@ const normalizedIconName = computed(() => {
|
|
|
152
162
|
return props.icon;
|
|
153
163
|
}
|
|
154
164
|
|
|
155
|
-
|
|
165
|
+
if (detectIconType.value === "material" && props.icon.startsWith("material-")) {
|
|
166
|
+
return props.icon.replace(/^material-/, "");
|
|
167
|
+
}
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
case "lucide":
|
|
161
|
-
return props.icon.replace(/^lucide-/, "");
|
|
162
|
-
default:
|
|
163
|
-
return props.icon;
|
|
169
|
+
if (detectIconType.value === "lucide" && props.icon.startsWith("lucide-")) {
|
|
170
|
+
const baseName = props.icon.replace(/^lucide-/, "");
|
|
171
|
+
return baseName.endsWith("Icon") ? baseName : `${baseName}Icon`;
|
|
164
172
|
}
|
|
173
|
+
|
|
174
|
+
return props.icon;
|
|
165
175
|
});
|
|
166
176
|
|
|
167
177
|
// Check if icon is a Material Design symbol
|
|
@@ -176,7 +186,7 @@ const isLucideIcon = computed(() => detectIconType.value === "lucide");
|
|
|
176
186
|
// Check if icon is a Font Awesome Icon
|
|
177
187
|
const isFontAwesomeIcon = computed(() => detectIconType.value === "fontawesome");
|
|
178
188
|
|
|
179
|
-
// Check if icon is a component or can be resolved as a component
|
|
189
|
+
// Check if the icon is a component or can be resolved as a component
|
|
180
190
|
const isCustomIcon = computed(() => {
|
|
181
191
|
if (typeof props.icon !== "string") {
|
|
182
192
|
return true; // Component instance passed directly
|
|
@@ -191,13 +201,25 @@ const isCustomIcon = computed(() => {
|
|
|
191
201
|
return false;
|
|
192
202
|
}
|
|
193
203
|
|
|
194
|
-
//
|
|
204
|
+
// Check for Lucide icons - they could be resolved as components
|
|
195
205
|
if (isLucideIcon.value) {
|
|
196
|
-
|
|
206
|
+
try {
|
|
207
|
+
const iconName =
|
|
208
|
+
typeof normalizedIconName.value === "string" ? normalizedIconName.value : String(normalizedIconName.value);
|
|
209
|
+
const resolved = resolveComponent(iconName);
|
|
210
|
+
return resolved !== iconName;
|
|
211
|
+
} catch (e) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
//
|
|
200
|
-
|
|
216
|
+
// Check if string is a component name that can be resolved
|
|
217
|
+
try {
|
|
218
|
+
const resolved = resolveComponent(props.icon);
|
|
219
|
+
return resolved !== props.icon; // If resolved is different from original string, it's a component name
|
|
220
|
+
} catch (e) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
201
223
|
});
|
|
202
224
|
|
|
203
225
|
// Get the component instance for rendering
|
|
@@ -211,14 +233,15 @@ const safeIcon = computed(() => {
|
|
|
211
233
|
return "i";
|
|
212
234
|
}
|
|
213
235
|
|
|
214
|
-
//
|
|
215
|
-
|
|
236
|
+
// Try to resolve component by name (mostly for Lucide icons)
|
|
237
|
+
try {
|
|
216
238
|
const iconName =
|
|
217
239
|
typeof normalizedIconName.value === "string" ? normalizedIconName.value : String(normalizedIconName.value);
|
|
218
|
-
|
|
240
|
+
const resolved = resolveComponent(iconName);
|
|
241
|
+
return resolved !== iconName ? resolved : "i"; // Return resolved component or fallback to 'i'
|
|
242
|
+
} catch (e) {
|
|
243
|
+
return "i";
|
|
219
244
|
}
|
|
220
|
-
|
|
221
|
-
return "i";
|
|
222
245
|
});
|
|
223
246
|
|
|
224
247
|
// Determine which component to render
|
|
@@ -292,32 +315,82 @@ const containerStyle = computed(() => {
|
|
|
292
315
|
|
|
293
316
|
// Prepare props for the rendered component
|
|
294
317
|
const componentProps = computed(() => {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
318
|
+
if (isMaterialIcon.value) {
|
|
319
|
+
// Clean the name from possible suffixes of the icon type
|
|
320
|
+
const cleanIconName =
|
|
321
|
+
typeof normalizedIconName.value === "string"
|
|
322
|
+
? normalizedIconName.value.replace(/-outlined$|-rounded$|-sharp$/, "")
|
|
323
|
+
: normalizedIconName.value;
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
icon: cleanIconName,
|
|
327
|
+
size: props.size,
|
|
328
|
+
variant: props.variant,
|
|
329
|
+
type: "outlined",
|
|
330
|
+
fill: 0,
|
|
331
|
+
weight: 300,
|
|
332
|
+
grade: 0,
|
|
333
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (isBootstrapIcon.value) {
|
|
338
|
+
// For Bootstrap icons
|
|
339
|
+
const iconName = typeof props.icon === "string" ? props.icon : "";
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
icon: iconName,
|
|
343
|
+
size: props.size,
|
|
344
|
+
variant: props.variant,
|
|
345
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (isLucideIcon.value) {
|
|
350
|
+
// For Lucide icons
|
|
351
|
+
const iconName =
|
|
352
|
+
typeof normalizedIconName.value === "string" ? normalizedIconName.value : String(normalizedIconName.value);
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
icon: iconName,
|
|
356
|
+
size: props.size,
|
|
357
|
+
variant: props.variant,
|
|
358
|
+
strokeWidth: 1.5,
|
|
359
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (isFontAwesomeIcon.value) {
|
|
364
|
+
// For Font Awesome icons
|
|
365
|
+
return {
|
|
366
|
+
icon: typeof props.icon === "string" ? props.icon : "",
|
|
367
|
+
size: props.size,
|
|
368
|
+
variant: props.variant,
|
|
369
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (isSvgIcon.value) {
|
|
374
|
+
return {
|
|
375
|
+
icon: svgPath.value,
|
|
376
|
+
size: props.size,
|
|
377
|
+
variant: props.variant,
|
|
378
|
+
strokeWidth: 1.5,
|
|
379
|
+
customSize: props.customSize, // Set custom size without scaling
|
|
380
|
+
basePath: props.basePath,
|
|
381
|
+
};
|
|
320
382
|
}
|
|
383
|
+
|
|
384
|
+
if (isCustomIcon.value) {
|
|
385
|
+
return {
|
|
386
|
+
size: props.size,
|
|
387
|
+
width: calculatedSize.value,
|
|
388
|
+
height: calculatedSize.value,
|
|
389
|
+
color: props.variant ? `var(--icon-color-${props.variant})` : "currentColor",
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return {};
|
|
321
394
|
});
|
|
322
395
|
|
|
323
396
|
// Check if icon is an SVG icon
|
|
@@ -461,4 +534,74 @@ const svgPath = computed(() => {
|
|
|
461
534
|
min-height: calc(var(--icon-size-xxxl) * 1.33);
|
|
462
535
|
font-size: var(--icon-size-xxxl); /* Set font-size for the container */
|
|
463
536
|
}
|
|
537
|
+
|
|
538
|
+
/* Material Icons specific styles */
|
|
539
|
+
.material-symbols-outlined,
|
|
540
|
+
.material-symbols-rounded,
|
|
541
|
+
.material-symbols-sharp {
|
|
542
|
+
font-family: "Material Symbols Outlined";
|
|
543
|
+
font-weight: normal;
|
|
544
|
+
font-style: normal;
|
|
545
|
+
line-height: 1;
|
|
546
|
+
letter-spacing: normal;
|
|
547
|
+
text-transform: none;
|
|
548
|
+
white-space: nowrap;
|
|
549
|
+
word-wrap: normal;
|
|
550
|
+
direction: ltr;
|
|
551
|
+
font-feature-settings: "liga";
|
|
552
|
+
-webkit-font-feature-settings: "liga";
|
|
553
|
+
-webkit-font-smoothing: antialiased;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/* Bootstrap Icons specific styles */
|
|
557
|
+
[class^="bi-"],
|
|
558
|
+
[class*=" bi-"] {
|
|
559
|
+
font-family: bootstrap-icons !important;
|
|
560
|
+
font-style: normal;
|
|
561
|
+
font-weight: normal !important;
|
|
562
|
+
font-variant: normal;
|
|
563
|
+
text-transform: none;
|
|
564
|
+
line-height: 1;
|
|
565
|
+
-webkit-font-smoothing: antialiased;
|
|
566
|
+
-moz-osx-font-smoothing: grayscale;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* Font Awesome Icons */
|
|
570
|
+
[class^="fa-"],
|
|
571
|
+
[class*=" fa-"],
|
|
572
|
+
[class~="fas"],
|
|
573
|
+
[class~="far"],
|
|
574
|
+
[class~="fal"],
|
|
575
|
+
[class~="fab"],
|
|
576
|
+
[class~="fad"] {
|
|
577
|
+
font-family: "Font Awesome 6 Free", "Font Awesome 6 Brands", "Font Awesome 6 Duotone", "Font Awesome 6 Pro";
|
|
578
|
+
font-style: normal;
|
|
579
|
+
font-weight: normal;
|
|
580
|
+
font-variant: normal;
|
|
581
|
+
text-transform: none;
|
|
582
|
+
line-height: 1;
|
|
583
|
+
-webkit-font-smoothing: antialiased;
|
|
584
|
+
-moz-osx-font-smoothing: grayscale;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/* Font weight adjustments for Font Awesome */
|
|
588
|
+
.fas,
|
|
589
|
+
.fa-solid {
|
|
590
|
+
font-weight: 900;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.far,
|
|
594
|
+
.fa-regular {
|
|
595
|
+
font-weight: 400;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
.fal,
|
|
599
|
+
.fa-light {
|
|
600
|
+
font-weight: 300;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
.fab,
|
|
604
|
+
.fa-brands {
|
|
605
|
+
font-family: "Font Awesome 6 Brands";
|
|
606
|
+
}
|
|
464
607
|
</style>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
:
|
|
2
|
+
<component
|
|
3
|
+
:is="resolvedIconComponent"
|
|
4
|
+
v-if="resolvedIconComponent"
|
|
4
5
|
:class="[
|
|
5
6
|
'vc-lucide-icon',
|
|
6
7
|
!hasCustomSize && `vc-lucide-icon--${size}`,
|
|
@@ -9,12 +10,18 @@
|
|
|
9
10
|
:style="computedStyle"
|
|
10
11
|
aria-hidden="true"
|
|
11
12
|
/>
|
|
13
|
+
<span
|
|
14
|
+
v-else
|
|
15
|
+
:class="['vc-lucide-icon', !hasCustomSize && `vc-lucide-icon--${size}`]"
|
|
16
|
+
>
|
|
17
|
+
<i class="vc-lucide-icon__fallback">❓</i>
|
|
18
|
+
</span>
|
|
12
19
|
</template>
|
|
13
20
|
|
|
14
21
|
<script lang="ts" setup>
|
|
15
|
-
import { computed } from "vue";
|
|
16
|
-
import { Icon } from "@iconify/vue";
|
|
22
|
+
import { computed, markRaw, onMounted, ref } from "vue";
|
|
17
23
|
import type { IconSize, IconVariant } from "./types";
|
|
24
|
+
import type { Component } from "vue";
|
|
18
25
|
import { useIcon } from "./composables";
|
|
19
26
|
|
|
20
27
|
interface Props {
|
|
@@ -33,6 +40,11 @@ interface Props {
|
|
|
33
40
|
*/
|
|
34
41
|
variant?: IconVariant;
|
|
35
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Stroke width for SVG
|
|
45
|
+
*/
|
|
46
|
+
strokeWidth?: number;
|
|
47
|
+
|
|
36
48
|
/**
|
|
37
49
|
* Custom size in pixels
|
|
38
50
|
*/
|
|
@@ -41,11 +53,15 @@ interface Props {
|
|
|
41
53
|
|
|
42
54
|
const props = withDefaults(defineProps<Props>(), {
|
|
43
55
|
size: "m",
|
|
56
|
+
strokeWidth: 1.5,
|
|
44
57
|
});
|
|
45
58
|
|
|
46
59
|
// Check if using custom size to conditionally apply CSS class
|
|
47
60
|
const hasCustomSize = computed(() => typeof props.customSize === "number" && props.customSize > 0);
|
|
48
61
|
|
|
62
|
+
// Component reference for Lucide icon
|
|
63
|
+
const resolvedIconComponent = ref<Component | null>(null);
|
|
64
|
+
|
|
49
65
|
// Use the shared icon composable for consistent scaling
|
|
50
66
|
const { iconStyle } = useIcon({
|
|
51
67
|
type: "lucide",
|
|
@@ -54,40 +70,71 @@ const { iconStyle } = useIcon({
|
|
|
54
70
|
customSize: props.customSize,
|
|
55
71
|
});
|
|
56
72
|
|
|
73
|
+
// Normalize the icon name for Lucide
|
|
74
|
+
const normalizedIconName = computed(() => {
|
|
75
|
+
if (!props.icon) return "HelpCircleIcon";
|
|
76
|
+
|
|
77
|
+
// Handle removal of lucide- prefix
|
|
78
|
+
let name = props.icon;
|
|
79
|
+
if (name.startsWith("lucide-")) {
|
|
80
|
+
name = name.substring(7);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Ensure name ends with 'Icon'
|
|
84
|
+
if (!name.endsWith("Icon")) {
|
|
85
|
+
name = `${name}Icon`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Convert to PascalCase if kebab-case
|
|
89
|
+
if (name.includes("-")) {
|
|
90
|
+
name = name
|
|
91
|
+
.split("-")
|
|
92
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
93
|
+
.join("");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Ensure first letter is capitalized
|
|
97
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
57
100
|
// Combine the shared icon styles with Lucide-specific settings
|
|
58
101
|
const computedStyle = computed(() => {
|
|
59
102
|
const styles = { ...iconStyle.value };
|
|
60
103
|
|
|
104
|
+
if (props.strokeWidth) {
|
|
105
|
+
styles.strokeWidth = props.strokeWidth.toString();
|
|
106
|
+
}
|
|
107
|
+
|
|
61
108
|
// If using custom size, make sure size is applied with !important
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
109
|
+
if (hasCustomSize.value) {
|
|
110
|
+
if (styles.width) styles.width = `${styles.width.replace("px", "")}px !important`;
|
|
111
|
+
if (styles.height) styles.height = `${styles.height.replace("px", "")}px !important`;
|
|
112
|
+
}
|
|
66
113
|
|
|
67
114
|
return styles;
|
|
68
115
|
});
|
|
69
116
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
// Dynamically import the Lucide icon
|
|
118
|
+
onMounted(async () => {
|
|
119
|
+
try {
|
|
120
|
+
// Import from lucide-vue-next
|
|
121
|
+
const module = await import("lucide-vue-next");
|
|
122
|
+
|
|
123
|
+
// Get the icon component safely with type checking
|
|
124
|
+
const iconName = normalizedIconName.value;
|
|
125
|
+
if (module && typeof module === "object" && iconName in module) {
|
|
126
|
+
resolvedIconComponent.value = markRaw(module[iconName as keyof typeof module] as Component);
|
|
127
|
+
} else {
|
|
128
|
+
console.warn(`Lucide icon not found: ${iconName}`);
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error(`Error loading Lucide icon: ${normalizedIconName.value}`, error);
|
|
78
132
|
}
|
|
79
|
-
|
|
80
|
-
return `lucide:${name}`;
|
|
81
133
|
});
|
|
82
134
|
</script>
|
|
83
135
|
|
|
84
136
|
<style lang="scss">
|
|
85
137
|
.vc-lucide-icon {
|
|
86
|
-
& g,
|
|
87
|
-
& path {
|
|
88
|
-
stroke-width: var(--vc-lucide-icon-stroke-width, 1.5);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
138
|
display: inline-flex;
|
|
92
139
|
align-items: center;
|
|
93
140
|
justify-content: center;
|