@shival99/z-ui 2.2.5 → 2.3.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/assets/css/base.css +4 -0
- package/assets/css/overlay.css +82 -0
- package/assets/css/tailwind.css +1 -0
- package/assets/css/themes/hospital.css +28 -2
- package/fesm2022/shival99-z-ui-components-z-button-group.mjs +15 -13
- package/fesm2022/shival99-z-ui-components-z-button-group.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-button.mjs +2 -2
- package/fesm2022/shival99-z-ui-components-z-button.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-calendar.mjs +23 -17
- package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-command.mjs +10 -24
- package/fesm2022/shival99-z-ui-components-z-command.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-drawer.mjs +61 -70
- package/fesm2022/shival99-z-ui-components-z-drawer.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-gallery.mjs +6 -8
- package/fesm2022/shival99-z-ui-components-z-gallery.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-icon.mjs +227 -11
- package/fesm2022/shival99-z-ui-components-z-icon.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-marquee.mjs +19 -4
- package/fesm2022/shival99-z-ui-components-z-marquee.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-menu.mjs +7 -7
- package/fesm2022/shival99-z-ui-components-z-menu.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-modal.mjs +45 -62
- package/fesm2022/shival99-z-ui-components-z-modal.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-overlay.mjs +363 -0
- package/fesm2022/shival99-z-ui-components-z-overlay.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-popover.mjs +94 -378
- package/fesm2022/shival99-z-ui-components-z-popover.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-skeleton.mjs +14 -3
- package/fesm2022/shival99-z-ui-components-z-skeleton.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-table.mjs +42 -16
- package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-tabs.mjs +85 -7
- package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-toast.mjs +32 -25
- package/fesm2022/shival99-z-ui-components-z-toast.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-components-z-tooltip.mjs +52 -222
- package/fesm2022/shival99-z-ui-components-z-tooltip.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-providers.mjs +9 -2
- package/fesm2022/shival99-z-ui-providers.mjs.map +1 -1
- package/fesm2022/shival99-z-ui-services.mjs +203 -98
- package/fesm2022/shival99-z-ui-services.mjs.map +1 -1
- package/package.json +9 -1
- package/types/shival99-z-ui-components-z-autocomplete.d.ts +1 -1
- package/types/shival99-z-ui-components-z-button-group.d.ts +12 -11
- package/types/shival99-z-ui-components-z-button.d.ts +2 -1
- package/types/shival99-z-ui-components-z-calendar.d.ts +4 -4
- package/types/shival99-z-ui-components-z-command.d.ts +2 -4
- package/types/shival99-z-ui-components-z-drawer.d.ts +22 -16
- package/types/shival99-z-ui-components-z-editor.d.ts +1 -1
- package/types/shival99-z-ui-components-z-gallery.d.ts +3 -3
- package/types/shival99-z-ui-components-z-icon.d.ts +38 -6
- package/types/shival99-z-ui-components-z-marquee.d.ts +7 -1
- package/types/shival99-z-ui-components-z-modal.d.ts +53 -53
- package/types/shival99-z-ui-components-z-overlay.d.ts +145 -0
- package/types/shival99-z-ui-components-z-popover.d.ts +7 -15
- package/types/shival99-z-ui-components-z-qrcode.d.ts +1 -1
- package/types/shival99-z-ui-components-z-select.d.ts +1 -1
- package/types/shival99-z-ui-components-z-skeleton.d.ts +2 -0
- package/types/shival99-z-ui-components-z-table.d.ts +7 -3
- package/types/shival99-z-ui-components-z-tabs.d.ts +13 -3
- package/types/shival99-z-ui-components-z-toast.d.ts +7 -1
- package/types/shival99-z-ui-components-z-tooltip.d.ts +9 -7
- package/types/shival99-z-ui-components-z-upload.d.ts +3 -3
- package/types/shival99-z-ui-providers.d.ts +3 -1
- package/types/shival99-z-ui-services.d.ts +73 -37
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { NgComponentOutlet } from '@angular/common';
|
|
2
1
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { isDevMode, input, signal, computed, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, makeEnvironmentProviders, inject } from '@angular/core';
|
|
2
|
+
import { isDevMode, input, signal, computed, viewChild, ViewContainerRef, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, makeEnvironmentProviders, inject } from '@angular/core';
|
|
4
3
|
import { NgIconComponent, provideNgIconLoader, withCaching } from '@ng-icons/core';
|
|
5
4
|
import { zMergeClasses } from '@shival99/z-ui/utils';
|
|
6
5
|
import * as animatedIcons from 'ng-animated-icons';
|
|
@@ -109,6 +108,7 @@ class ZIconComponent {
|
|
|
109
108
|
...(ngDevMode ? [{ debugName: "_svgFetchError" }] : /* istanbul ignore next */ []));
|
|
110
109
|
zClasses = computed(() => zMergeClasses(zIconVariants({ zSize: this.zSize() }), this.class(), this.zStrokeWidth() === 0 ? 'stroke-none' : '', 'inline-flex shrink-0'), /* @ts-ignore */
|
|
111
110
|
...(ngDevMode ? [{ debugName: "zClasses" }] : /* istanbul ignore next */ []));
|
|
111
|
+
animatedIconHost = viewChild('animatedIconHost', { ...(ngDevMode ? { debugName: "animatedIconHost" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
112
112
|
animatedIcon = computed(() => {
|
|
113
113
|
const animatedType = this.zAnimatedType();
|
|
114
114
|
if (!animatedType) {
|
|
@@ -117,13 +117,19 @@ class ZIconComponent {
|
|
|
117
117
|
return getZAnimatedIconComponent(animatedType);
|
|
118
118
|
}, /* @ts-ignore */
|
|
119
119
|
...(ngDevMode ? [{ debugName: "animatedIcon" }] : /* istanbul ignore next */ []));
|
|
120
|
-
|
|
120
|
+
_animatedIconInputs = computed(() => ({
|
|
121
121
|
animate: this.shouldAnimate(),
|
|
122
122
|
color: 'currentColor',
|
|
123
123
|
size: Number(this.normalizedSize()),
|
|
124
124
|
strokeWidth: this.zStrokeWidth(),
|
|
125
125
|
}), /* @ts-ignore */
|
|
126
|
-
...(ngDevMode ? [{ debugName: "
|
|
126
|
+
...(ngDevMode ? [{ debugName: "_animatedIconInputs" }] : /* istanbul ignore next */ []));
|
|
127
|
+
_animatedIconRef = null;
|
|
128
|
+
_animatedIconType = null;
|
|
129
|
+
_animatedIconListenerCleanup = null;
|
|
130
|
+
_animatedIconRestartTimeoutId = null;
|
|
131
|
+
_isPersistentAnimate = computed(() => this.zAnimationTrigger() === 'always' || this.zAnimate(), /* @ts-ignore */
|
|
132
|
+
...(ngDevMode ? [{ debugName: "_isPersistentAnimate" }] : /* istanbul ignore next */ []));
|
|
127
133
|
shouldAnimate = computed(() => {
|
|
128
134
|
const trigger = this.zAnimationTrigger();
|
|
129
135
|
if (trigger === 'always' || this.zAnimate()) {
|
|
@@ -142,6 +148,33 @@ class ZIconComponent {
|
|
|
142
148
|
}, /* @ts-ignore */
|
|
143
149
|
...(ngDevMode ? [{ debugName: "shouldAnimate" }] : /* istanbul ignore next */ []));
|
|
144
150
|
constructor() {
|
|
151
|
+
effect(() => {
|
|
152
|
+
const host = this.animatedIconHost();
|
|
153
|
+
const type = this.animatedIcon();
|
|
154
|
+
if (!host) {
|
|
155
|
+
this._destroyAnimatedIconRef();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (type !== this._animatedIconType) {
|
|
159
|
+
this._destroyAnimatedIconRef();
|
|
160
|
+
this._animatedIconType = type;
|
|
161
|
+
host.clear();
|
|
162
|
+
if (type) {
|
|
163
|
+
this._animatedIconRef = host.createComponent(type);
|
|
164
|
+
this._attachAnimatedIconLoopListener(this._animatedIconRef);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const ref = this._animatedIconRef;
|
|
168
|
+
if (ref) {
|
|
169
|
+
const inputs = this._animatedIconInputs();
|
|
170
|
+
for (const [key, value] of Object.entries(inputs)) {
|
|
171
|
+
ref.setInput(key, value);
|
|
172
|
+
}
|
|
173
|
+
// Signal inputs set imperatively via setInput() don't reliably schedule
|
|
174
|
+
// change detection for a dynamically created OnPush child, so force it.
|
|
175
|
+
ref.changeDetectorRef.detectChanges();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
145
178
|
effect(onCleanup => {
|
|
146
179
|
const svgInput = this.zSvg().trim();
|
|
147
180
|
if (!svgInput) {
|
|
@@ -202,6 +235,45 @@ class ZIconComponent {
|
|
|
202
235
|
});
|
|
203
236
|
});
|
|
204
237
|
}
|
|
238
|
+
_destroyAnimatedIconRef() {
|
|
239
|
+
this._cancelAnimatedIconRestart();
|
|
240
|
+
this._animatedIconListenerCleanup?.();
|
|
241
|
+
this._animatedIconListenerCleanup = null;
|
|
242
|
+
this._animatedIconRef?.destroy();
|
|
243
|
+
this._animatedIconRef = null;
|
|
244
|
+
this._animatedIconType = null;
|
|
245
|
+
}
|
|
246
|
+
_attachAnimatedIconLoopListener(ref) {
|
|
247
|
+
const nativeElement = ref.location.nativeElement;
|
|
248
|
+
const handler = () => this._restartAnimatedIconLoop(ref);
|
|
249
|
+
nativeElement.addEventListener('animationend', handler);
|
|
250
|
+
this._animatedIconListenerCleanup = () => nativeElement.removeEventListener('animationend', handler);
|
|
251
|
+
}
|
|
252
|
+
_restartAnimatedIconLoop(ref) {
|
|
253
|
+
if (this._animatedIconRef !== ref || !this._isPersistentAnimate()) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
this._cancelAnimatedIconRestart();
|
|
257
|
+
ref.setInput('animate', false);
|
|
258
|
+
ref.changeDetectorRef.detectChanges();
|
|
259
|
+
this._animatedIconRestartTimeoutId = setTimeout(() => {
|
|
260
|
+
this._animatedIconRestartTimeoutId = null;
|
|
261
|
+
if (this._animatedIconRef !== ref || !this._isPersistentAnimate()) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
ref.setInput('animate', true);
|
|
265
|
+
ref.changeDetectorRef.detectChanges();
|
|
266
|
+
}, 50);
|
|
267
|
+
}
|
|
268
|
+
_cancelAnimatedIconRestart() {
|
|
269
|
+
if (this._animatedIconRestartTimeoutId !== null) {
|
|
270
|
+
clearTimeout(this._animatedIconRestartTimeoutId);
|
|
271
|
+
this._animatedIconRestartTimeoutId = null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
ngOnDestroy() {
|
|
275
|
+
this._destroyAnimatedIconRef();
|
|
276
|
+
}
|
|
205
277
|
_isRawSvg(value) {
|
|
206
278
|
return value.startsWith('<svg');
|
|
207
279
|
}
|
|
@@ -261,11 +333,11 @@ class ZIconComponent {
|
|
|
261
333
|
}
|
|
262
334
|
}
|
|
263
335
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: ZIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
264
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: ZIconComponent, isStandalone: true, selector: "z-icon, [z-icon]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zType: { classPropertyName: "zType", publicName: "zType", isSignal: true, isRequired: false, transformFunction: null }, zAnimatedType: { classPropertyName: "zAnimatedType", publicName: "zAnimatedType", isSignal: true, isRequired: false, transformFunction: null }, zAnimate: { classPropertyName: "zAnimate", publicName: "zAnimate", isSignal: true, isRequired: false, transformFunction: null }, zAnimationTrigger: { classPropertyName: "zAnimationTrigger", publicName: "zAnimationTrigger", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zStrokeWidth: { classPropertyName: "zStrokeWidth", publicName: "zStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, zSvg: { classPropertyName: "zSvg", publicName: "zSvg", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "setHoverActive(true)", "mouseleave": "setHoverActive(false)", "focusin": "setFocusActive(true)", "focusout": "setFocusActive(false)", "touchstart": "setTouchActive(true)", "touchend": "setTouchActive(false)" }, properties: { "class": "zClasses()", "style.width": "normalizedSize() + \"px\"", "style.height": "normalizedSize() + \"px\"" } }, ngImport: i0, template: "@if (animatedIcon()) {\n <ng-container
|
|
336
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: ZIconComponent, isStandalone: true, selector: "z-icon, [z-icon]", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zType: { classPropertyName: "zType", publicName: "zType", isSignal: true, isRequired: false, transformFunction: null }, zAnimatedType: { classPropertyName: "zAnimatedType", publicName: "zAnimatedType", isSignal: true, isRequired: false, transformFunction: null }, zAnimate: { classPropertyName: "zAnimate", publicName: "zAnimate", isSignal: true, isRequired: false, transformFunction: null }, zAnimationTrigger: { classPropertyName: "zAnimationTrigger", publicName: "zAnimationTrigger", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zStrokeWidth: { classPropertyName: "zStrokeWidth", publicName: "zStrokeWidth", isSignal: true, isRequired: false, transformFunction: null }, zSvg: { classPropertyName: "zSvg", publicName: "zSvg", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "setHoverActive(true)", "mouseleave": "setHoverActive(false)", "focusin": "setFocusActive(true)", "focusout": "setFocusActive(false)", "touchstart": "setTouchActive(true)", "touchend": "setTouchActive(false)" }, properties: { "class": "zClasses()", "style.width": "normalizedSize() + \"px\"", "style.height": "normalizedSize() + \"px\"" } }, viewQueries: [{ propertyName: "animatedIconHost", first: true, predicate: ["animatedIconHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@if (animatedIcon()) {\n <ng-container #animatedIconHost />\n} @else if (resolvedSvg()) {\n <ng-icon [svg]=\"resolvedSvg()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n} @else if (!zSvg()) {\n <ng-icon [name]=\"zType()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n}\n", dependencies: [{ kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
265
337
|
}
|
|
266
338
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: ZIconComponent, decorators: [{
|
|
267
339
|
type: Component,
|
|
268
|
-
args: [{ selector: 'z-icon, [z-icon]', imports: [NgIconComponent
|
|
340
|
+
args: [{ selector: 'z-icon, [z-icon]', imports: [NgIconComponent], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
269
341
|
'[class]': 'zClasses()',
|
|
270
342
|
'[style.width]': 'normalizedSize() + "px"',
|
|
271
343
|
'[style.height]': 'normalizedSize() + "px"',
|
|
@@ -275,9 +347,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImpor
|
|
|
275
347
|
'(focusout)': 'setFocusActive(false)',
|
|
276
348
|
'(touchstart)': 'setTouchActive(true)',
|
|
277
349
|
'(touchend)': 'setTouchActive(false)',
|
|
278
|
-
}, template: "@if (animatedIcon()) {\n <ng-container
|
|
279
|
-
}], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zType", required: false }] }], zAnimatedType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimatedType", required: false }] }], zAnimate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimate", required: false }] }], zAnimationTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimationTrigger", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "zStrokeWidth", required: false }] }], zSvg: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSvg", required: false }] }] } });
|
|
350
|
+
}, template: "@if (animatedIcon()) {\n <ng-container #animatedIconHost />\n} @else if (resolvedSvg()) {\n <ng-icon [svg]=\"resolvedSvg()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n} @else if (!zSvg()) {\n <ng-icon [name]=\"zType()\" [size]=\"normalizedSize()\" [strokeWidth]=\"zStrokeWidth()\" />\n}\n" }]
|
|
351
|
+
}], ctorParameters: () => [], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zType", required: false }] }], zAnimatedType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimatedType", required: false }] }], zAnimate: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimate", required: false }] }], zAnimationTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAnimationTrigger", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zStrokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "zStrokeWidth", required: false }] }], zSvg: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSvg", required: false }] }], animatedIconHost: [{ type: i0.ViewChild, args: ['animatedIconHost', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
280
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Optional bundled icon overrides used before the CDN loader fallback.
|
|
355
|
+
*
|
|
356
|
+
* The default registry is intentionally empty so icon families remain lazy.
|
|
357
|
+
*/
|
|
281
358
|
const Z_ICONS = {};
|
|
282
359
|
|
|
283
360
|
/**
|
|
@@ -298,6 +375,14 @@ function normalizeLucideSvg(svg) {
|
|
|
298
375
|
const cssVar = 'style="stroke-width: var(--ng-icon__stroke-width, 2)"';
|
|
299
376
|
return svg.replace(/stroke-width="[^"]*"/gi, cssVar);
|
|
300
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Normalizes line-based SVG families to the shared ng-icon stroke variable.
|
|
380
|
+
* This keeps `zStrokeWidth` consistent across the different icon sources.
|
|
381
|
+
*/
|
|
382
|
+
function normalizeStrokeSvg(svg) {
|
|
383
|
+
const cssVar = 'style="stroke-width: var(--ng-icon__stroke-width, 2)"';
|
|
384
|
+
return svg.replace(/stroke-width="[^"]*"/gi, cssVar);
|
|
385
|
+
}
|
|
301
386
|
/**
|
|
302
387
|
* Phosphor SVGs already ship with fill="currentColor" and no stroke-width,
|
|
303
388
|
* so no normalization is required. Kept as an explicit passthrough for parity
|
|
@@ -382,6 +467,10 @@ async function getFallbackIcon(name) {
|
|
|
382
467
|
// console.warn(`[ZIcon] Using bundled fallback for "${name}"`);
|
|
383
468
|
return icon;
|
|
384
469
|
}
|
|
470
|
+
const familyIcon = await getFallbackIconFromFamily(name);
|
|
471
|
+
if (familyIcon) {
|
|
472
|
+
return familyIcon;
|
|
473
|
+
}
|
|
385
474
|
const lucideIcons = await import('@ng-icons/lucide');
|
|
386
475
|
const matchedIcon = Reflect.get(lucideIcons, name);
|
|
387
476
|
if (typeof matchedIcon === 'string') {
|
|
@@ -389,6 +478,54 @@ async function getFallbackIcon(name) {
|
|
|
389
478
|
}
|
|
390
479
|
return lucideIcons.lucideCircleHelp;
|
|
391
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* Resolves an icon from the local ng-icons package for CDN failure fallback.
|
|
483
|
+
* Dynamic imports keep the complete family out of the normal application path.
|
|
484
|
+
*/
|
|
485
|
+
async function getFallbackIconFromFamily(name) {
|
|
486
|
+
if (name.startsWith('tabler')) {
|
|
487
|
+
const icons = name.endsWith('Fill')
|
|
488
|
+
? await import('@ng-icons/tabler-icons/fill')
|
|
489
|
+
: await import('@ng-icons/tabler-icons');
|
|
490
|
+
const icon = Reflect.get(icons, name);
|
|
491
|
+
return typeof icon === 'string' ? icon : null;
|
|
492
|
+
}
|
|
493
|
+
if (name.startsWith('hero')) {
|
|
494
|
+
const icons = name.endsWith('Micro')
|
|
495
|
+
? await import('@ng-icons/heroicons/micro')
|
|
496
|
+
: name.endsWith('Mini')
|
|
497
|
+
? await import('@ng-icons/heroicons/mini')
|
|
498
|
+
: name.endsWith('Solid')
|
|
499
|
+
? await import('@ng-icons/heroicons/solid')
|
|
500
|
+
: await import('@ng-icons/heroicons/outline');
|
|
501
|
+
const icon = Reflect.get(icons, name);
|
|
502
|
+
return typeof icon === 'string' ? icon : null;
|
|
503
|
+
}
|
|
504
|
+
if (name.startsWith('iconoir')) {
|
|
505
|
+
const icons = name.endsWith('Solid')
|
|
506
|
+
? await import('@ng-icons/iconoir/solid')
|
|
507
|
+
: await import('@ng-icons/iconoir/regular');
|
|
508
|
+
const icon = Reflect.get(icons, name);
|
|
509
|
+
return typeof icon === 'string' ? icon : null;
|
|
510
|
+
}
|
|
511
|
+
if (name.startsWith('phosphor')) {
|
|
512
|
+
const { weight } = convertPhosphorIconName(name);
|
|
513
|
+
const icons = weight === 'bold'
|
|
514
|
+
? await import('@ng-icons/phosphor-icons/bold')
|
|
515
|
+
: weight === 'fill'
|
|
516
|
+
? await import('@ng-icons/phosphor-icons/fill')
|
|
517
|
+
: weight === 'light'
|
|
518
|
+
? await import('@ng-icons/phosphor-icons/light')
|
|
519
|
+
: weight === 'thin'
|
|
520
|
+
? await import('@ng-icons/phosphor-icons/thin')
|
|
521
|
+
: weight === 'duotone'
|
|
522
|
+
? await import('@ng-icons/phosphor-icons/duotone')
|
|
523
|
+
: await import('@ng-icons/phosphor-icons/regular');
|
|
524
|
+
const icon = Reflect.get(icons, name);
|
|
525
|
+
return typeof icon === 'string' ? icon : null;
|
|
526
|
+
}
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
392
529
|
/**
|
|
393
530
|
* Converts ng-icons icon name to Lucide CDN format.
|
|
394
531
|
* Examples:
|
|
@@ -461,6 +598,67 @@ function convertPhosphorIconName(name) {
|
|
|
461
598
|
const iconName = weight === 'regular' ? kebab : `${kebab}-${weight}`;
|
|
462
599
|
return { weight, iconName };
|
|
463
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Converts a Tabler icon name to its CDN folder and kebab-case asset name.
|
|
603
|
+
* Tabler's filled package uses a `Fill` suffix in its ng-icons exports.
|
|
604
|
+
*/
|
|
605
|
+
function convertTablerIconName(name) {
|
|
606
|
+
const isFilled = name.endsWith('Fill');
|
|
607
|
+
const iconPart = (isFilled ? name.slice(0, -'Fill'.length) : name).replace(/^tabler/, '');
|
|
608
|
+
const iconName = iconPart
|
|
609
|
+
.replace(/([A-Z])/g, '-$1')
|
|
610
|
+
.replace(/(\d+)/g, '-$1')
|
|
611
|
+
.replace(/(\d)([a-z])/g, '$1-$2')
|
|
612
|
+
.toLowerCase()
|
|
613
|
+
.replace(/^-/, '')
|
|
614
|
+
.replace(/--+/g, '-');
|
|
615
|
+
return { style: isFilled ? 'filled' : 'outline', iconName };
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Converts a Heroicons export name to its official size/style asset path.
|
|
619
|
+
* Mini and micro exports are solid-only 20px and 16px variants respectively.
|
|
620
|
+
*/
|
|
621
|
+
function convertHeroIconName(name) {
|
|
622
|
+
let iconPart = name.replace(/^hero/, '');
|
|
623
|
+
let size = '24';
|
|
624
|
+
let style = 'outline';
|
|
625
|
+
if (iconPart.endsWith('Micro')) {
|
|
626
|
+
size = '16';
|
|
627
|
+
style = 'solid';
|
|
628
|
+
iconPart = iconPart.slice(0, -'Micro'.length);
|
|
629
|
+
}
|
|
630
|
+
else if (iconPart.endsWith('Mini')) {
|
|
631
|
+
size = '20';
|
|
632
|
+
style = 'solid';
|
|
633
|
+
iconPart = iconPart.slice(0, -'Mini'.length);
|
|
634
|
+
}
|
|
635
|
+
else if (iconPart.endsWith('Solid')) {
|
|
636
|
+
style = 'solid';
|
|
637
|
+
iconPart = iconPart.slice(0, -'Solid'.length);
|
|
638
|
+
}
|
|
639
|
+
const iconName = iconPart
|
|
640
|
+
.replace(/([A-Z])/g, '-$1')
|
|
641
|
+
.replace(/(\d+)/g, '-$1')
|
|
642
|
+
.replace(/(\d)([a-z])/g, '$1-$2')
|
|
643
|
+
.toLowerCase()
|
|
644
|
+
.replace(/^-/, '')
|
|
645
|
+
.replace(/--+/g, '-');
|
|
646
|
+
return { size, style, iconName };
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Converts an Iconoir export name to its style folder and kebab-case asset.
|
|
650
|
+
*/
|
|
651
|
+
function convertIconoirIconName(name) {
|
|
652
|
+
const isSolid = name.endsWith('Solid');
|
|
653
|
+
const iconPart = (isSolid ? name.slice(0, -'Solid'.length) : name).replace(/^iconoir/, '');
|
|
654
|
+
const iconName = iconPart
|
|
655
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
656
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
657
|
+
.toLowerCase()
|
|
658
|
+
.replace(/^-/, '')
|
|
659
|
+
.replace(/--+/g, '-');
|
|
660
|
+
return { style: isSolid ? 'solid' : 'regular', iconName };
|
|
661
|
+
}
|
|
464
662
|
/**
|
|
465
663
|
* Converts ng-icons-style Huge icon name to the @hugeicons/core-free-icons
|
|
466
664
|
* CDN module name. We expose icons with a `huge` prefix over the original
|
|
@@ -508,6 +706,9 @@ function convertBrandIconName(name) {
|
|
|
508
706
|
const LUCIDE_CDN_URL = 'https://cdn.jsdelivr.net/npm/lucide-static@latest/icons';
|
|
509
707
|
const SAX_CDN_URL = 'https://cdn.jsdelivr.net/gh/placetopay-org/iconsax-vue@main/src/Base';
|
|
510
708
|
const PHOSPHOR_CDN_URL = 'https://cdn.jsdelivr.net/npm/@phosphor-icons/core@latest/assets';
|
|
709
|
+
const TABLER_CDN_URL = 'https://cdn.jsdelivr.net/npm/@tabler/icons@latest/icons';
|
|
710
|
+
const HEROICONS_CDN_URL = 'https://cdn.jsdelivr.net/npm/heroicons@latest';
|
|
711
|
+
const ICONOIR_CDN_URL = 'https://cdn.jsdelivr.net/npm/iconoir@latest/icons';
|
|
511
712
|
const HUGE_CDN_URL = 'https://cdn.jsdelivr.net/npm/@hugeicons/core-free-icons@4.2.1/dist/esm';
|
|
512
713
|
const BRAND_CDN_URL = 'https://thesvg.org/icons';
|
|
513
714
|
const ICON_CDN_TIMEOUT_MS = 4000;
|
|
@@ -520,9 +721,9 @@ function retryIconRequest(error, retryCount) {
|
|
|
520
721
|
return timer(ICON_CDN_RETRY_DELAY_MS * retryCount);
|
|
521
722
|
}
|
|
522
723
|
/**
|
|
523
|
-
* Provides hybrid icon loading from CDN with fallback to
|
|
524
|
-
*
|
|
525
|
-
*
|
|
724
|
+
* Provides hybrid icon loading from CDN with fallback to local icon packages.
|
|
725
|
+
* The default path keeps full icon families lazy, while a CDN failure loads
|
|
726
|
+
* only the requested family's package as a fallback.
|
|
526
727
|
*
|
|
527
728
|
* @example
|
|
528
729
|
* ```typescript
|
|
@@ -593,6 +794,21 @@ function provideZIconLoader() {
|
|
|
593
794
|
const url = `${PHOSPHOR_CDN_URL}/${weight}/${iconName}.svg`;
|
|
594
795
|
return loadWithCache(name, url, http, normalizePhosphorSvg);
|
|
595
796
|
}
|
|
797
|
+
if (name.startsWith('tabler')) {
|
|
798
|
+
const { style, iconName } = convertTablerIconName(name);
|
|
799
|
+
const url = `${TABLER_CDN_URL}/${style}/${iconName}.svg`;
|
|
800
|
+
return loadWithCache(name, url, http, normalizeStrokeSvg);
|
|
801
|
+
}
|
|
802
|
+
if (name.startsWith('hero')) {
|
|
803
|
+
const { size, style, iconName } = convertHeroIconName(name);
|
|
804
|
+
const url = `${HEROICONS_CDN_URL}/${size}/${style}/${iconName}.svg`;
|
|
805
|
+
return loadWithCache(name, url, http, normalizeStrokeSvg);
|
|
806
|
+
}
|
|
807
|
+
if (name.startsWith('iconoir')) {
|
|
808
|
+
const { style, iconName } = convertIconoirIconName(name);
|
|
809
|
+
const url = `${ICONOIR_CDN_URL}/${style}/${iconName}.svg`;
|
|
810
|
+
return loadWithCache(name, url, http, normalizeStrokeSvg);
|
|
811
|
+
}
|
|
596
812
|
if (name.startsWith('huge')) {
|
|
597
813
|
const moduleName = convertHugeIconName(name);
|
|
598
814
|
const url = `${HUGE_CDN_URL}/${moduleName}.js`;
|