@eturnity/eturnity_reusable_components 9.19.8 → 9.19.10
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
|
@@ -250,7 +250,12 @@
|
|
|
250
250
|
const icon = reactive({ html: '' })
|
|
251
251
|
|
|
252
252
|
const loadSvg = async () => {
|
|
253
|
-
|
|
253
|
+
const raw = props.name
|
|
254
|
+
if (raw == null || String(raw).trim() === '') {
|
|
255
|
+
icon.html = ''
|
|
256
|
+
return
|
|
257
|
+
}
|
|
258
|
+
let svgString = await fetchIcon(String(raw).toLowerCase())
|
|
254
259
|
if (props.svgRotation) svgString = rotateSvg(svgString, props.svgRotation)
|
|
255
260
|
icon.html = svgString
|
|
256
261
|
}
|
|
@@ -1,23 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load SVG icon markup by file stem (lowercase), matching files in
|
|
3
|
+
* `src/assets/svgIcons/<stem>.svg`.
|
|
4
|
+
*
|
|
5
|
+
* Uses `import.meta.glob` instead of `new URL(..., import.meta.url)` + `fetch`
|
|
6
|
+
* so Vite does not emit a broken asset URL when this package is linked via
|
|
7
|
+
* `@fs/...` (which previously produced requests like `.../icon/undefined`).
|
|
8
|
+
*/
|
|
9
|
+
const rawIconModules = import.meta.glob('../../assets/svgIcons/*.svg', {
|
|
10
|
+
query: '?raw',
|
|
11
|
+
import: 'default',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const iconLoadersByStem = {}
|
|
15
|
+
for (const path of Object.keys(rawIconModules)) {
|
|
16
|
+
const normalized = path.replace(/\\/g, '/')
|
|
17
|
+
const match = normalized.match(/\/([^/]+)\.svg$/i)
|
|
18
|
+
if (!match) continue
|
|
19
|
+
iconLoadersByStem[match[1].toLowerCase()] = rawIconModules[path]
|
|
20
|
+
}
|
|
21
|
+
|
|
1
22
|
const iconCache = {}
|
|
2
23
|
|
|
3
24
|
export const fetchIcon = async (fileName) => {
|
|
4
|
-
if (
|
|
5
|
-
|
|
25
|
+
if (fileName == null) {
|
|
26
|
+
console.warn('fetchIcon called with null or undefined fileName')
|
|
27
|
+
return ''
|
|
6
28
|
}
|
|
7
29
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
).href
|
|
30
|
+
const stem = String(fileName).trim().toLowerCase()
|
|
31
|
+
if (!stem) {
|
|
32
|
+
return ''
|
|
33
|
+
}
|
|
13
34
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
35
|
+
if (iconCache[stem]) {
|
|
36
|
+
return iconCache[stem]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const loader = iconLoadersByStem[stem]
|
|
40
|
+
if (!loader) {
|
|
41
|
+
console.error(`Unknown icon SVG: ${stem}.svg`)
|
|
42
|
+
return ''
|
|
43
|
+
}
|
|
18
44
|
|
|
45
|
+
try {
|
|
46
|
+
const rawFile = await loader()
|
|
47
|
+
iconCache[stem] = rawFile
|
|
19
48
|
return rawFile
|
|
20
49
|
} catch (error) {
|
|
21
|
-
console.error(`Failed to load ${
|
|
50
|
+
console.error(`Failed to load ${stem}.svg`, error)
|
|
51
|
+
return ''
|
|
22
52
|
}
|
|
23
53
|
}
|
|
@@ -137,11 +137,16 @@
|
|
|
137
137
|
:is-disabled="item.isDisabled"
|
|
138
138
|
@click="
|
|
139
139
|
!item.isDisabled &&
|
|
140
|
-
|
|
140
|
+
$emit('on-menu-item-click', { item })
|
|
141
141
|
"
|
|
142
142
|
>
|
|
143
143
|
<IconCell :is-collapsed="isCollapsed">
|
|
144
|
+
<NavMenuStatusDot
|
|
145
|
+
v-if="item.statusDotBackgroundColor"
|
|
146
|
+
:background-color="item.statusDotBackgroundColor"
|
|
147
|
+
/>
|
|
144
148
|
<IconComponent
|
|
149
|
+
v-if="item.icon"
|
|
145
150
|
:color="
|
|
146
151
|
item.id === activeItemId
|
|
147
152
|
? theme.semanticColors.purple[500]
|
|
@@ -169,7 +174,7 @@
|
|
|
169
174
|
type="tertiary"
|
|
170
175
|
@click="
|
|
171
176
|
!item.isDisabled &&
|
|
172
|
-
|
|
177
|
+
$emit('on-menu-item-click', { item })
|
|
173
178
|
"
|
|
174
179
|
/>
|
|
175
180
|
</template>
|
|
@@ -186,7 +191,12 @@
|
|
|
186
191
|
@click="!item.isDisabled && toggleDropdown(item.id)"
|
|
187
192
|
>
|
|
188
193
|
<IconCell :is-collapsed="isCollapsed">
|
|
194
|
+
<NavMenuStatusDot
|
|
195
|
+
v-if="item.statusDotBackgroundColor"
|
|
196
|
+
:background-color="item.statusDotBackgroundColor"
|
|
197
|
+
/>
|
|
189
198
|
<IconComponent
|
|
199
|
+
v-if="item.icon"
|
|
190
200
|
:color="
|
|
191
201
|
item.id === activeParentId
|
|
192
202
|
? theme.semanticColors.purple[500]
|
|
@@ -234,7 +244,7 @@
|
|
|
234
244
|
:is-disabled="sub.isDisabled"
|
|
235
245
|
@click="
|
|
236
246
|
!sub.isDisabled &&
|
|
237
|
-
|
|
247
|
+
$emit('on-menu-item-click', { item: sub })
|
|
238
248
|
"
|
|
239
249
|
>
|
|
240
250
|
<span>{{ sub.name }}</span>
|
|
@@ -297,8 +307,8 @@
|
|
|
297
307
|
p.isCollapsed
|
|
298
308
|
? `${NAV_SIDEBAR_COLLAPSED_OUTER_WIDTH_PX}px`
|
|
299
309
|
: p.expandedWidth
|
|
300
|
-
|
|
301
|
-
|
|
310
|
+
? `${p.expandedWidth}px`
|
|
311
|
+
: 'max-content'};
|
|
302
312
|
min-width: ${(p) =>
|
|
303
313
|
p.isCollapsed ? `${NAV_SIDEBAR_COLLAPSED_OUTER_WIDTH_PX}px` : '0'};
|
|
304
314
|
border-right: 1px solid ${(p) => p.theme.semanticColors.grey[300]};
|
|
@@ -486,9 +496,23 @@
|
|
|
486
496
|
justify-content: center;
|
|
487
497
|
flex-shrink: 0;
|
|
488
498
|
width: 24px;
|
|
499
|
+
position: relative;
|
|
489
500
|
${(p) => p.isCollapsed && 'width: 100%;'}
|
|
490
501
|
`
|
|
491
502
|
|
|
503
|
+
const NavMenuStatusDotAttrs = { backgroundColor: String }
|
|
504
|
+
const NavMenuStatusDot = styled('div', NavMenuStatusDotAttrs)`
|
|
505
|
+
position: absolute;
|
|
506
|
+
z-index: 1;
|
|
507
|
+
background: ${(p) =>
|
|
508
|
+
p.backgroundColor || p.theme.semanticColors.green[500]};
|
|
509
|
+
width: 8px;
|
|
510
|
+
height: 8px;
|
|
511
|
+
border-radius: 100%;
|
|
512
|
+
top: -2px;
|
|
513
|
+
right: 0;
|
|
514
|
+
`
|
|
515
|
+
|
|
492
516
|
const ItemLabel = styled.div`
|
|
493
517
|
white-space: nowrap;
|
|
494
518
|
font-size: 14px;
|
|
@@ -738,6 +762,7 @@
|
|
|
738
762
|
ItemList,
|
|
739
763
|
MenuItem,
|
|
740
764
|
IconCell,
|
|
765
|
+
NavMenuStatusDot,
|
|
741
766
|
ItemLabel,
|
|
742
767
|
ChevronCell,
|
|
743
768
|
CollapseWrapper,
|