@vc-shell/framework 1.1.4 → 1.1.5

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.
Files changed (132) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/core/directives/loading/styles.css +1 -1
  3. package/core/plugins/modularity/README.md +347 -17
  4. package/core/plugins/modularity/loader.ts +217 -3
  5. package/dist/core/plugins/modularity/loader.d.ts +4 -0
  6. package/dist/core/plugins/modularity/loader.d.ts.map +1 -1
  7. package/dist/framework.js +1 -1
  8. package/dist/{index-BdflTsg6.js → index-BBHl6nap.js} +1 -1
  9. package/dist/{index-DJOis7Nc.js → index-BG6N4UCY.js} +1 -1
  10. package/dist/{index-CIcET-ZI.js → index-Bv5as3SI.js} +1 -1
  11. package/dist/{index-wfv8ehcx.js → index-C4VyqVxv.js} +1 -1
  12. package/dist/{index-Cf2H7YZ1.js → index-CKLiFGZ-.js} +1 -1
  13. package/dist/{index-DuY7BIGm.js → index-CTmAMa_1.js} +1 -1
  14. package/dist/{index-D-fPN3yf.js → index-CtGZgIiV.js} +1 -1
  15. package/dist/{index-BpBTtmQ6.js → index-D13Jcezf.js} +1 -1
  16. package/dist/{index-DWTsz5bC.js → index-DbpKygJh.js} +1 -1
  17. package/dist/{index-Br0y2YMn.js → index-DgCtSr4P.js} +1 -1
  18. package/dist/{index-Ck055pN8.js → index-Dh1XjfgY.js} +1 -1
  19. package/dist/{index-CYAMpxnu.js → index-DpDbQQg6.js} +1 -1
  20. package/dist/{index-BDqUaIyQ.js → index-DwuQbDJG.js} +1 -1
  21. package/dist/{index-BBYKbiRX.js → index-Fhuqbkq2.js} +1 -1
  22. package/dist/{index-o6aSdNED.js → index-JTAZpxKF.js} +1 -1
  23. package/dist/{index-BDm0tcWn.js → index-MKD2CP5c.js} +49888 -48568
  24. package/dist/{index-DKtQMsy4.js → index-Q3k1PYzc.js} +1 -1
  25. package/dist/index.css +3 -3
  26. package/dist/shared/components/generic-dropdown/generic-dropdown.vue.d.ts.map +1 -1
  27. package/dist/shared/components/settings-menu-item/settings-menu-item.vue.d.ts.map +1 -1
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/dist/ui/components/atoms/vc-icon/composables/index.d.ts +3 -0
  30. package/dist/ui/components/atoms/vc-icon/composables/index.d.ts.map +1 -0
  31. package/dist/ui/components/atoms/vc-icon/composables/use-icon-type.d.ts +22 -0
  32. package/dist/ui/components/atoms/vc-icon/composables/use-icon-type.d.ts.map +1 -0
  33. package/dist/ui/components/atoms/vc-icon/composables/use-icon.d.ts +30 -0
  34. package/dist/ui/components/atoms/vc-icon/composables/use-icon.d.ts.map +1 -0
  35. package/dist/ui/components/atoms/vc-icon/index.d.ts +1 -0
  36. package/dist/ui/components/atoms/vc-icon/index.d.ts.map +1 -1
  37. package/dist/ui/components/atoms/vc-icon/types.d.ts +31 -0
  38. package/dist/ui/components/atoms/vc-icon/types.d.ts.map +1 -0
  39. package/dist/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue.d.ts +18 -4
  40. package/dist/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue.d.ts.map +1 -1
  41. package/dist/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue.d.ts +15 -2
  42. package/dist/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue.d.ts.map +1 -1
  43. package/dist/ui/components/atoms/vc-icon/vc-icon-examples.vue.d.ts.map +1 -1
  44. package/dist/ui/components/atoms/vc-icon/vc-icon-test.vue.d.ts.map +1 -1
  45. package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts +11 -6
  46. package/dist/ui/components/atoms/vc-icon/vc-icon.vue.d.ts.map +1 -1
  47. package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts +21 -4
  48. package/dist/ui/components/atoms/vc-icon/vc-lucide-icon.vue.d.ts.map +1 -1
  49. package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts +30 -4
  50. package/dist/ui/components/atoms/vc-icon/vc-material-icon.vue.d.ts.map +1 -1
  51. package/dist/ui/components/atoms/vc-icon/vc-svg-icon.vue.d.ts +33 -0
  52. package/dist/ui/components/atoms/vc-icon/vc-svg-icon.vue.d.ts.map +1 -0
  53. package/dist/ui/components/molecules/vc-pagination/vc-pagination.vue.d.ts.map +1 -1
  54. package/dist/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue.d.ts.map +1 -1
  55. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/props.d.ts +14 -0
  56. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/props.d.ts.map +1 -0
  57. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-base-button.vue.d.ts +2 -13
  58. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-base-button.vue.d.ts.map +1 -1
  59. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-circle-button.vue.d.ts +1 -1
  60. package/dist/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-circle-button.vue.d.ts.map +1 -1
  61. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts +1 -1
  62. package/dist/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue.d.ts.map +1 -1
  63. package/dist/ui/components/organisms/vc-table/_internal/vc-table-column-switcher/vc-table-column-switcher.vue.d.ts +1 -1
  64. package/dist/ui/components/organisms/vc-table/_internal/vc-table-column-switcher/vc-table-column-switcher.vue.d.ts.map +1 -1
  65. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-body/vc-table-body.vue.d.ts +1 -1
  66. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-body/vc-table-body.vue.d.ts.map +1 -1
  67. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-columns-header/vc-table-columns-header.vue.d.ts +1 -1
  68. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-columns-header/vc-table-columns-header.vue.d.ts.map +1 -1
  69. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue.d.ts +1 -1
  70. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue.d.ts.map +1 -1
  71. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue.d.ts +1 -1
  72. package/dist/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue.d.ts.map +1 -1
  73. package/dist/ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue.d.ts +1 -1
  74. package/dist/ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue.d.ts.map +1 -1
  75. package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts +1 -1
  76. package/dist/ui/components/organisms/vc-table/composables/useTableActions.d.ts.map +1 -1
  77. package/dist/ui/components/organisms/vc-table/composables/useTableColumnReorder.d.ts +1 -1
  78. package/dist/ui/components/organisms/vc-table/composables/useTableColumnReorder.d.ts.map +1 -1
  79. package/dist/ui/components/organisms/vc-table/composables/useTableColumnResize.d.ts +1 -1
  80. package/dist/ui/components/organisms/vc-table/composables/useTableColumnResize.d.ts.map +1 -1
  81. package/dist/ui/components/organisms/vc-table/composables/useTableRowReorder.d.ts +1 -1
  82. package/dist/ui/components/organisms/vc-table/composables/useTableRowReorder.d.ts.map +1 -1
  83. package/dist/ui/components/organisms/vc-table/composables/useTableSelection.d.ts +1 -1
  84. package/dist/ui/components/organisms/vc-table/composables/useTableSelection.d.ts.map +1 -1
  85. package/dist/ui/components/organisms/vc-table/composables/useTableState.d.ts +1 -1
  86. package/dist/ui/components/organisms/vc-table/composables/useTableState.d.ts.map +1 -1
  87. package/dist/ui/components/organisms/vc-table/types.d.ts +36 -0
  88. package/dist/ui/components/organisms/vc-table/types.d.ts.map +1 -0
  89. package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts +2 -34
  90. package/dist/ui/components/organisms/vc-table/vc-table.vue.d.ts.map +1 -1
  91. package/package.json +4 -4
  92. package/shared/components/generic-dropdown/generic-dropdown.vue +1 -1
  93. package/shared/components/settings-menu-item/settings-menu-item.vue +1 -6
  94. package/shared/components/user-dropdown-button/_internal/user-info.vue +3 -3
  95. package/ui/components/atoms/vc-icon/README.md +198 -220
  96. package/ui/components/atoms/vc-icon/composables/index.ts +2 -0
  97. package/ui/components/atoms/vc-icon/composables/use-icon-type.ts +83 -0
  98. package/ui/components/atoms/vc-icon/composables/use-icon.ts +129 -0
  99. package/ui/components/atoms/vc-icon/index.ts +1 -0
  100. package/ui/components/atoms/vc-icon/types.ts +36 -0
  101. package/ui/components/atoms/vc-icon/vc-bootstrap-icon.vue +111 -10
  102. package/ui/components/atoms/vc-icon/vc-fontawesome-icon.vue +119 -17
  103. package/ui/components/atoms/vc-icon/vc-icon-examples.vue +485 -124
  104. package/ui/components/atoms/vc-icon/vc-icon-test.vue +399 -209
  105. package/ui/components/atoms/vc-icon/vc-icon.stories.ts +502 -56
  106. package/ui/components/atoms/vc-icon/vc-icon.vue +240 -155
  107. package/ui/components/atoms/vc-icon/vc-lucide-icon.vue +163 -33
  108. package/ui/components/atoms/vc-icon/vc-material-icon.vue +136 -30
  109. package/ui/components/atoms/vc-icon/vc-svg-icon.vue +168 -0
  110. package/ui/components/atoms/vc-widget/vc-widget.stories.ts +13 -0
  111. package/ui/components/molecules/vc-multivalue/vc-multivalue.vue +1 -1
  112. package/ui/components/molecules/vc-pagination/vc-pagination.vue +23 -14
  113. package/ui/components/organisms/vc-app/_internal/vc-app-bar/_internal/AppBarHeader.vue +2 -2
  114. package/ui/components/organisms/vc-app/_internal/vc-app-bar/vc-app-bar.vue +2 -3
  115. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/props.ts +14 -0
  116. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-base-button.vue +1 -12
  117. package/ui/components/organisms/vc-blade/_internal/vc-blade-toolbar/_internal/vc-blade-toolbar-buttons/_internal/vc-blade-toolbar-button/vc-blade-toolbar-circle-button.vue +1 -1
  118. package/ui/components/organisms/vc-table/_internal/vc-table-cell/vc-table-cell.vue +1 -1
  119. package/ui/components/organisms/vc-table/_internal/vc-table-column-switcher/vc-table-column-switcher.vue +1 -1
  120. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-body/vc-table-body.vue +1 -1
  121. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-columns-header/vc-table-columns-header.vue +1 -1
  122. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/_internal/vc-table-row/vc-table-row.vue +1 -1
  123. package/ui/components/organisms/vc-table/_internal/vc-table-desktop-view/vc-table-desktop-view.vue +1 -1
  124. package/ui/components/organisms/vc-table/_internal/vc-table-mobile-view/vc-table-mobile-view.vue +1 -1
  125. package/ui/components/organisms/vc-table/composables/useTableActions.ts +1 -1
  126. package/ui/components/organisms/vc-table/composables/useTableColumnReorder.ts +1 -1
  127. package/ui/components/organisms/vc-table/composables/useTableColumnResize.ts +1 -1
  128. package/ui/components/organisms/vc-table/composables/useTableRowReorder.ts +1 -1
  129. package/ui/components/organisms/vc-table/composables/useTableSelection.ts +1 -1
  130. package/ui/components/organisms/vc-table/composables/useTableState.ts +1 -1
  131. package/ui/components/organisms/vc-table/types.ts +32 -0
  132. package/ui/components/organisms/vc-table/vc-table.vue +2 -30
