@haloduck/ui 2.0.9 → 2.0.11
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/fesm2022/haloduck-ui.mjs +232 -1
- package/fesm2022/haloduck-ui.mjs.map +1 -1
- package/index.d.ts +54 -3
- package/package.json +1 -1
package/fesm2022/haloduck-ui.mjs
CHANGED
|
@@ -2784,6 +2784,237 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
2784
2784
|
args: ['label']
|
|
2785
2785
|
}] } });
|
|
2786
2786
|
|
|
2787
|
+
class TabsComponent {
|
|
2788
|
+
tabs = [];
|
|
2789
|
+
selectedIndex = 0;
|
|
2790
|
+
layout = 'vertical';
|
|
2791
|
+
labelWidth = '';
|
|
2792
|
+
selectedIndexChange = new EventEmitter();
|
|
2793
|
+
label;
|
|
2794
|
+
ngOnChanges(changes) {
|
|
2795
|
+
if (changes['tabs']) {
|
|
2796
|
+
this.ensureSelectedInRange();
|
|
2797
|
+
}
|
|
2798
|
+
if (changes['selectedIndex']) {
|
|
2799
|
+
this.ensureSelectedInRange();
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
ngAfterViewInit() {
|
|
2803
|
+
// hide label if no content.
|
|
2804
|
+
if (this.label && this.label.nativeElement) {
|
|
2805
|
+
const hasContent = this.label.nativeElement.textContent?.trim();
|
|
2806
|
+
if (!hasContent) {
|
|
2807
|
+
this.label.nativeElement.style.display = 'none';
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
get current() {
|
|
2812
|
+
if (!this.tabs || this.tabs.length === 0)
|
|
2813
|
+
return null;
|
|
2814
|
+
const idx = Math.min(Math.max(this.selectedIndex, 0), this.tabs.length - 1);
|
|
2815
|
+
return this.tabs[idx];
|
|
2816
|
+
}
|
|
2817
|
+
select(index) {
|
|
2818
|
+
if (index < 0 || index >= this.tabs.length)
|
|
2819
|
+
return;
|
|
2820
|
+
this.selectedIndex = index;
|
|
2821
|
+
this.selectedIndexChange.emit(this.selectedIndex);
|
|
2822
|
+
}
|
|
2823
|
+
ensureSelectedInRange() {
|
|
2824
|
+
if (!this.tabs || this.tabs.length === 0) {
|
|
2825
|
+
this.selectedIndex = 0;
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
if (this.selectedIndex < 0)
|
|
2829
|
+
this.selectedIndex = 0;
|
|
2830
|
+
if (this.selectedIndex > this.tabs.length - 1)
|
|
2831
|
+
this.selectedIndex = this.tabs.length - 1;
|
|
2832
|
+
}
|
|
2833
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2834
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: TabsComponent, isStandalone: true, selector: "haloduck-tabs", inputs: { tabs: "tabs", selectedIndex: "selectedIndex", layout: "layout", labelWidth: "labelWidth" }, outputs: { selectedIndexChange: "selectedIndexChange" }, viewQueries: [{ propertyName: "label", first: true, predicate: ["label"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex gap-2 items-start w-full\" [ngClass]=\"{'flex-col': layout === 'vertical'}\">\n <label #label class=\"block text-sm/6 font-medium text-light-on-control dark:text-dark-on-control {{ labelWidth }}\" [ngClass]=\"{'w-full': layout === 'vertical'}\">\n <ng-content select=\"[slot=label]\"></ng-content>\n </label>\n\n <div class=\"flex-1 w-full\">\n <div class=\"flex items-center gap-1 border-b border-light-inactive dark:border-dark-inactive text-sm/6\">\n @for (tab of tabs; track tab; let i = $index) {\n <button type=\"button\"\n class=\"px-3 py-2 rounded-t-md\"\n [ngClass]=\"{\n 'text-light-on-control dark:text-dark-on-control': i !== selectedIndex,\n 'text-light-primary dark:text-dark-primary border-b-2 border-light-primary dark:border-dark-primary': i === selectedIndex\n }\"\n (click)=\"select(i)\">\n {{ tab.label }}\n </button>\n }\n </div>\n\n <div class=\"mt-3\">\n @if (current) {\n <ng-container *ngComponentOutlet=\"current!.component; inputs: current!.inputs || {}\"></ng-container>\n }\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"], exportAs: ["ngComponentOutlet"] }] });
|
|
2835
|
+
}
|
|
2836
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TabsComponent, decorators: [{
|
|
2837
|
+
type: Component,
|
|
2838
|
+
args: [{ selector: 'haloduck-tabs', imports: [CommonModule], template: "<div class=\"flex gap-2 items-start w-full\" [ngClass]=\"{'flex-col': layout === 'vertical'}\">\n <label #label class=\"block text-sm/6 font-medium text-light-on-control dark:text-dark-on-control {{ labelWidth }}\" [ngClass]=\"{'w-full': layout === 'vertical'}\">\n <ng-content select=\"[slot=label]\"></ng-content>\n </label>\n\n <div class=\"flex-1 w-full\">\n <div class=\"flex items-center gap-1 border-b border-light-inactive dark:border-dark-inactive text-sm/6\">\n @for (tab of tabs; track tab; let i = $index) {\n <button type=\"button\"\n class=\"px-3 py-2 rounded-t-md\"\n [ngClass]=\"{\n 'text-light-on-control dark:text-dark-on-control': i !== selectedIndex,\n 'text-light-primary dark:text-dark-primary border-b-2 border-light-primary dark:border-dark-primary': i === selectedIndex\n }\"\n (click)=\"select(i)\">\n {{ tab.label }}\n </button>\n }\n </div>\n\n <div class=\"mt-3\">\n @if (current) {\n <ng-container *ngComponentOutlet=\"current!.component; inputs: current!.inputs || {}\"></ng-container>\n }\n </div>\n </div>\n</div>\n" }]
|
|
2839
|
+
}], propDecorators: { tabs: [{
|
|
2840
|
+
type: Input
|
|
2841
|
+
}], selectedIndex: [{
|
|
2842
|
+
type: Input
|
|
2843
|
+
}], layout: [{
|
|
2844
|
+
type: Input
|
|
2845
|
+
}], labelWidth: [{
|
|
2846
|
+
type: Input
|
|
2847
|
+
}], selectedIndexChange: [{
|
|
2848
|
+
type: Output
|
|
2849
|
+
}], label: [{
|
|
2850
|
+
type: ViewChild,
|
|
2851
|
+
args: ['label']
|
|
2852
|
+
}] } });
|
|
2853
|
+
|
|
2854
|
+
class TagInputComponent {
|
|
2855
|
+
label;
|
|
2856
|
+
inputEl;
|
|
2857
|
+
placeholder = '';
|
|
2858
|
+
disabled = false;
|
|
2859
|
+
allowDuplicates = false;
|
|
2860
|
+
// Two-way binding support independent of CVA
|
|
2861
|
+
set value(tags) {
|
|
2862
|
+
if (Array.isArray(tags)) {
|
|
2863
|
+
this.tags = tags
|
|
2864
|
+
.map((t) => (t ?? '').trim())
|
|
2865
|
+
.filter((t) => t.length > 0);
|
|
2866
|
+
}
|
|
2867
|
+
else {
|
|
2868
|
+
this.tags = [];
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
valueChange = new EventEmitter();
|
|
2872
|
+
tags = [];
|
|
2873
|
+
inputValue = '';
|
|
2874
|
+
onChange = () => { };
|
|
2875
|
+
onTouched = () => { };
|
|
2876
|
+
writeValue(value) {
|
|
2877
|
+
if (Array.isArray(value)) {
|
|
2878
|
+
this.tags = value
|
|
2879
|
+
.map((t) => (t ?? '').trim())
|
|
2880
|
+
.filter((t) => t.length > 0);
|
|
2881
|
+
}
|
|
2882
|
+
else {
|
|
2883
|
+
this.tags = [];
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
registerOnChange(fn) {
|
|
2887
|
+
this.onChange = fn;
|
|
2888
|
+
}
|
|
2889
|
+
registerOnTouched(fn) {
|
|
2890
|
+
this.onTouched = fn;
|
|
2891
|
+
}
|
|
2892
|
+
setDisabledState(isDisabled) {
|
|
2893
|
+
this.disabled = isDisabled;
|
|
2894
|
+
}
|
|
2895
|
+
ngAfterViewInit() {
|
|
2896
|
+
// hide label if no projected content
|
|
2897
|
+
if (this.label && this.label.nativeElement) {
|
|
2898
|
+
const hasContent = this.label.nativeElement.textContent?.trim();
|
|
2899
|
+
if (!hasContent) {
|
|
2900
|
+
this.label.nativeElement.style.display = 'none';
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
focus() {
|
|
2905
|
+
this.inputEl?.nativeElement?.focus();
|
|
2906
|
+
}
|
|
2907
|
+
onInput(event) {
|
|
2908
|
+
const input = event.target;
|
|
2909
|
+
this.inputValue = input.value;
|
|
2910
|
+
this.onTouched();
|
|
2911
|
+
}
|
|
2912
|
+
onBlur() {
|
|
2913
|
+
if (this.disabled)
|
|
2914
|
+
return;
|
|
2915
|
+
this.inputValue = '';
|
|
2916
|
+
this.onTouched();
|
|
2917
|
+
}
|
|
2918
|
+
onKeydown(event) {
|
|
2919
|
+
if (this.disabled)
|
|
2920
|
+
return;
|
|
2921
|
+
// Commit on comma or Enter
|
|
2922
|
+
if (event.key === ',' || event.key === 'Enter') {
|
|
2923
|
+
event.preventDefault();
|
|
2924
|
+
this.commitCurrentInput();
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
// Backspace behavior
|
|
2928
|
+
if (event.key === 'Backspace') {
|
|
2929
|
+
if (this.inputValue.length > 0) {
|
|
2930
|
+
return; // default backspace in input
|
|
2931
|
+
}
|
|
2932
|
+
if (this.tags.length > 0) {
|
|
2933
|
+
event.preventDefault();
|
|
2934
|
+
this.removeTag(this.tags.length - 1);
|
|
2935
|
+
return;
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
removeTag(index) {
|
|
2940
|
+
if (this.disabled)
|
|
2941
|
+
return;
|
|
2942
|
+
if (index < 0 || index >= this.tags.length)
|
|
2943
|
+
return;
|
|
2944
|
+
this.tags = this.tags.filter((_, i) => i !== index);
|
|
2945
|
+
this.emitChanges();
|
|
2946
|
+
}
|
|
2947
|
+
commitCurrentInput() {
|
|
2948
|
+
const raw = this.inputValue.trim();
|
|
2949
|
+
if (!raw) {
|
|
2950
|
+
this.inputValue = '';
|
|
2951
|
+
return;
|
|
2952
|
+
}
|
|
2953
|
+
// If user pasted multiple comma-separated values, split and add all
|
|
2954
|
+
const parts = raw.split(',').map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2955
|
+
for (const part of parts) {
|
|
2956
|
+
this.addTag(part);
|
|
2957
|
+
}
|
|
2958
|
+
this.inputValue = '';
|
|
2959
|
+
}
|
|
2960
|
+
addTag(tag) {
|
|
2961
|
+
if (!this.allowDuplicates) {
|
|
2962
|
+
const exists = this.tags.some((t) => t.toLowerCase() === tag.toLowerCase());
|
|
2963
|
+
if (exists) {
|
|
2964
|
+
return;
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
this.tags = [...this.tags, tag];
|
|
2968
|
+
this.emitChanges();
|
|
2969
|
+
}
|
|
2970
|
+
emitChanges() {
|
|
2971
|
+
const cleaned = this.tags
|
|
2972
|
+
.map((t) => (t ?? '').trim())
|
|
2973
|
+
.filter((t) => t.length > 0);
|
|
2974
|
+
if (cleaned.length !== this.tags.length || cleaned.some((t, i) => t !== this.tags[i])) {
|
|
2975
|
+
this.tags = cleaned;
|
|
2976
|
+
}
|
|
2977
|
+
this.onChange(this.tags);
|
|
2978
|
+
this.valueChange.emit(this.tags);
|
|
2979
|
+
}
|
|
2980
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TagInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2981
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.4", type: TagInputComponent, isStandalone: true, selector: "haloduck-tag-input", inputs: { placeholder: "placeholder", disabled: "disabled", allowDuplicates: "allowDuplicates", value: "value" }, outputs: { valueChange: "valueChange" }, providers: [
|
|
2982
|
+
{
|
|
2983
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2984
|
+
useExisting: forwardRef(() => TagInputComponent),
|
|
2985
|
+
multi: true,
|
|
2986
|
+
},
|
|
2987
|
+
provideTranslocoScope('haloduck'),
|
|
2988
|
+
], viewQueries: [{ propertyName: "label", first: true, predicate: ["label"], descendants: true }, { propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true }], ngImport: i0, template: "<div class=\"flex flex-col gap-2\">\n <label #label class=\"block text-sm/6 font-medium text-light-on-control dark:text-dark-on-control text-left\">\n <ng-content></ng-content>\n </label>\n\n <div class=\"block w-full rounded-md bg-light-control dark:bg-dark-control disabled:bg-light-control/60 dark:disabled:bg-dark-control/80 px-2 py-1.5 text-base text-light-on-control dark:text-dark-on-control disabled:cursor-not-allowed disabled:text-light-on-control/60 dark:disabled:text-dark-on-control/80 outline -outline-offset-1 outline-light-inactive dark:outline-dark-inactive placeholder:text-light-inactive dark:placeholder:text-dark-inactive focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-light-primary dark:focus-within:outline-dark-primary sm:text-sm/6\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <ng-container *ngFor=\"let tag of tags; let i = index\">\n <span class=\"inline-flex items-center gap-1 rounded-md bg-light-secondary dark:bg-dark-secondary text-light-on-secondary dark:text-dark-on-secondary px-2 py-0.5 text-xs\">\n {{ tag }}\n @if (!disabled) {\n <button type=\"button\" (click)=\"removeTag(i)\" class=\"text-light-on-secondary/80 hover:text-light-on-secondary dark:text-dark-on-secondary/80 dark:hover:text-dark-on-secondary hover:cursor-pointer\">\n \u00D7\n </button>\n }\n </span>\n </ng-container>\n\n <input #inputEl\n [disabled]=\"disabled\"\n [placeholder]=\"placeholder\"\n class=\"flex-1 min-w-[8rem] bg-transparent outline-none placeholder:text-light-inactive dark:placeholder:text-dark-inactive\"\n [value]=\"inputValue\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onBlur()\"\n />\n </div>\n </div>\n</div>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
2989
|
+
}
|
|
2990
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TagInputComponent, decorators: [{
|
|
2991
|
+
type: Component,
|
|
2992
|
+
args: [{ selector: 'haloduck-tag-input', imports: [CommonModule], providers: [
|
|
2993
|
+
{
|
|
2994
|
+
provide: NG_VALUE_ACCESSOR,
|
|
2995
|
+
useExisting: forwardRef(() => TagInputComponent),
|
|
2996
|
+
multi: true,
|
|
2997
|
+
},
|
|
2998
|
+
provideTranslocoScope('haloduck'),
|
|
2999
|
+
], template: "<div class=\"flex flex-col gap-2\">\n <label #label class=\"block text-sm/6 font-medium text-light-on-control dark:text-dark-on-control text-left\">\n <ng-content></ng-content>\n </label>\n\n <div class=\"block w-full rounded-md bg-light-control dark:bg-dark-control disabled:bg-light-control/60 dark:disabled:bg-dark-control/80 px-2 py-1.5 text-base text-light-on-control dark:text-dark-on-control disabled:cursor-not-allowed disabled:text-light-on-control/60 dark:disabled:text-dark-on-control/80 outline -outline-offset-1 outline-light-inactive dark:outline-dark-inactive placeholder:text-light-inactive dark:placeholder:text-dark-inactive focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-light-primary dark:focus-within:outline-dark-primary sm:text-sm/6\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <ng-container *ngFor=\"let tag of tags; let i = index\">\n <span class=\"inline-flex items-center gap-1 rounded-md bg-light-secondary dark:bg-dark-secondary text-light-on-secondary dark:text-dark-on-secondary px-2 py-0.5 text-xs\">\n {{ tag }}\n @if (!disabled) {\n <button type=\"button\" (click)=\"removeTag(i)\" class=\"text-light-on-secondary/80 hover:text-light-on-secondary dark:text-dark-on-secondary/80 dark:hover:text-dark-on-secondary hover:cursor-pointer\">\n \u00D7\n </button>\n }\n </span>\n </ng-container>\n\n <input #inputEl\n [disabled]=\"disabled\"\n [placeholder]=\"placeholder\"\n class=\"flex-1 min-w-[8rem] bg-transparent outline-none placeholder:text-light-inactive dark:placeholder:text-dark-inactive\"\n [value]=\"inputValue\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (blur)=\"onBlur()\"\n />\n </div>\n </div>\n</div>\n", styles: [":host{display:block}\n"] }]
|
|
3000
|
+
}], propDecorators: { label: [{
|
|
3001
|
+
type: ViewChild,
|
|
3002
|
+
args: ['label']
|
|
3003
|
+
}], inputEl: [{
|
|
3004
|
+
type: ViewChild,
|
|
3005
|
+
args: ['inputEl']
|
|
3006
|
+
}], placeholder: [{
|
|
3007
|
+
type: Input
|
|
3008
|
+
}], disabled: [{
|
|
3009
|
+
type: Input
|
|
3010
|
+
}], allowDuplicates: [{
|
|
3011
|
+
type: Input
|
|
3012
|
+
}], value: [{
|
|
3013
|
+
type: Input
|
|
3014
|
+
}], valueChange: [{
|
|
3015
|
+
type: Output
|
|
3016
|
+
}] } });
|
|
3017
|
+
|
|
2787
3018
|
class BreadcrumbService {
|
|
2788
3019
|
router;
|
|
2789
3020
|
coreService = inject(CoreService);
|
|
@@ -2896,5 +3127,5 @@ const provideHaloduckTransloco = () => provideTranslocoScope({
|
|
|
2896
3127
|
* Generated bundle index. Do not edit.
|
|
2897
3128
|
*/
|
|
2898
3129
|
|
|
2899
|
-
export { AuthenticateComponent, BreadcrumbComponent, ButtonComponent, CalendarComponent, ConfirmDialogService, CopyButtonComponent, DatePickerComponent, DateRangeComponent, DialogService, DrawCanvasComponent, ERROR_NOT_ACCEPTABLE_FILE_TYPE, ERROR_OVER_COUNT, ERROR_OVER_SIZE, ERROR_UPLOAD, FileUploaderComponent, FlipComponent, ImageUploaderComponent, ImageViewerComponent, InputComponent, LanguageSelectorComponent, MapToAddressComponent, NotificationComponent, NotificationService, PictureNameComponent, SelectComponent, SelectDropdownComponent, SideMenuComponent, SideMenuItemComponent, StlViewerComponent, TableComponent, ToggleComponent, dateToString, provideHaloduckTransloco };
|
|
3130
|
+
export { AuthenticateComponent, BreadcrumbComponent, ButtonComponent, CalendarComponent, ConfirmDialogService, CopyButtonComponent, DatePickerComponent, DateRangeComponent, DialogService, DrawCanvasComponent, ERROR_NOT_ACCEPTABLE_FILE_TYPE, ERROR_OVER_COUNT, ERROR_OVER_SIZE, ERROR_UPLOAD, FileUploaderComponent, FlipComponent, ImageUploaderComponent, ImageViewerComponent, InputComponent, LanguageSelectorComponent, MapToAddressComponent, NotificationComponent, NotificationService, PictureNameComponent, SelectComponent, SelectDropdownComponent, SideMenuComponent, SideMenuItemComponent, StlViewerComponent, TableComponent, TabsComponent, TagInputComponent, ToggleComponent, dateToString, provideHaloduckTransloco };
|
|
2900
3131
|
//# sourceMappingURL=haloduck-ui.mjs.map
|