@ng-forge/dynamic-forms-ionic 1.3.0-next.3 → 1.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/fesm2022/ng-forge-dynamic-forms-ionic-lazy-datepicker.mjs +23 -9
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-datepicker.mjs.map +1 -1
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-input.mjs +8 -0
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-input.mjs.map +1 -1
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-select.mjs +4 -4
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-select.mjs.map +1 -1
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-textarea.mjs +8 -0
- package/fesm2022/ng-forge-dynamic-forms-ionic-lazy-textarea.mjs.map +1 -1
- package/package.json +2 -2
- package/types/ng-forge-dynamic-forms-ionic-lazy-checkbox.d.ts +1 -1
- package/types/ng-forge-dynamic-forms-ionic-lazy-datepicker.d.ts +7 -5
- package/types/ng-forge-dynamic-forms-ionic-lazy-multi-checkbox.d.ts +1 -1
- package/types/ng-forge-dynamic-forms-ionic-lazy-radio.d.ts +1 -1
- package/types/ng-forge-dynamic-forms-ionic-lazy-select.d.ts +3 -3
- package/types/ng-forge-dynamic-forms-ionic-lazy-slider.d.ts +1 -1
- package/types/ng-forge-dynamic-forms-ionic-lazy-toggle.d.ts +1 -1
- package/types/ng-forge-dynamic-forms-ionic.d.ts +11 -11
|
@@ -57,20 +57,25 @@ var IonicDatepickerFieldComponent = class IonicDatepickerFieldComponent {
|
|
|
57
57
|
}
|
|
58
58
|
onDateChange(event) {
|
|
59
59
|
const value = event.detail.value;
|
|
60
|
-
if (value
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
60
|
+
if (Array.isArray(value)) {
|
|
61
|
+
this.ngf.field()().value.set(value.map((iso) => new Date(iso)));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.ngf.field()().value.set(typeof value === "string" && value.length > 0 ? new Date(value) : null);
|
|
64
65
|
this.closeModal();
|
|
65
66
|
}
|
|
67
|
+
valueToIso(value) {
|
|
68
|
+
if (!value) return void 0;
|
|
69
|
+
return isDateArray(value) ? value.map((d) => d.toISOString()) : value.toISOString();
|
|
70
|
+
}
|
|
66
71
|
dateToIsoString(date) {
|
|
67
|
-
|
|
68
|
-
return date.toISOString();
|
|
72
|
+
return date ? date.toISOString() : void 0;
|
|
69
73
|
}
|
|
70
74
|
formatDisplayDate(date) {
|
|
71
75
|
if (!date) return "";
|
|
72
76
|
const options = DISPLAY_FORMATS[this.props()?.presentation ?? "date"];
|
|
73
|
-
|
|
77
|
+
const format = new Intl.DateTimeFormat(this.locale(), options);
|
|
78
|
+
return isDateArray(date) ? date.map((d) => format.format(d)).join(", ") : format.format(date);
|
|
74
79
|
}
|
|
75
80
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
76
81
|
minVersion: "12.0.0",
|
|
@@ -155,8 +160,11 @@ var IonicDatepickerFieldComponent = class IonicDatepickerFieldComponent {
|
|
|
155
160
|
<ion-content>
|
|
156
161
|
<ion-datetime
|
|
157
162
|
[presentation]="props()?.presentation ?? 'date'"
|
|
158
|
-
[value]="
|
|
163
|
+
[value]="valueToIso(dateValue)"
|
|
159
164
|
[multiple]="props()?.multiple ?? false"
|
|
165
|
+
[doneText]="(props()?.doneText | dynamicText | async) || 'Done'"
|
|
166
|
+
[cancelText]="(props()?.cancelText | dynamicText | async) || 'Cancel'"
|
|
167
|
+
[size]="props()?.size ?? 'fixed'"
|
|
160
168
|
[preferWheel]="props()?.preferWheel ?? false"
|
|
161
169
|
[showDefaultButtons]="props()?.showDefaultButtons ?? false"
|
|
162
170
|
[showDefaultTitle]="props()?.showDefaultTitle ?? false"
|
|
@@ -417,8 +425,11 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
417
425
|
<ion-content>
|
|
418
426
|
<ion-datetime
|
|
419
427
|
[presentation]="props()?.presentation ?? 'date'"
|
|
420
|
-
[value]="
|
|
428
|
+
[value]="valueToIso(dateValue)"
|
|
421
429
|
[multiple]="props()?.multiple ?? false"
|
|
430
|
+
[doneText]="(props()?.doneText | dynamicText | async) || 'Done'"
|
|
431
|
+
[cancelText]="(props()?.cancelText | dynamicText | async) || 'Cancel'"
|
|
432
|
+
[size]="props()?.size ?? 'fixed'"
|
|
422
433
|
[preferWheel]="props()?.preferWheel ?? false"
|
|
423
434
|
[showDefaultButtons]="props()?.showDefaultButtons ?? false"
|
|
424
435
|
[showDefaultTitle]="props()?.showDefaultTitle ?? false"
|
|
@@ -474,6 +485,9 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
474
485
|
}]
|
|
475
486
|
}
|
|
476
487
|
});
|
|
488
|
+
function isDateArray(value) {
|
|
489
|
+
return Array.isArray(value);
|
|
490
|
+
}
|
|
477
491
|
export { IonicDatepickerFieldComponent };
|
|
478
492
|
|
|
479
493
|
//# sourceMappingURL=ng-forge-dynamic-forms-ionic-lazy-datepicker.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-datepicker.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/datepicker/ionic-datepicker.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';\nimport {\n IonButton,\n IonButtons,\n IonContent,\n IonDatetime,\n IonHeader,\n IonInput,\n IonModal,\n IonNote,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { IonicDatepickerProps } from './ionic-datepicker.type';\nimport { AsyncPipe } from '@angular/common';\n\nconst TIME = { hour: 'numeric', minute: '2-digit' } as const;\nconst DATE = { month: 'short', day: 'numeric', year: 'numeric' } as const;\n\nconst DISPLAY_FORMATS = {\n date: DATE,\n 'date-time': { ...DATE, ...TIME },\n 'time-date': { ...DATE, ...TIME },\n time: TIME,\n month: { month: 'long', year: 'numeric' },\n 'month-year': { month: 'short', year: 'numeric' },\n year: { year: 'numeric' },\n} as const satisfies Record<NonNullable<IonicDatepickerProps['presentation']>, Intl.DateTimeFormatOptions>;\n\n@Component({\n selector: 'df-ion-datepicker',\n imports: [\n IonInput,\n IonModal,\n IonDatetime,\n IonNote,\n IonButtons,\n IonHeader,\n IonContent,\n IonToolbar,\n IonTitle,\n IonButton,\n DynamicTextPipe,\n AsyncPipe,\n NgForgeControl,\n ],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let dateValue = f().value();\n @let inputId = ngf.key() + '-input';\n\n <ion-input\n ngForgeControl\n [id]=\"inputId\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"'stacked'\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [disabled]=\"f().disabled()\"\n [value]=\"formatDisplayDate(dateValue)\"\n [readonly]=\"true\"\n [fill]=\"'outline'\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n (click)=\"!f().disabled() && openModal()\"\n />\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n } @else if (props()?.hint; as hint) {\n <ion-note class=\"df-ion-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</ion-note>\n }\n\n <ion-modal [isOpen]=\"isModalOpen()\" (didDismiss)=\"closeModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-title>{{ ngf.label() | dynamicText | async }}</ion-title>\n <ion-buttons slot=\"end\">\n <ion-button (click)=\"closeModal()\">Close</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content>\n <ion-datetime\n [presentation]=\"props()?.presentation ?? 'date'\"\n [value]=\"dateToIsoString(dateValue)\"\n [multiple]=\"props()?.multiple ?? false\"\n [preferWheel]=\"props()?.preferWheel ?? false\"\n [showDefaultButtons]=\"props()?.showDefaultButtons ?? false\"\n [showDefaultTitle]=\"props()?.showDefaultTitle ?? false\"\n [showDefaultTimeLabel]=\"props()?.showDefaultTimeLabel ?? true\"\n [showClearButton]=\"props()?.showClearButton ?? false\"\n [color]=\"props()?.color\"\n [locale]=\"locale() ?? 'default'\"\n [min]=\"dateToIsoString(minDate())\"\n [max]=\"dateToIsoString(maxDate())\"\n (ionChange)=\"onDateChange($event)\"\n >\n </ion-datetime>\n </ion-content>\n </ng-template>\n </ion-modal>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n ion-input {\n cursor: pointer;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class IonicDatepickerFieldComponent {\n protected readonly ngf = injectNgForgeField<Date | null>();\n\n readonly minDate = input<Date | null>(null);\n readonly maxDate = input<Date | null>(null);\n readonly startAt = input<Date | null>(null);\n readonly props = input<IonicDatepickerProps>();\n\n readonly isModalOpen = signal(false);\n\n /** Canonical locale tag, or undefined (browser locale) when unset or malformed. */\n protected readonly locale = computed(() => {\n const locale = this.props()?.locale;\n try {\n return locale ? Intl.getCanonicalLocales(locale)[0] : undefined;\n } catch {\n return undefined;\n }\n });\n\n openModal() {\n this.isModalOpen.set(true);\n }\n\n closeModal() {\n this.isModalOpen.set(false);\n }\n\n onDateChange(event: CustomEvent) {\n const value = event.detail.value;\n // ion-datetime emits ISO 8601 strings internally; convert to Date | null\n // to match the field tree's value type.\n if (value && typeof value === 'string' && value.length > 0) {\n const date = new Date(value);\n this.ngf.field()().value.set(date);\n } else {\n this.ngf.field()().value.set(null);\n }\n this.closeModal();\n }\n\n dateToIsoString(date: Date | null | undefined): string | undefined {\n if (!date) return undefined;\n return date.toISOString();\n }\n\n formatDisplayDate(date: Date | null | undefined): string {\n if (!date) return '';\n const options = DISPLAY_FORMATS[this.props()?.presentation ?? 'date'];\n return new Intl.DateTimeFormat(this.locale(), options).format(date);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-datepicker.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/datepicker/ionic-datepicker.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, signal } from '@angular/core';\nimport {\n IonButton,\n IonButtons,\n IonContent,\n IonDatetime,\n IonHeader,\n IonInput,\n IonModal,\n IonNote,\n IonTitle,\n IonToolbar,\n} from '@ionic/angular/standalone';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { IonicDatepickerProps } from './ionic-datepicker.type';\nimport { AsyncPipe } from '@angular/common';\n\nconst TIME = { hour: 'numeric', minute: '2-digit' } as const;\nconst DATE = { month: 'short', day: 'numeric', year: 'numeric' } as const;\n\nconst DISPLAY_FORMATS = {\n date: DATE,\n 'date-time': { ...DATE, ...TIME },\n 'time-date': { ...DATE, ...TIME },\n time: TIME,\n month: { month: 'long', year: 'numeric' },\n 'month-year': { month: 'short', year: 'numeric' },\n year: { year: 'numeric' },\n} as const satisfies Record<NonNullable<IonicDatepickerProps['presentation']>, Intl.DateTimeFormatOptions>;\n\n@Component({\n selector: 'df-ion-datepicker',\n imports: [\n IonInput,\n IonModal,\n IonDatetime,\n IonNote,\n IonButtons,\n IonHeader,\n IonContent,\n IonToolbar,\n IonTitle,\n IonButton,\n DynamicTextPipe,\n AsyncPipe,\n NgForgeControl,\n ],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let dateValue = f().value();\n @let inputId = ngf.key() + '-input';\n\n <ion-input\n ngForgeControl\n [id]=\"inputId\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"'stacked'\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [disabled]=\"f().disabled()\"\n [value]=\"formatDisplayDate(dateValue)\"\n [readonly]=\"true\"\n [fill]=\"'outline'\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n (click)=\"!f().disabled() && openModal()\"\n />\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n } @else if (props()?.hint; as hint) {\n <ion-note class=\"df-ion-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</ion-note>\n }\n\n <ion-modal [isOpen]=\"isModalOpen()\" (didDismiss)=\"closeModal()\">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-title>{{ ngf.label() | dynamicText | async }}</ion-title>\n <ion-buttons slot=\"end\">\n <ion-button (click)=\"closeModal()\">Close</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content>\n <ion-datetime\n [presentation]=\"props()?.presentation ?? 'date'\"\n [value]=\"valueToIso(dateValue)\"\n [multiple]=\"props()?.multiple ?? false\"\n [doneText]=\"(props()?.doneText | dynamicText | async) || 'Done'\"\n [cancelText]=\"(props()?.cancelText | dynamicText | async) || 'Cancel'\"\n [size]=\"props()?.size ?? 'fixed'\"\n [preferWheel]=\"props()?.preferWheel ?? false\"\n [showDefaultButtons]=\"props()?.showDefaultButtons ?? false\"\n [showDefaultTitle]=\"props()?.showDefaultTitle ?? false\"\n [showDefaultTimeLabel]=\"props()?.showDefaultTimeLabel ?? true\"\n [showClearButton]=\"props()?.showClearButton ?? false\"\n [color]=\"props()?.color\"\n [locale]=\"locale() ?? 'default'\"\n [min]=\"dateToIsoString(minDate())\"\n [max]=\"dateToIsoString(maxDate())\"\n (ionChange)=\"onDateChange($event)\"\n >\n </ion-datetime>\n </ion-content>\n </ng-template>\n </ion-modal>\n `,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n ion-input {\n cursor: pointer;\n }\n\n :host([hidden]) {\n display: none !important;\n }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport default class IonicDatepickerFieldComponent {\n protected readonly ngf = injectNgForgeField<Date | readonly Date[] | null>();\n\n readonly minDate = input<Date | null>(null);\n readonly maxDate = input<Date | null>(null);\n readonly startAt = input<Date | null>(null);\n readonly props = input<IonicDatepickerProps>();\n\n readonly isModalOpen = signal(false);\n\n /** Canonical locale tag, or undefined (browser locale) when unset or malformed. */\n protected readonly locale = computed(() => {\n const locale = this.props()?.locale;\n try {\n return locale ? Intl.getCanonicalLocales(locale)[0] : undefined;\n } catch {\n return undefined;\n }\n });\n\n openModal() {\n this.isModalOpen.set(true);\n }\n\n closeModal() {\n this.isModalOpen.set(false);\n }\n\n onDateChange(event: CustomEvent) {\n // ion-datetime emits ISO 8601 strings (an array in multiple mode); store Date values.\n const value: unknown = event.detail.value;\n if (Array.isArray(value)) {\n this.ngf\n .field()()\n .value.set(value.map((iso: string) => new Date(iso)));\n // Keep the picker open so more dates can be chosen.\n return;\n }\n this.ngf\n .field()()\n .value.set(typeof value === 'string' && value.length > 0 ? new Date(value) : null);\n this.closeModal();\n }\n\n /** The field value as ion-datetime expects it: an ISO string, or an array of them in multiple mode. */\n valueToIso(value: Date | readonly Date[] | null | undefined): string | string[] | undefined {\n if (!value) return undefined;\n return isDateArray(value) ? value.map((d) => d.toISOString()) : value.toISOString();\n }\n\n dateToIsoString(date: Date | null | undefined): string | undefined {\n return date ? date.toISOString() : undefined;\n }\n\n formatDisplayDate(date: Date | readonly Date[] | null | undefined): string {\n if (!date) return '';\n const options = DISPLAY_FORMATS[this.props()?.presentation ?? 'date'];\n const format = new Intl.DateTimeFormat(this.locale(), options);\n return isDateArray(date) ? date.map((d) => format.format(d)).join(', ') : format.format(date);\n }\n}\n\nfunction isDateArray(value: Date | readonly Date[]): value is readonly Date[] {\n return Array.isArray(value);\n}\n"],"mappings":"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"}
|
|
@@ -136,6 +136,10 @@ var IonicInputFieldComponent = class IonicInputFieldComponent {
|
|
|
136
136
|
</ion-input>
|
|
137
137
|
@if (ngf.errorsToDisplay()[0]; as error) {
|
|
138
138
|
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{ error.message }}</ion-note>
|
|
139
|
+
} @else if (props()?.errorText && f().invalid() && f().touched()) {
|
|
140
|
+
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{
|
|
141
|
+
props()?.errorText | dynamicText | async
|
|
142
|
+
}}</ion-note>
|
|
139
143
|
}
|
|
140
144
|
`,
|
|
141
145
|
isInline: true,
|
|
@@ -294,6 +298,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
294
298
|
</ion-input>
|
|
295
299
|
@if (ngf.errorsToDisplay()[0]; as error) {
|
|
296
300
|
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{ error.message }}</ion-note>
|
|
301
|
+
} @else if (props()?.errorText && f().invalid() && f().touched()) {
|
|
302
|
+
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{
|
|
303
|
+
props()?.errorText | dynamicText | async
|
|
304
|
+
}}</ion-note>
|
|
297
305
|
}
|
|
298
306
|
`,
|
|
299
307
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-input.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/input/ionic-input.component.ts"],"sourcesContent":["import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, DestroyRef, ElementRef, forwardRef, inject, input, signal } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { IonInput, IonNote } from '@ionic/angular/standalone';\nimport { AddonActionContext, AddonActionPreset, DynamicFormLogger } from '@ng-forge/dynamic-forms';\nimport { DfAddonSlot } from '@ng-forge/dynamic-forms/integration';\nimport { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';\nimport { DynamicTextPipe, FIELD_SIGNAL_CONTEXT } from '@ng-forge/dynamic-forms/integration';\nimport {\n ADDON_PRESET_HANDLER,\n AddonPresetHandler,\n injectNgForgeAddons,\n injectNgForgeField,\n NgForgeAddons,\n NgForgeControl,\n NgForgeFieldHost,\n} from '@ng-forge/dynamic-forms/integration';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport {\n IONIC_CONFIG,\n IONIC_INPUT_TYPE_OVERRIDE,\n IonicInlineButtonAddonComponent,\n runIonicPresetAction,\n} from '@ng-forge/dynamic-forms-ionic/shared';\nimport { IonicInputAddon, IonicInputProps } from './ionic-input.type';\n\n// minlength/maxlength bindings: Signal Forms auto-syncs these on NATIVE\n// inputs; <ion-input> is a Stencil web component so we bind directly from\n// FieldState (`f().maxLength?.()` — the signal itself is missing when no\n// validator is configured).\n@Component({\n selector: 'df-ion-input',\n // IonButton intentionally NOT imported — it would collide with\n // IonicInlineButtonAddonComponent on `<ion-button>` (NG0300).\n imports: [IonInput, IonNote, FormField, DynamicTextPipe, AsyncPipe, NgForgeControl, DfAddonSlot, IonicInlineButtonAddonComponent],\n hostDirectives: [NgForgeFieldHost, NgForgeAddons],\n template: `\n @let f = ngf.field();\n @let inputId = ngf.key() + '-input';\n\n <ion-input\n ngForgeControl\n [id]=\"inputId\"\n [type]=\"type()\"\n [formField]=\"f\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"labelPlacement()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [clearInput]=\"props()?.clearInput ?? false\"\n [counter]=\"props()?.counter ?? false\"\n [minlength]=\"f().minLength?.()\"\n [maxlength]=\"f().maxLength?.()\"\n [color]=\"color()\"\n [fill]=\"fill()\"\n [shape]=\"shape()\"\n [readonly]=\"f().readonly()\"\n [helperText]=\"ngf.errorsToDisplay().length === 0 ? ((props()?.hint | dynamicText | async) ?? undefined) : undefined\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n >\n @for (a of decorativePrefixAddons(); track $index) {\n <span slot=\"start\">\n <df-addon-slot [addon]=\"a\" [fieldInputs]=\"fieldInputs()\" [hidden]=\"ngfa.hiddenSignalCache().get(a)\" />\n </span>\n }\n @for (a of buttonPrefixAddons(); track $index) {\n <ion-button df-ion-button-addon slot=\"start\" [addon]=\"a\" [fieldInputs]=\"fieldInputs()\"></ion-button>\n }\n @for (a of buttonSuffixAddons(); track $index) {\n <ion-button df-ion-button-addon slot=\"end\" [addon]=\"a\" [fieldInputs]=\"fieldInputs()\"></ion-button>\n }\n @for (a of decorativeSuffixAddons(); track $index) {\n <span slot=\"end\">\n <df-addon-slot [addon]=\"a\" [fieldInputs]=\"fieldInputs()\" [hidden]=\"ngfa.hiddenSignalCache().get(a)\" />\n </span>\n }\n </ion-input>\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n styleUrl: '../../styles/_form-field.scss',\n providers: [\n {\n provide: IONIC_INPUT_TYPE_OVERRIDE,\n useFactory: () => signal<string | undefined>(undefined),\n },\n {\n // Adapter-specific preset semantics for `ion-button` addons (clear /\n // reset / paste / copy / toggle-password-visibility). The directive\n // (`NgForgeAddonAction`) delegates here when an addon configures a\n // `preset`. Per-ion-input-instance so the `typeOverride` signal is\n // scoped to one field.\n provide: ADDON_PRESET_HANDLER,\n useFactory: (): AddonPresetHandler => {\n const typeOverride = inject(IONIC_INPUT_TYPE_OVERRIDE);\n const fsc = inject(FIELD_SIGNAL_CONTEXT, { optional: true });\n const logger = inject(DynamicFormLogger);\n // forwardRef for baselineType only — host.props()?.type gates toggle-password-visibility.\n const host = inject(forwardRef(() => IonicInputFieldComponent));\n return {\n run: (preset: string, ctx: AddonActionContext) => {\n const fieldKey = ctx.field.key;\n return runIonicPresetAction(preset as AddonActionPreset, ctx, {\n typeOverride,\n fieldValueSetter: ctx.setValue,\n fieldDefaultValueGetter:\n fsc && fieldKey ? () => (fsc.defaultValues() as Record<string, unknown> | undefined)?.[fieldKey] : undefined,\n baselineType: () => host.props()?.type,\n logger,\n });\n },\n };\n },\n },\n ],\n styles: [\n `\n :host([hidden]) {\n display: none !important;\n }\n /* Per-side padding knobs on each slot wrapper (independent prefix/suffix). */\n :host {\n --df-ion-addon-prefix-outer-padding: 0;\n --df-ion-addon-prefix-inner-padding: 0.5rem;\n --df-ion-addon-suffix-inner-padding: 0.5rem;\n --df-ion-addon-suffix-outer-padding: 0;\n }\n /* inline-flex on slot wrappers prevents baseline-pinning of decorative addon glyphs. */\n :host ::ng-deep ion-input [slot='start'],\n :host ::ng-deep ion-input [slot='end'] {\n display: inline-flex;\n align-items: center;\n align-self: center;\n line-height: 1;\n }\n :host ::ng-deep ion-input [slot='start'] df-addon-slot,\n :host ::ng-deep ion-input [slot='end'] df-addon-slot,\n :host ::ng-deep ion-input [slot='start'] df-ion-icon-addon,\n :host ::ng-deep ion-input [slot='end'] df-ion-icon-addon {\n display: inline-flex;\n align-items: center;\n line-height: 1;\n }\n :host ::ng-deep ion-input [slot='start'] {\n padding-inline-start: var(--df-ion-addon-prefix-outer-padding);\n padding-inline-end: var(--df-ion-addon-prefix-inner-padding);\n }\n :host ::ng-deep ion-input [slot='end'] {\n padding-inline-start: var(--df-ion-addon-suffix-inner-padding);\n padding-inline-end: var(--df-ion-addon-suffix-outer-padding);\n }\n /* Inherit input text color so icons stay readable on dark themes\n (Ionic's default \"medium\" greys out and fails WCAG on dark inputs). */\n :host ::ng-deep ion-input ion-icon {\n color: inherit;\n }\n `,\n ],\n})\nexport default class IonicInputFieldComponent {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n private ionicConfig = inject(IONIC_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n protected readonly ngfa = injectNgForgeAddons<IonicInputAddon>();\n\n readonly props = input<IonicInputProps>();\n\n /**\n * Wrapper-style host bag pushed by `DfFieldOutlet`. Declared at the\n * component level so `setInputIfDeclared` (which uses\n * `reflectComponentType`) can write it.\n */\n readonly fieldInputs = input<WrapperFieldInputs | undefined>();\n\n /** Per-instance type override populated by `toggle-password-visibility` preset. */\n private readonly typeOverride = inject(IONIC_INPUT_TYPE_OVERRIDE);\n\n protected readonly fill = computed(() => this.props()?.fill ?? this.ionicConfig?.fill ?? 'solid');\n protected readonly shape = computed(() => this.props()?.shape ?? this.ionicConfig?.shape);\n /** Bootstrap / PrimeNG. Consumers can opt into Ionic's native inline 'start' */\n protected readonly labelPlacement = computed(() => this.props()?.labelPlacement ?? this.ionicConfig?.labelPlacement ?? 'stacked');\n protected readonly color = computed(() => this.props()?.color ?? this.ionicConfig?.color);\n\n /** Override (set by `toggle-password-visibility` preset) wins over `props().type`. */\n protected readonly type = computed(() => this.typeOverride() ?? this.props()?.type ?? 'text');\n\n /** Per-type split: ion-button addons render inline via the attribute-\n * selector inline component (so the slotted element is a native\n * <ion-button> Ionic can style); everything else (icon/text/template/\n * component types) goes through the universal <df-addon-slot> dispatcher\n * wrapped in <span slot=\"start|end\"> for safe shadow-DOM projection. */\n protected readonly buttonPrefixAddons = computed(() => this.ngfa.prefixAddons().filter((a) => a.type === 'ion-button'));\n protected readonly buttonSuffixAddons = computed(() => this.ngfa.suffixAddons().filter((a) => a.type === 'ion-button'));\n protected readonly decorativePrefixAddons = computed(() => this.ngfa.prefixAddons().filter((a) => a.type !== 'ion-button'));\n protected readonly decorativeSuffixAddons = computed(() => this.ngfa.suffixAddons().filter((a) => a.type !== 'ion-button'));\n\n /** Set when the component is destroyed — guards async aria-describedby sync against teardown. */\n private destroyed = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => (this.destroyed = true));\n // ion-input encapsulates a native <input> in shadow DOM and does not automatically\n // propagate aria-describedby to it. This effect imperatively syncs the attribute\n // after a microtask to ensure Ionic has resolved the internal element.\n explicitEffect([this.ngf.ariaDescribedBy], ([describedBy]) => {\n queueMicrotask(() => {\n if (this.destroyed) return;\n const ionInput = this.elementRef.nativeElement.querySelector('ion-input') as HTMLIonInputElement | null;\n if (ionInput?.getInputElement) {\n ionInput.getInputElement().then((inputEl) => {\n if (this.destroyed || !inputEl) return;\n if (describedBy) {\n inputEl.setAttribute('aria-describedby', describedBy);\n } else {\n inputEl.removeAttribute('aria-describedby');\n }\n });\n }\n });\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-input.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/input/ionic-input.component.ts"],"sourcesContent":["import { AsyncPipe } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, computed, DestroyRef, ElementRef, forwardRef, inject, input, signal } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { IonInput, IonNote } from '@ionic/angular/standalone';\nimport { AddonActionContext, AddonActionPreset, DynamicFormLogger } from '@ng-forge/dynamic-forms';\nimport { DfAddonSlot } from '@ng-forge/dynamic-forms/integration';\nimport { WrapperFieldInputs } from '@ng-forge/dynamic-forms/integration';\nimport { DynamicTextPipe, FIELD_SIGNAL_CONTEXT } from '@ng-forge/dynamic-forms/integration';\nimport {\n ADDON_PRESET_HANDLER,\n AddonPresetHandler,\n injectNgForgeAddons,\n injectNgForgeField,\n NgForgeAddons,\n NgForgeControl,\n NgForgeFieldHost,\n} from '@ng-forge/dynamic-forms/integration';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport {\n IONIC_CONFIG,\n IONIC_INPUT_TYPE_OVERRIDE,\n IonicInlineButtonAddonComponent,\n runIonicPresetAction,\n} from '@ng-forge/dynamic-forms-ionic/shared';\nimport { IonicInputAddon, IonicInputProps } from './ionic-input.type';\n\n// minlength/maxlength bindings: Signal Forms auto-syncs these on NATIVE\n// inputs; <ion-input> is a Stencil web component so we bind directly from\n// FieldState (`f().maxLength?.()` — the signal itself is missing when no\n// validator is configured).\n@Component({\n selector: 'df-ion-input',\n // IonButton intentionally NOT imported — it would collide with\n // IonicInlineButtonAddonComponent on `<ion-button>` (NG0300).\n imports: [IonInput, IonNote, FormField, DynamicTextPipe, AsyncPipe, NgForgeControl, DfAddonSlot, IonicInlineButtonAddonComponent],\n hostDirectives: [NgForgeFieldHost, NgForgeAddons],\n template: `\n @let f = ngf.field();\n @let inputId = ngf.key() + '-input';\n\n <ion-input\n ngForgeControl\n [id]=\"inputId\"\n [type]=\"type()\"\n [formField]=\"f\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"labelPlacement()\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [clearInput]=\"props()?.clearInput ?? false\"\n [counter]=\"props()?.counter ?? false\"\n [minlength]=\"f().minLength?.()\"\n [maxlength]=\"f().maxLength?.()\"\n [color]=\"color()\"\n [fill]=\"fill()\"\n [shape]=\"shape()\"\n [readonly]=\"f().readonly()\"\n [helperText]=\"ngf.errorsToDisplay().length === 0 ? ((props()?.hint | dynamicText | async) ?? undefined) : undefined\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n >\n @for (a of decorativePrefixAddons(); track $index) {\n <span slot=\"start\">\n <df-addon-slot [addon]=\"a\" [fieldInputs]=\"fieldInputs()\" [hidden]=\"ngfa.hiddenSignalCache().get(a)\" />\n </span>\n }\n @for (a of buttonPrefixAddons(); track $index) {\n <ion-button df-ion-button-addon slot=\"start\" [addon]=\"a\" [fieldInputs]=\"fieldInputs()\"></ion-button>\n }\n @for (a of buttonSuffixAddons(); track $index) {\n <ion-button df-ion-button-addon slot=\"end\" [addon]=\"a\" [fieldInputs]=\"fieldInputs()\"></ion-button>\n }\n @for (a of decorativeSuffixAddons(); track $index) {\n <span slot=\"end\">\n <df-addon-slot [addon]=\"a\" [fieldInputs]=\"fieldInputs()\" [hidden]=\"ngfa.hiddenSignalCache().get(a)\" />\n </span>\n }\n </ion-input>\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n } @else if (props()?.errorText && f().invalid() && f().touched()) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{\n props()?.errorText | dynamicText | async\n }}</ion-note>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n styleUrl: '../../styles/_form-field.scss',\n providers: [\n {\n provide: IONIC_INPUT_TYPE_OVERRIDE,\n useFactory: () => signal<string | undefined>(undefined),\n },\n {\n // Adapter-specific preset semantics for `ion-button` addons (clear /\n // reset / paste / copy / toggle-password-visibility). The directive\n // (`NgForgeAddonAction`) delegates here when an addon configures a\n // `preset`. Per-ion-input-instance so the `typeOverride` signal is\n // scoped to one field.\n provide: ADDON_PRESET_HANDLER,\n useFactory: (): AddonPresetHandler => {\n const typeOverride = inject(IONIC_INPUT_TYPE_OVERRIDE);\n const fsc = inject(FIELD_SIGNAL_CONTEXT, { optional: true });\n const logger = inject(DynamicFormLogger);\n // forwardRef for baselineType only — host.props()?.type gates toggle-password-visibility.\n const host = inject(forwardRef(() => IonicInputFieldComponent));\n return {\n run: (preset: string, ctx: AddonActionContext) => {\n const fieldKey = ctx.field.key;\n return runIonicPresetAction(preset as AddonActionPreset, ctx, {\n typeOverride,\n fieldValueSetter: ctx.setValue,\n fieldDefaultValueGetter:\n fsc && fieldKey ? () => (fsc.defaultValues() as Record<string, unknown> | undefined)?.[fieldKey] : undefined,\n baselineType: () => host.props()?.type,\n logger,\n });\n },\n };\n },\n },\n ],\n styles: [\n `\n :host([hidden]) {\n display: none !important;\n }\n /* Per-side padding knobs on each slot wrapper (independent prefix/suffix). */\n :host {\n --df-ion-addon-prefix-outer-padding: 0;\n --df-ion-addon-prefix-inner-padding: 0.5rem;\n --df-ion-addon-suffix-inner-padding: 0.5rem;\n --df-ion-addon-suffix-outer-padding: 0;\n }\n /* inline-flex on slot wrappers prevents baseline-pinning of decorative addon glyphs. */\n :host ::ng-deep ion-input [slot='start'],\n :host ::ng-deep ion-input [slot='end'] {\n display: inline-flex;\n align-items: center;\n align-self: center;\n line-height: 1;\n }\n :host ::ng-deep ion-input [slot='start'] df-addon-slot,\n :host ::ng-deep ion-input [slot='end'] df-addon-slot,\n :host ::ng-deep ion-input [slot='start'] df-ion-icon-addon,\n :host ::ng-deep ion-input [slot='end'] df-ion-icon-addon {\n display: inline-flex;\n align-items: center;\n line-height: 1;\n }\n :host ::ng-deep ion-input [slot='start'] {\n padding-inline-start: var(--df-ion-addon-prefix-outer-padding);\n padding-inline-end: var(--df-ion-addon-prefix-inner-padding);\n }\n :host ::ng-deep ion-input [slot='end'] {\n padding-inline-start: var(--df-ion-addon-suffix-inner-padding);\n padding-inline-end: var(--df-ion-addon-suffix-outer-padding);\n }\n /* Inherit input text color so icons stay readable on dark themes\n (Ionic's default \"medium\" greys out and fails WCAG on dark inputs). */\n :host ::ng-deep ion-input ion-icon {\n color: inherit;\n }\n `,\n ],\n})\nexport default class IonicInputFieldComponent {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n private ionicConfig = inject(IONIC_CONFIG, { optional: true });\n\n protected readonly ngf = injectNgForgeField<string>();\n protected readonly ngfa = injectNgForgeAddons<IonicInputAddon>();\n\n readonly props = input<IonicInputProps>();\n\n /**\n * Wrapper-style host bag pushed by `DfFieldOutlet`. Declared at the\n * component level so `setInputIfDeclared` (which uses\n * `reflectComponentType`) can write it.\n */\n readonly fieldInputs = input<WrapperFieldInputs | undefined>();\n\n /** Per-instance type override populated by `toggle-password-visibility` preset. */\n private readonly typeOverride = inject(IONIC_INPUT_TYPE_OVERRIDE);\n\n protected readonly fill = computed(() => this.props()?.fill ?? this.ionicConfig?.fill ?? 'solid');\n protected readonly shape = computed(() => this.props()?.shape ?? this.ionicConfig?.shape);\n /** Bootstrap / PrimeNG. Consumers can opt into Ionic's native inline 'start' */\n protected readonly labelPlacement = computed(() => this.props()?.labelPlacement ?? this.ionicConfig?.labelPlacement ?? 'stacked');\n protected readonly color = computed(() => this.props()?.color ?? this.ionicConfig?.color);\n\n /** Override (set by `toggle-password-visibility` preset) wins over `props().type`. */\n protected readonly type = computed(() => this.typeOverride() ?? this.props()?.type ?? 'text');\n\n /** Per-type split: ion-button addons render inline via the attribute-\n * selector inline component (so the slotted element is a native\n * <ion-button> Ionic can style); everything else (icon/text/template/\n * component types) goes through the universal <df-addon-slot> dispatcher\n * wrapped in <span slot=\"start|end\"> for safe shadow-DOM projection. */\n protected readonly buttonPrefixAddons = computed(() => this.ngfa.prefixAddons().filter((a) => a.type === 'ion-button'));\n protected readonly buttonSuffixAddons = computed(() => this.ngfa.suffixAddons().filter((a) => a.type === 'ion-button'));\n protected readonly decorativePrefixAddons = computed(() => this.ngfa.prefixAddons().filter((a) => a.type !== 'ion-button'));\n protected readonly decorativeSuffixAddons = computed(() => this.ngfa.suffixAddons().filter((a) => a.type !== 'ion-button'));\n\n /** Set when the component is destroyed — guards async aria-describedby sync against teardown. */\n private destroyed = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => (this.destroyed = true));\n // ion-input encapsulates a native <input> in shadow DOM and does not automatically\n // propagate aria-describedby to it. This effect imperatively syncs the attribute\n // after a microtask to ensure Ionic has resolved the internal element.\n explicitEffect([this.ngf.ariaDescribedBy], ([describedBy]) => {\n queueMicrotask(() => {\n if (this.destroyed) return;\n const ionInput = this.elementRef.nativeElement.querySelector('ion-input') as HTMLIonInputElement | null;\n if (ionInput?.getInputElement) {\n ionInput.getInputElement().then((inputEl) => {\n if (this.destroyed || !inputEl) return;\n if (describedBy) {\n inputEl.setAttribute('aria-describedby', describedBy);\n } else {\n inputEl.removeAttribute('aria-describedby');\n }\n });\n }\n });\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -57,8 +57,8 @@ var IonicSelectFieldComponent = class IonicSelectFieldComponent {
|
|
|
57
57
|
[compareWith]="props()?.compareWith ?? defaultCompare"
|
|
58
58
|
[interface]="props()?.interface ?? 'alert'"
|
|
59
59
|
[interfaceOptions]="props()?.interfaceOptions ?? {}"
|
|
60
|
-
[cancelText]="props()?.cancelText
|
|
61
|
-
[okText]="props()?.okText
|
|
60
|
+
[cancelText]="(props()?.cancelText | dynamicText | async) || 'Cancel'"
|
|
61
|
+
[okText]="(props()?.okText | dynamicText | async) || 'OK'"
|
|
62
62
|
[color]="props()?.color"
|
|
63
63
|
[fill]="props()?.fill ?? 'outline'"
|
|
64
64
|
[shape]="props()?.shape"
|
|
@@ -181,8 +181,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
181
181
|
[compareWith]="props()?.compareWith ?? defaultCompare"
|
|
182
182
|
[interface]="props()?.interface ?? 'alert'"
|
|
183
183
|
[interfaceOptions]="props()?.interfaceOptions ?? {}"
|
|
184
|
-
[cancelText]="props()?.cancelText
|
|
185
|
-
[okText]="props()?.okText
|
|
184
|
+
[cancelText]="(props()?.cancelText | dynamicText | async) || 'Cancel'"
|
|
185
|
+
[okText]="(props()?.okText | dynamicText | async) || 'OK'"
|
|
186
186
|
[color]="props()?.color"
|
|
187
187
|
[fill]="props()?.fill ?? 'outline'"
|
|
188
188
|
[shape]="props()?.shape"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-select.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/select/ionic-select.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { IonNote, IonSelect, IonSelectOption } from '@ionic/angular/standalone';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { IonicSelectProps } from './ionic-select.type';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-ion-select',\n imports: [IonSelect, IonSelectOption, IonNote, FormField, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let selectId = ngf.key() + '-select';\n\n <ion-select\n ngForgeControl\n [id]=\"selectId\"\n [formField]=\"f\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"props()?.labelPlacement ?? 'stacked'\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [multiple]=\"props()?.multiple ?? false\"\n [compareWith]=\"props()?.compareWith ?? defaultCompare\"\n [interface]=\"props()?.interface ?? 'alert'\"\n [interfaceOptions]=\"props()?.interfaceOptions ?? {}\"\n [cancelText]=\"props()?.cancelText
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-select.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/select/ionic-select.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\nimport { IonNote, IonSelect, IonSelectOption } from '@ionic/angular/standalone';\nimport { FieldOption, ValueType } from '@ng-forge/dynamic-forms';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { IonicSelectProps } from './ionic-select.type';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-ion-select',\n imports: [IonSelect, IonSelectOption, IonNote, FormField, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let selectId = ngf.key() + '-select';\n\n <ion-select\n ngForgeControl\n [id]=\"selectId\"\n [formField]=\"f\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"props()?.labelPlacement ?? 'stacked'\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [multiple]=\"props()?.multiple ?? false\"\n [compareWith]=\"props()?.compareWith ?? defaultCompare\"\n [interface]=\"props()?.interface ?? 'alert'\"\n [interfaceOptions]=\"props()?.interfaceOptions ?? {}\"\n [cancelText]=\"(props()?.cancelText | dynamicText | async) || 'Cancel'\"\n [okText]=\"(props()?.okText | dynamicText | async) || 'OK'\"\n [color]=\"props()?.color\"\n [fill]=\"props()?.fill ?? 'outline'\"\n [shape]=\"props()?.shape\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n >\n @for (option of options(); track option.value) {\n <ion-select-option [value]=\"option.value\" [disabled]=\"option.disabled || false\">\n {{ option.label | dynamicText | async }}\n </ion-select-option>\n }\n </ion-select>\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n } @else if (props()?.hint; as hint) {\n <ion-note class=\"df-ion-hint\" [id]=\"ngf.hintId()\">{{ hint | dynamicText | async }}</ion-note>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n :host([hidden]) {\n display: none !important;\n }\n `,\n ],\n})\nexport default class IonicSelectFieldComponent {\n protected readonly ngf = injectNgForgeField<ValueType>();\n\n readonly options = input<FieldOption<ValueType>[]>([]);\n readonly props = input<IonicSelectProps>();\n\n defaultCompare = Object.is;\n}\n"],"mappings":";;;;;;;AAyDA,IAAqB,4BAArB,MAAqB,0BAAyB;CACzB,MAAM,mBAAkB;CAElC,UAAU,MAAgC,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAC7C,QAAQ,MAAyB,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAE1C,iBAAiB,OAAO;CANL,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAyB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAzB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAyB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,gBAAA,CAAA,EAAA,WAAA,GAAA,iBAAA,CAAA;EAAA,UAAA;EAAA,UA5ClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCT,UAAA;EAAA,QAAA,CAAA,mfAAA,2CAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAnCS;IAAS,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAe,UAAA;IAAA,QAAA,CAAA,YAAA,OAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAO,UAAA;IAAA,QAAA,CAAA,SAAA,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAS,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAA8B;IAAc,UAAA;IAAA,QAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAA1C;IAAe,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAS,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AA8CjE,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAyB,YAAA,CAAA;EAhD7C,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAe,SAChB;IAAC;IAAW;IAAiB;IAAS;IAAW;IAAiB;IAAW;GAAc;GAAC,gBACrF,CAAC,gBAAgB;GAAC,UACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCT,iBACgB,wBAAwB;GAAM,QAAA,CAAA,mfAAA,2CAAA;EAAA,CAAA"}
|
|
@@ -70,6 +70,10 @@ var IonicTextareaFieldComponent = class IonicTextareaFieldComponent {
|
|
|
70
70
|
/>
|
|
71
71
|
@if (ngf.errorsToDisplay()[0]; as error) {
|
|
72
72
|
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{ error.message }}</ion-note>
|
|
73
|
+
} @else if (props()?.errorText && f().invalid() && f().touched()) {
|
|
74
|
+
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{
|
|
75
|
+
props()?.errorText | dynamicText | async
|
|
76
|
+
}}</ion-note>
|
|
73
77
|
}
|
|
74
78
|
`,
|
|
75
79
|
isInline: true,
|
|
@@ -187,6 +191,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
187
191
|
/>
|
|
188
192
|
@if (ngf.errorsToDisplay()[0]; as error) {
|
|
189
193
|
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{ error.message }}</ion-note>
|
|
194
|
+
} @else if (props()?.errorText && f().invalid() && f().touched()) {
|
|
195
|
+
<ion-note color="danger" class="df-ion-error" [id]="ngf.errorId()" role="alert">{{
|
|
196
|
+
props()?.errorText | dynamicText | async
|
|
197
|
+
}}</ion-note>
|
|
190
198
|
}
|
|
191
199
|
`,
|
|
192
200
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-textarea.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/textarea/ionic-textarea.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ElementRef, inject, input } from '@angular/core';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { FormField } from '@angular/forms/signals';\nimport { IonNote, IonTextarea } from '@ionic/angular/standalone';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { IonicTextareaProps } from './ionic-textarea.type';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-ion-textarea',\n imports: [IonTextarea, IonNote, FormField, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let textareaId = ngf.key() + '-textarea';\n\n <ion-textarea\n ngForgeControl\n [id]=\"textareaId\"\n [formField]=\"f\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"props()?.labelPlacement ?? 'stacked'\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [rows]=\"props()?.rows ?? 4\"\n [autoGrow]=\"props()?.autoGrow ?? false\"\n [counter]=\"props()?.counter ?? false\"\n [minlength]=\"f().minLength?.()\"\n [maxlength]=\"f().maxLength?.()\"\n [color]=\"props()?.color\"\n [fill]=\"props()?.fill ?? 'outline'\"\n [shape]=\"props()?.shape\"\n [readonly]=\"f().readonly()\"\n [helperText]=\"ngf.errorsToDisplay().length === 0 ? ((props()?.hint | dynamicText | async) ?? undefined) : undefined\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n />\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n :host([hidden]) {\n display: none !important;\n }\n `,\n ],\n})\nexport default class IonicTextareaFieldComponent {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n protected readonly ngf = injectNgForgeField<string>();\n\n readonly props = input<IonicTextareaProps>();\n\n constructor() {\n // ion-textarea encapsulates a native <textarea> in shadow DOM and does not automatically\n // propagate aria-describedby to it. This effect imperatively syncs the attribute\n // after a microtask to ensure Ionic has resolved the internal element.\n explicitEffect([this.ngf.ariaDescribedBy], ([describedBy]) => {\n queueMicrotask(() => {\n const ionTextarea = this.elementRef.nativeElement.querySelector('ion-textarea') as HTMLIonTextareaElement | null;\n if (ionTextarea?.getInputElement) {\n ionTextarea.getInputElement().then((textareaEl) => {\n if (!textareaEl) return;\n if (describedBy) {\n textareaEl.setAttribute('aria-describedby', describedBy);\n } else {\n textareaEl.removeAttribute('aria-describedby');\n }\n });\n }\n });\n });\n }\n}\n"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"ng-forge-dynamic-forms-ionic-lazy-textarea.mjs","names":[],"sources":["../../../../packages/dynamic-forms-ionic/src/lib/fields/textarea/ionic-textarea.component.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ElementRef, inject, input } from '@angular/core';\nimport { explicitEffect } from 'ngxtension/explicit-effect';\nimport { FormField } from '@angular/forms/signals';\nimport { IonNote, IonTextarea } from '@ionic/angular/standalone';\nimport { DynamicTextPipe } from '@ng-forge/dynamic-forms/integration';\nimport { NgForgeControl, injectNgForgeField, NgForgeFieldHost } from '@ng-forge/dynamic-forms/integration';\nimport { IonicTextareaProps } from './ionic-textarea.type';\nimport { AsyncPipe } from '@angular/common';\n\n@Component({\n selector: 'df-ion-textarea',\n imports: [IonTextarea, IonNote, FormField, DynamicTextPipe, AsyncPipe, NgForgeControl],\n hostDirectives: [NgForgeFieldHost],\n template: `\n @let f = ngf.field();\n @let textareaId = ngf.key() + '-textarea';\n\n <ion-textarea\n ngForgeControl\n [id]=\"textareaId\"\n [formField]=\"f\"\n [label]=\"(ngf.label() | dynamicText | async) ?? undefined\"\n [labelPlacement]=\"props()?.labelPlacement ?? 'stacked'\"\n [placeholder]=\"(ngf.placeholder() | dynamicText | async) ?? ''\"\n [rows]=\"props()?.rows ?? 4\"\n [autoGrow]=\"props()?.autoGrow ?? false\"\n [counter]=\"props()?.counter ?? false\"\n [minlength]=\"f().minLength?.()\"\n [maxlength]=\"f().maxLength?.()\"\n [color]=\"props()?.color\"\n [fill]=\"props()?.fill ?? 'outline'\"\n [shape]=\"props()?.shape\"\n [readonly]=\"f().readonly()\"\n [helperText]=\"ngf.errorsToDisplay().length === 0 ? ((props()?.hint | dynamicText | async) ?? undefined) : undefined\"\n [attr.tabindex]=\"ngf.tabIndex()\"\n />\n @if (ngf.errorsToDisplay()[0]; as error) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{ error.message }}</ion-note>\n } @else if (props()?.errorText && f().invalid() && f().touched()) {\n <ion-note color=\"danger\" class=\"df-ion-error\" [id]=\"ngf.errorId()\" role=\"alert\">{{\n props()?.errorText | dynamicText | async\n }}</ion-note>\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n styleUrl: '../../styles/_form-field.scss',\n styles: [\n `\n :host([hidden]) {\n display: none !important;\n }\n `,\n ],\n})\nexport default class IonicTextareaFieldComponent {\n private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n protected readonly ngf = injectNgForgeField<string>();\n\n readonly props = input<IonicTextareaProps>();\n\n constructor() {\n // ion-textarea encapsulates a native <textarea> in shadow DOM and does not automatically\n // propagate aria-describedby to it. This effect imperatively syncs the attribute\n // after a microtask to ensure Ionic has resolved the internal element.\n explicitEffect([this.ngf.ariaDescribedBy], ([describedBy]) => {\n queueMicrotask(() => {\n const ionTextarea = this.elementRef.nativeElement.querySelector('ion-textarea') as HTMLIonTextareaElement | null;\n if (ionTextarea?.getInputElement) {\n ionTextarea.getInputElement().then((textareaEl) => {\n if (!textareaEl) return;\n if (describedBy) {\n textareaEl.setAttribute('aria-describedby', describedBy);\n } else {\n textareaEl.removeAttribute('aria-describedby');\n }\n });\n }\n });\n });\n }\n}\n"],"mappings":";;;;;;;;AAsDA,IAAqB,8BAArB,MAAqB,4BAA2B;CAC7B,aAAa,OAAO,UAAuB;CAEzC,MAAM,mBAAkB;CAElC,QAAQ,MAA2B,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAE5C,cAAA;EAIE,eAAe,CAAC,KAAK,IAAI,eAAe,IAAI,CAAC,iBAAgB;GAC3D,qBAAoB;IAClB,MAAM,cAAc,KAAK,WAAW,cAAc,cAAc,cAAc;IAC9E,IAAI,aAAa,iBACf,YAAY,gBAAe,CAAE,CAAC,MAAM,eAAc;KAChD,IAAI,CAAC,YAAY;KACjB,IAAI,aACF,WAAW,aAAa,oBAAoB,WAAW;UAEvD,WAAW,gBAAgB,kBAAkB;IAEjD,CAAC;GAEL,CAAC;EACH,CAAC;CACH;CA1BmB,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAA2B,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAA3B,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAA2B,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,OAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,gBAAA,CAAA,EAAA,WAAA,GAAA,iBAAA,CAAA;EAAA,UAAA;EAAA,UAzCpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8BT,UAAA;EAAA,QAAA,CAAA,mfAAA,2CAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MAhCS;IAAW,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAO,UAAA;IAAA,QAAA,CAAA,SAAA,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAS,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAA8B;IAAc,UAAA;IAAA,QAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAA1C;IAAe,MAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAS,MAAA;GAAA;EAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AA2ClD,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAA2B,YAAA,CAAA;EA7C/C,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAiB,SAClB;IAAC;IAAa;IAAS;IAAW;IAAiB;IAAW;GAAc;GAAC,gBACtE,CAAC,gBAAgB;GAAC,UACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BT,iBACgB,wBAAwB;GAAM,QAAA,CAAA,mfAAA,2CAAA;EAAA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-forge/dynamic-forms-ionic",
|
|
3
|
-
"version": "1.3.0
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Ionic integration for @ng-forge/dynamic-forms. Pre-built Ionic form components for mobile and desktop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"@angular/core": "^22.0.0",
|
|
96
96
|
"@angular/forms": "^22.0.0",
|
|
97
97
|
"@ionic/angular": ">=8.0.0",
|
|
98
|
-
"@ng-forge/dynamic-forms": "~1.3.0
|
|
98
|
+
"@ng-forge/dynamic-forms": "~1.3.0",
|
|
99
99
|
"rxjs": ">=7.0.0"
|
|
100
100
|
},
|
|
101
101
|
"dependencies": {
|
|
@@ -5,7 +5,7 @@ import * as i0 from "@angular/core";
|
|
|
5
5
|
interface IonicCheckboxProps {
|
|
6
6
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
7
7
|
justify?: 'start' | 'end' | 'space-between';
|
|
8
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
8
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
9
9
|
indeterminate?: boolean;
|
|
10
10
|
hint?: DynamicText;
|
|
11
11
|
}
|
|
@@ -10,17 +10,17 @@ interface IonicDatepickerProps extends DatepickerProps {
|
|
|
10
10
|
showDefaultTitle?: boolean;
|
|
11
11
|
showDefaultTimeLabel?: boolean;
|
|
12
12
|
showClearButton?: boolean;
|
|
13
|
-
doneText?:
|
|
14
|
-
cancelText?:
|
|
13
|
+
doneText?: DynamicText;
|
|
14
|
+
cancelText?: DynamicText;
|
|
15
15
|
size?: 'cover' | 'fixed';
|
|
16
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
16
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
17
17
|
hint?: DynamicText;
|
|
18
18
|
/** BCP 47 locale for the picker and the displayed value. Defaults to the browser locale. */
|
|
19
19
|
locale?: string;
|
|
20
20
|
}
|
|
21
21
|
type IonicDatepickerField = DatepickerField<IonicDatepickerProps>;
|
|
22
22
|
declare class IonicDatepickerFieldComponent {
|
|
23
|
-
protected readonly ngf: import("@ng-forge/dynamic-forms/integration").TypedNgForgeField<Date | null>;
|
|
23
|
+
protected readonly ngf: import("@ng-forge/dynamic-forms/integration").TypedNgForgeField<Date | readonly Date[] | null>;
|
|
24
24
|
readonly minDate: import("@angular/core").InputSignal<Date | null>;
|
|
25
25
|
readonly maxDate: import("@angular/core").InputSignal<Date | null>;
|
|
26
26
|
readonly startAt: import("@angular/core").InputSignal<Date | null>;
|
|
@@ -31,8 +31,10 @@ declare class IonicDatepickerFieldComponent {
|
|
|
31
31
|
openModal(): void;
|
|
32
32
|
closeModal(): void;
|
|
33
33
|
onDateChange(event: CustomEvent): void;
|
|
34
|
+
/** The field value as ion-datetime expects it: an ISO string, or an array of them in multiple mode. */
|
|
35
|
+
valueToIso(value: Date | readonly Date[] | null | undefined): string | string[] | undefined;
|
|
34
36
|
dateToIsoString(date: Date | null | undefined): string | undefined;
|
|
35
|
-
formatDisplayDate(date: Date | null | undefined): string;
|
|
37
|
+
formatDisplayDate(date: Date | readonly Date[] | null | undefined): string;
|
|
36
38
|
static ɵfac: i0.ɵɵFactoryDeclaration<IonicDatepickerFieldComponent, never>;
|
|
37
39
|
static ɵcmp: i0.ɵɵComponentDeclaration<IonicDatepickerFieldComponent, "df-ion-datepicker", never, {
|
|
38
40
|
"minDate": {
|
|
@@ -5,7 +5,7 @@ import * as i0 from "@angular/core";
|
|
|
5
5
|
interface IonicMultiCheckboxProps {
|
|
6
6
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
7
7
|
justify?: 'start' | 'end' | 'space-between';
|
|
8
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
8
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
9
9
|
hint?: DynamicText;
|
|
10
10
|
}
|
|
11
11
|
type IonicMultiCheckboxField<T> = MultiCheckboxField<T, IonicMultiCheckboxProps>;
|
|
@@ -5,7 +5,7 @@ import * as i0 from "@angular/core";
|
|
|
5
5
|
interface IonicRadioProps {
|
|
6
6
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
7
7
|
justify?: 'start' | 'end' | 'space-between';
|
|
8
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
8
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
9
9
|
compareWith?: (o1: ValueType, o2: ValueType) => boolean;
|
|
10
10
|
hint?: DynamicText;
|
|
11
11
|
}
|
|
@@ -6,12 +6,12 @@ interface IonicSelectProps extends SelectProps {
|
|
|
6
6
|
multiple?: boolean;
|
|
7
7
|
interface?: 'action-sheet' | 'popover' | 'alert';
|
|
8
8
|
interfaceOptions?: unknown;
|
|
9
|
-
cancelText?:
|
|
10
|
-
okText?:
|
|
9
|
+
cancelText?: DynamicText;
|
|
10
|
+
okText?: DynamicText;
|
|
11
11
|
fill?: 'solid' | 'outline';
|
|
12
12
|
shape?: 'round';
|
|
13
13
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked' | 'floating';
|
|
14
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
14
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
15
15
|
compareWith?: (o1: ValueType, o2: ValueType) => boolean;
|
|
16
16
|
hint?: DynamicText;
|
|
17
17
|
}
|
|
@@ -23,7 +23,7 @@ interface IonicSliderProps {
|
|
|
23
23
|
pinFormatter?: (value: number) => string | number;
|
|
24
24
|
ticks?: boolean;
|
|
25
25
|
snaps?: boolean;
|
|
26
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
26
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
27
27
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
28
28
|
hint?: DynamicText;
|
|
29
29
|
}
|
|
@@ -6,7 +6,7 @@ import { FormCheckboxControl } from "@angular/forms/signals";
|
|
|
6
6
|
interface IonicToggleProps {
|
|
7
7
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
8
8
|
justify?: 'start' | 'end' | 'space-between';
|
|
9
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
9
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
10
10
|
enableOnOffLabels?: boolean;
|
|
11
11
|
hint?: DynamicText;
|
|
12
12
|
}
|
|
@@ -119,7 +119,7 @@ type IonicShiftArrayItemButtonField = Omit<IonicButtonField<ShiftArrayItemEvent>
|
|
|
119
119
|
interface IonicCheckboxProps {
|
|
120
120
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
121
121
|
justify?: 'start' | 'end' | 'space-between';
|
|
122
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
122
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
123
123
|
indeterminate?: boolean;
|
|
124
124
|
hint?: DynamicText;
|
|
125
125
|
}
|
|
@@ -132,10 +132,10 @@ interface IonicDatepickerProps extends DatepickerProps {
|
|
|
132
132
|
showDefaultTitle?: boolean;
|
|
133
133
|
showDefaultTimeLabel?: boolean;
|
|
134
134
|
showClearButton?: boolean;
|
|
135
|
-
doneText?:
|
|
136
|
-
cancelText?:
|
|
135
|
+
doneText?: DynamicText;
|
|
136
|
+
cancelText?: DynamicText;
|
|
137
137
|
size?: 'cover' | 'fixed';
|
|
138
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
138
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
139
139
|
hint?: DynamicText;
|
|
140
140
|
/** BCP 47 locale for the picker and the displayed value. Defaults to the browser locale. */
|
|
141
141
|
locale?: string;
|
|
@@ -165,14 +165,14 @@ type IonicInputField = InputField<IonicInputProps> & {
|
|
|
165
165
|
interface IonicMultiCheckboxProps {
|
|
166
166
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
167
167
|
justify?: 'start' | 'end' | 'space-between';
|
|
168
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
168
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
169
169
|
hint?: DynamicText;
|
|
170
170
|
}
|
|
171
171
|
type IonicMultiCheckboxField<T> = MultiCheckboxField<T, IonicMultiCheckboxProps>;
|
|
172
172
|
interface IonicRadioProps {
|
|
173
173
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
174
174
|
justify?: 'start' | 'end' | 'space-between';
|
|
175
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
175
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
176
176
|
compareWith?: (o1: ValueType, o2: ValueType) => boolean;
|
|
177
177
|
hint?: DynamicText;
|
|
178
178
|
}
|
|
@@ -181,12 +181,12 @@ interface IonicSelectProps extends SelectProps {
|
|
|
181
181
|
multiple?: boolean;
|
|
182
182
|
interface?: 'action-sheet' | 'popover' | 'alert';
|
|
183
183
|
interfaceOptions?: unknown;
|
|
184
|
-
cancelText?:
|
|
185
|
-
okText?:
|
|
184
|
+
cancelText?: DynamicText;
|
|
185
|
+
okText?: DynamicText;
|
|
186
186
|
fill?: 'solid' | 'outline';
|
|
187
187
|
shape?: 'round';
|
|
188
188
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked' | 'floating';
|
|
189
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
189
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
190
190
|
compareWith?: (o1: ValueType, o2: ValueType) => boolean;
|
|
191
191
|
hint?: DynamicText;
|
|
192
192
|
}
|
|
@@ -212,7 +212,7 @@ interface IonicSliderProps {
|
|
|
212
212
|
pinFormatter?: (value: number) => string | number;
|
|
213
213
|
ticks?: boolean;
|
|
214
214
|
snaps?: boolean;
|
|
215
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
215
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
216
216
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
217
217
|
hint?: DynamicText;
|
|
218
218
|
}
|
|
@@ -231,7 +231,7 @@ type IonicTextareaField = TextareaField<IonicTextareaProps>;
|
|
|
231
231
|
interface IonicToggleProps {
|
|
232
232
|
labelPlacement?: 'start' | 'end' | 'fixed' | 'stacked';
|
|
233
233
|
justify?: 'start' | 'end' | 'space-between';
|
|
234
|
-
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger';
|
|
234
|
+
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'danger' | 'light' | 'medium' | 'dark';
|
|
235
235
|
enableOnOffLabels?: boolean;
|
|
236
236
|
hint?: DynamicText;
|
|
237
237
|
}
|