@@ -1,66 +1,196 @@
1
1
  <template>
2
2
  <component
3
- :is="resolvedIcon"
4
- :class="['vc-icon', `vc-icon_${size}`, variant ? `vc-icon_${variant}` : '']"
5
- :stroke-width="strokeWidth"
3
+ :is="resolvedIconComponent"
4
+ v-if="resolvedIconComponent"
5
+ :class="[
6
+ 'vc-lucide-icon',
7
+ !hasCustomSize && `vc-lucide-icon--${size}`,
8
+ variant ? `vc-lucide-icon--${variant}` : '',
9
+ ]"
10
+ :style="computedStyle"
11
+ aria-hidden="true"
6
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>
7
19
  </template>
8
20
 
9
21
  <script lang="ts" setup>
10
- import { computed, resolveComponent } from "vue";
22
+ import { computed, markRaw, onMounted, ref } from "vue";
23
+ import type { IconSize, IconVariant } from "./types";
24
+ import type { Component } from "vue";
25
+ import { useIcon } from "./composables";
11
26
 
12
- export interface Props {
27
+ interface Props {
28
+ /**
29
+ * Lucide icon name or reference
30
+ */
13
31
  icon: string;
14
- size?: "xs" | "s" | "m" | "l" | "xl" | "xxl" | "xxxl";
15
- variant?: "warning" | "danger" | "success";
32
+
33
+ /**
34
+ * Icon size
35
+ */
36
+ size?: IconSize;
37
+
38
+ /**
39
+ * Icon color variant
40
+ */
41
+ variant?: IconVariant;
42
+
43
+ /**
44
+ * Stroke width for SVG
45
+ */
16
46
  strokeWidth?: number;
47
+
48
+ /**
49
+ * Custom size in pixels
50
+ */
51
+ customSize?: number;
17
52
  }
18
53
 
19
54
  const props = withDefaults(defineProps<Props>(), {
20
55
  size: "m",
21
- strokeWidth: 2,
56
+ strokeWidth: 1.5,
22
57
  });
23
58
 
24
- // Normalize icon name to extract the base name without prefixes
59
+ // Check if using custom size to conditionally apply CSS class
60
+ const hasCustomSize = computed(() => typeof props.customSize === "number" && props.customSize > 0);
61
+
62
+ // Component reference for Lucide icon
63
+ const resolvedIconComponent = ref<Component | null>(null);
64
+
65
+ // Use the shared icon composable for consistent scaling
66
+ const { iconStyle } = useIcon({
67
+ type: "lucide",
68
+ size: props.size,
69
+ variant: props.variant,
70
+ customSize: props.customSize,
71
+ });
72
+
73
+ // Normalize the icon name for Lucide
25
74
  const normalizedIconName = computed(() => {
26
- if (!props.icon) return "";
75
+ if (!props.icon) return "HelpCircleIcon";
27
76
 
28
- // Remove lucide- prefix if present
29
- let baseName = props.icon;
30
- if (baseName.startsWith("lucide-")) {
31
- baseName = baseName.substring(7); // length of "lucide-"
77
+ // Handle removal of lucide- prefix
78
+ let name = props.icon;
79
+ if (name.startsWith("lucide-")) {
80
+ name = name.substring(7);
32
81
  }
33
82
 
34
- // Convert to PascalCase and add Icon suffix if needed
35
- // For example, convert "alert-triangle" to "AlertTriangle"
36
- if (baseName.includes("-")) {
37
- baseName = baseName
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
38
91
  .split("-")
39
92
  .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
40
93
  .join("");
41
- } else {
42
- baseName = baseName.charAt(0).toUpperCase() + baseName.slice(1);
43
94
  }
44
95
 
45
- // Add Icon suffix if not already present
46
- if (!baseName.endsWith("Icon")) {
47
- baseName += "Icon";
96
+ // Ensure first letter is capitalized
97
+ return name.charAt(0).toUpperCase() + name.slice(1);
98
+ });
99
+
100
+ // Combine the shared icon styles with Lucide-specific settings
101
+ const computedStyle = computed(() => {
102
+ const styles = { ...iconStyle.value };
103
+
104
+ if (props.strokeWidth) {
105
+ styles.strokeWidth = props.strokeWidth.toString();
48
106
  }
49
107
 
50
- return baseName;
51
- });
108
+ // If using custom size, make sure size is applied with !important
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
+ }
52
113
 
53
- // Try to resolve the icon component
54
- const resolvedIcon = computed(() => {
55
- if (!props.icon) return null;
114
+ return styles;
115
+ });
56
116
 
117
+ // Dynamically import the Lucide icon
118
+ onMounted(async () => {
57
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
58
124
  const iconName = normalizedIconName.value;
59
- const resolved = resolveComponent(iconName);
60
- return resolved !== iconName ? resolved : null;
61
- } catch (e) {
62
- console.error(`Failed to resolve Lucide icon: ${props.icon} (normalized: ${normalizedIconName.value})`, e);
63
- return null;
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);
64
132
  }
65
133
  });
66
134
  </script>
135
+
136
+ <style lang="scss">
137
+ .vc-lucide-icon {
138
+ display: inline-flex;
139
+ align-items: center;
140
+ justify-content: center;
141
+ vertical-align: middle;
142
+ font-size: inherit;
143
+
144
+ &--xs {
145
+ width: var(--icon-size-xs);
146
+ height: var(--icon-size-xs);
147
+ }
148
+
149
+ &--s {
150
+ width: var(--icon-size-s);
151
+ height: var(--icon-size-s);
152
+ }
153
+
154
+ &--m {
155
+ width: var(--icon-size-m);
156
+ height: var(--icon-size-m);
157
+ }
158
+
159
+ &--l {
160
+ width: var(--icon-size-l);
161
+ height: var(--icon-size-l);
162
+ }
163
+
164
+ &--xl {
165
+ width: var(--icon-size-xl);
166
+ height: var(--icon-size-xl);
167
+ }
168
+
169
+ &--xxl {
170
+ width: var(--icon-size-xxl);
171
+ height: var(--icon-size-xxl);
172
+ }
173
+
174
+ &--xxxl {
175
+ width: var(--icon-size-xxxl);
176
+ height: var(--icon-size-xxxl);
177
+ }
178
+
179
+ &--warning {
180
+ color: var(--icon-color-warning);
181
+ }
182
+
183
+ &--danger {
184
+ color: var(--icon-color-danger);
185
+ }
186
+
187
+ &--success {
188
+ color: var(--icon-color-success);
189
+ }
190
+
191
+ &__fallback {
192
+ font-style: normal;
193
+ color: currentColor;
194
+ }
195
+ }
196
+ </style>
@@ -1,61 +1,167 @@
1
1
  <template>
2
2
  <span
3
- :class="[iconClass, variant ? `vc-icon_${variant}` : '']"
3
+ :class="[
4
+ 'vc-material-icon',
5
+ !hasCustomSize && `vc-material-icon--${size}`,
6
+ variant ? `vc-material-icon--${variant}` : '',
7
+ materialIconClass,
8
+ ]"
4
9
  :style="computedStyle"
5
- >{{ normalizedIcon }}</span
10
+ aria-hidden="true"
6
11
  >
12
+ {{ icon }}
13
+ </span>
7
14
  </template>
8
15
 
9
16
  <script lang="ts" setup>
10
17
  import { computed } from "vue";
18
+ import type { IconSize, IconVariant } from "./types";
19
+ import { useIcon } from "./composables";
11
20
 
12
- export interface Props {
21
+ interface Props {
22
+ /**
23
+ * Material icon name
24
+ */
13
25
  icon: string;
14
- size?: "xs" | "s" | "m" | "l" | "xl" | "xxl" | "xxxl";
15
- variant?: "warning" | "danger" | "success";
26
+
27
+ /**
28
+ * Icon size
29
+ */
30
+ size?: IconSize;
31
+
32
+ /**
33
+ * Type of the Material icon (outlined, rounded, sharp)
34
+ */
16
35
  type?: "outlined" | "rounded" | "sharp";
36
+
37
+ /**
38
+ * Icon color variant
39
+ */
40
+ variant?: IconVariant;
41
+
42
+ /**
43
+ * Fill value (0-1)
44
+ */
17
45
  fill?: number;
46
+
47
+ /**
48
+ * Weight value (100-700)
49
+ */
18
50
  weight?: number;
51
+
52
+ /**
53
+ * Grade value (-25 to 200)
54
+ */
19
55
  grade?: number;
56
+
57
+ /**
58
+ * Custom size in pixels
59
+ */
60
+ customSize?: number;
20
61
  }
21
62
 
22
63
  const props = withDefaults(defineProps<Props>(), {
23
64
  size: "m",
24
65
  type: "outlined",
25
66
  fill: 0,
26
- weight: 200,
67
+ weight: 300,
27
68
  grade: 0,
28
69
  });
29
70
 
30
- // Font variation settings
31
- const computedStyle = computed(() => {
32
- return {
33
- fontVariationSettings: `'FILL' ${props.fill}, 'wght' ${props.weight}, 'GRAD' ${props.grade}`,
34
- };
35
- });
71
+ // Check if using custom size to conditionally apply CSS class
72
+ const hasCustomSize = computed(() => typeof props.customSize === "number" && props.customSize > 0);
36
73
 
37
- // Normalize icon name to remove any type suffixes that might have been missed
38
- const normalizedIcon = computed(() => {
39
- if (!props.icon) return "";
74
+ // Use the shared icon composable for consistent scaling
75
+ const { iconStyle } = useIcon({
76
+ type: "material",
77
+ size: props.size,
78
+ variant: props.variant,
79
+ customSize: props.customSize,
80
+ });
40
81
 
41
- // Remove material- prefix if present
42
- let iconName = props.icon;
43
- if (iconName.startsWith("material-")) {
44
- iconName = iconName.substring(9); // length of "material-"
82
+ // Compute the Google Material Symbols class based on type
83
+ const materialIconClass = computed(() => {
84
+ switch (props.type) {
85
+ case "rounded":
86
+ return "material-symbols-rounded";
87
+ case "sharp":
88
+ return "material-symbols-sharp";
89
+ case "outlined":
90
+ default:
91
+ return "material-symbols-outlined";
45
92
  }
46
-
47
- // Remove possible type suffixes if they still exist
48
- return iconName.replace(/-outlined$|-rounded$|-sharp$/, "");
49
93
  });
50
94
 
51
- // Material Symbols class based on type
52
- const iconClass = computed(() => {
53
- const typeClass = {
54
- outlined: "material-symbols-outlined",
55
- rounded: "material-symbols-rounded",
56
- sharp: "material-symbols-sharp",
57
- }[props.type];
95
+ // Combine the shared icon styles with Material-specific settings
96
+ const computedStyle = computed(() => {
97
+ const styles = { ...iconStyle.value };
98
+
99
+ // Apply Material variation settings
100
+ styles.fontVariationSettings = `'FILL' ${props.fill}, 'wght' ${props.weight}, 'GRAD' ${props.grade}`;
101
+
102
+ // If using custom size, make sure fontSize is applied with !important
103
+ if (hasCustomSize.value && styles.fontSize) {
104
+ styles.fontSize = `${styles.fontSize.replace("px", "")}px !important`;
105
+ }
58
106
 
59
- return [`vc-icon`, `vc-icon_${props.size}`, typeClass];
107
+ return styles;
60
108
  });
61
109
  </script>
110
+
111
+ <style lang="scss">
112
+ .vc-material-icon {
113
+ font-family: "Material Symbols Outlined";
114
+ font-weight: normal;
115
+ font-style: normal;
116
+ line-height: 1;
117
+ letter-spacing: normal;
118
+ text-transform: none;
119
+ display: inline-block;
120
+ white-space: nowrap;
121
+ word-wrap: normal;
122
+ direction: ltr;
123
+ -webkit-font-feature-settings: "liga";
124
+ -webkit-font-smoothing: antialiased;
125
+ font-size: inherit;
126
+
127
+ &--xs {
128
+ font-size: var(--icon-size-xs);
129
+ }
130
+
131
+ &--s {
132
+ font-size: var(--icon-size-s);
133
+ }
134
+
135
+ &--m {
136
+ font-size: var(--icon-size-m);
137
+ }
138
+
139
+ &--l {
140
+ font-size: var(--icon-size-l);
141
+ }
142
+
143
+ &--xl {
144
+ font-size: var(--icon-size-xl);
145
+ }
146
+
147
+ &--xxl {
148
+ font-size: var(--icon-size-xxl);
149
+ }
150
+
151
+ &--xxxl {
152
+ font-size: var(--icon-size-xxxl);
153
+ }
154
+
155
+ &--warning {
156
+ color: var(--icon-color-warning);
157
+ }
158
+
159
+ &--danger {
160
+ color: var(--icon-color-danger);
161
+ }
162
+
163
+ &--success {
164
+ color: var(--icon-color-success);
165
+ }
166
+ }
167
+ </style>
@@ -0,0 +1,168 @@
1
+ <template>
2
+ <svg
3
+ xmlns="http://www.w3.org/2000/svg"
4
+ :class="['vc-svg-icon', !hasCustomSize && `vc-svg-icon--${size}`, variant ? `vc-svg-icon--${variant}` : '']"
5
+ :style="computedStyle"
6
+ v-bind="$attrs"
7
+ >
8
+ <use
9
+ v-if="resolvedIconPath"
10
+ :xlink:href="resolvedIconPath"
11
+ />
12
+ </svg>
13
+ </template>
14
+
15
+ <script lang="ts" setup>
16
+ import { computed } from "vue";
17
+ import type { IconSize, IconVariant } from "./types";
18
+ import { useIcon } from "./composables";
19
+
20
+ defineOptions({
21
+ inheritAttrs: false,
22
+ });
23
+
24
+ interface Props {
25
+ /**
26
+ * Path to SVG icon or sprite
27
+ */
28
+ icon: string;
29
+
30
+ /**
31
+ * Icon size
32
+ */
33
+ size?: IconSize;
34
+
35
+ /**
36
+ * Variant for special coloring
37
+ */
38
+ variant?: IconVariant;
39
+
40
+ /**
41
+ * Base path prepended to icon path
42
+ */
43
+ basePath?: string;
44
+
45
+ /**
46
+ * Custom size in pixels
47
+ */
48
+ customSize?: number;
49
+
50
+ /**
51
+ * Stroke width for SVG icons
52
+ */
53
+ strokeWidth?: number;
54
+ }
55
+
56
+ const props = withDefaults(defineProps<Props>(), {
57
+ size: "m",
58
+ basePath: "/assets/icons",
59
+ });
60
+
61
+ // Check if using custom size to conditionally apply CSS class
62
+ const hasCustomSize = computed(() => typeof props.customSize === "number" && props.customSize > 0);
63
+
64
+ // Use the shared icon composable for consistent scaling
65
+ const { iconStyle } = useIcon({
66
+ type: "svg",
67
+ size: props.size,
68
+ variant: props.variant,
69
+ customSize: props.customSize,
70
+ });
71
+
72
+ // Compute the full path to the icon
73
+ const resolvedIconPath = computed(() => {
74
+ // Check if the icon is already a complete path
75
+ if (props.icon.startsWith("/") || props.icon.includes("://") || props.icon.startsWith("#")) {
76
+ return props.icon;
77
+ }
78
+
79
+ // Check if the icon is a reference to a sprite (contains #)
80
+ const hashIndex = props.icon.indexOf("#");
81
+ if (hashIndex > -1) {
82
+ const spritePath = props.icon.substring(0, hashIndex);
83
+ const iconId = props.icon.substring(hashIndex);
84
+ return `${props.basePath}/${spritePath}${iconId}`;
85
+ }
86
+
87
+ // Apply basePath for relative paths
88
+ return `${props.basePath}/${props.icon}`;
89
+ });
90
+
91
+ // Combine the shared icon styles with SVG-specific settings
92
+ const computedStyle = computed(() => {
93
+ const styles = { ...iconStyle.value };
94
+
95
+ if (props.strokeWidth) {
96
+ styles.strokeWidth = `${props.strokeWidth}`;
97
+ }
98
+
99
+ // If using custom size, make sure size is applied with !important
100
+ if (hasCustomSize.value) {
101
+ if (styles.width) styles.width = `${styles.width.replace("px", "")}px !important`;
102
+ if (styles.height) styles.height = `${styles.height.replace("px", "")}px !important`;
103
+ }
104
+
105
+ return styles;
106
+ });
107
+ </script>
108
+
109
+ <style lang="scss">
110
+ .vc-svg-icon {
111
+ display: inline-block;
112
+ width: 1em;
113
+ height: 1em;
114
+ stroke-width: 0;
115
+ stroke: currentColor;
116
+ fill: currentColor;
117
+ vertical-align: middle;
118
+ flex-shrink: 0;
119
+ font-size: inherit;
120
+
121
+ &--xs {
122
+ width: var(--icon-size-xs);
123
+ height: var(--icon-size-xs);
124
+ }
125
+
126
+ &--s {
127
+ width: var(--icon-size-s);
128
+ height: var(--icon-size-s);
129
+ }
130
+
131
+ &--m {
132
+ width: var(--icon-size-m);
133
+ height: var(--icon-size-m);
134
+ }
135
+
136
+ &--l {
137
+ width: var(--icon-size-l);
138
+ height: var(--icon-size-l);
139
+ }
140
+
141
+ &--xl {
142
+ width: var(--icon-size-xl);
143
+ height: var(--icon-size-xl);
144
+ }
145
+
146
+ &--xxl {
147
+ width: var(--icon-size-xxl);
148
+ height: var(--icon-size-xxl);
149
+ }
150
+
151
+ &--xxxl {
152
+ width: var(--icon-size-xxxl);
153
+ height: var(--icon-size-xxxl);
154
+ }
155
+
156
+ &--warning {
157
+ color: var(--icon-color-warning);
158
+ }
159
+
160
+ &--danger {
161
+ color: var(--icon-color-danger);
162
+ }
163
+
164
+ &--success {
165
+ color: var(--icon-color-success);
166
+ }
167
+ }
168
+ </style>
@@ -1,6 +1,7 @@
1
1
  import { ref } from "vue";
2
2
  import type { Meta, StoryObj } from "@storybook/vue3";
3
3
  import { VcWidget } from "./";
4
+ import { provideWidgetService } from "../../../../core/composables";
4
5
 
5
6
  /**
6
7
  * `VcWidget` is a component that represents a clickable widget with an icon, title, and optional badge.
@@ -10,6 +11,18 @@ const meta = {
10
11
  title: "Atoms/VcWidget",
11
12
  component: VcWidget,
12
13
  tags: ["autodocs"],
14
+ decorators: [
15
+ () => ({
16
+ setup() {
17
+ provideWidgetService();
18
+ },
19
+ template: `
20
+ <div>
21
+ <story />
22
+ </div>
23
+ `,
24
+ }),
25
+ ],
13
26
  argTypes: {
14
27
  icon: {
15
28
  description: "Icon to display in the widget (Font Awesome format or component name)",
@@ -539,7 +539,7 @@ function onSearch(event: Event) {
539
539
 
540
540
  &__field {
541
541
  @apply tw-border-none tw-outline-none tw-min-h-[var(--multivalue-height)] tw-bg-[color:var(--multivalue-background-color)]
542
- tw-min-w-[120px] tw-box-border placeholder:tw-text-[color:var(--multivalue-placeholder-color)] tw-text-sm tw-rounded-[var(--multivalue-border-radius)];
542
+ tw-flex-grow tw-flex-shrink tw-w-auto tw-box-border placeholder:tw-text-[color:var(--multivalue-placeholder-color)] tw-text-sm tw-rounded-[var(--multivalue-border-radius)];
543
543
 
544
544
  &::-webkit-input-placeholder {
545
545
  @apply tw-text-[color:var(--multivalue-placeholder-color)];