@frame-kit/ui-ng 0.2.8 → 0.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +8 -0
- package/fesm2022/frame-kit-ui-ng-forms.mjs +35 -4
- package/fesm2022/frame-kit-ui-ng-forms.mjs.map +1 -1
- package/fesm2022/frame-kit-ui-ng-services-i18n.mjs +97 -0
- package/fesm2022/frame-kit-ui-ng-services-i18n.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng.mjs +1 -0
- package/fesm2022/frame-kit-ui-ng.mjs.map +1 -1
- package/package.json +6 -1
- package/services/i18n/README.md +102 -0
- package/types/frame-kit-ui-ng-forms.d.ts +19 -2
- package/types/frame-kit-ui-ng-services-i18n.d.ts +81 -0
- package/types/frame-kit-ui-ng.d.ts +1 -0
package/COMPONENTS.md
CHANGED
|
@@ -83,6 +83,7 @@ Organized by **purpose** (not Atomic Design) into six layers with strict depende
|
|
|
83
83
|
### Services — runtime services with no UI
|
|
84
84
|
|
|
85
85
|
- [OverlayOrchestrator](#overlayorchestrator)
|
|
86
|
+
- [ReactiveI18nService](#reactivei18nservice)
|
|
86
87
|
- [SpotlightService](#spotlightservice)
|
|
87
88
|
- [ToastService](#toastservice)
|
|
88
89
|
|
|
@@ -631,6 +632,13 @@ Centralized priority stack for dialogs, drawers, popovers, and navigation panels
|
|
|
631
632
|
|
|
632
633
|
---
|
|
633
634
|
|
|
635
|
+
### ReactiveI18nService
|
|
636
|
+
|
|
637
|
+
Message lookup by dot-path key with `{{var}}` interpolation and a minimal ICU plural subset, backed by signals so a locale switch re-renders every template reading it. Provided with `provideI18n`, injected via `I18N_SERVICE`; the framework-free core lives in `@frame-kit/utils` so a server can render the same copy.
|
|
638
|
+
[README](https://github.com/frame-kit/packages/blob/main/packages/ui-ng/services/i18n/README.md)
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
634
642
|
### SpotlightService
|
|
635
643
|
|
|
636
644
|
Coordinates a single global "active key" with reference-counted holders, so unrelated parts of the DOM can pulse together when the same key is activated. The `fkSpotlightTrigger` / `fkSpotlightTarget` directives are the typical consumers.
|
|
@@ -289,6 +289,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
289
289
|
args: ['attr.for']
|
|
290
290
|
}] } });
|
|
291
291
|
|
|
292
|
+
const FK_LABEL_ACTION = new InjectionToken('FK_LABEL_ACTION');
|
|
293
|
+
/**
|
|
294
|
+
* Marks content that belongs on the label's own row, aligned to the trailing
|
|
295
|
+
* edge — a "Forgot password?" link beside a Password label being the canonical
|
|
296
|
+
* case.
|
|
297
|
+
*
|
|
298
|
+
* It sits outside the `<label>` element deliberately. A link inside a label is
|
|
299
|
+
* activated when the label is clicked, so the user reaches for the link and
|
|
300
|
+
* focuses the input instead; and its text would join the input's accessible
|
|
301
|
+
* name.
|
|
302
|
+
*/
|
|
303
|
+
class FkLabelActionDirective {
|
|
304
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FkLabelActionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
305
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: FkLabelActionDirective, isStandalone: true, selector: "[fkLabelAction]", providers: [{ provide: FK_LABEL_ACTION, useExisting: FkLabelActionDirective }], ngImport: i0 });
|
|
306
|
+
}
|
|
307
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FkLabelActionDirective, decorators: [{
|
|
308
|
+
type: Directive,
|
|
309
|
+
args: [{
|
|
310
|
+
selector: '[fkLabelAction]',
|
|
311
|
+
standalone: true,
|
|
312
|
+
providers: [{ provide: FK_LABEL_ACTION, useExisting: FkLabelActionDirective }],
|
|
313
|
+
}]
|
|
314
|
+
}] });
|
|
315
|
+
|
|
292
316
|
const FK_PREFIX = new InjectionToken('FK_PREFIX');
|
|
293
317
|
class FkPrefixDirective {
|
|
294
318
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FkPrefixDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -349,6 +373,7 @@ class FormFieldComponent {
|
|
|
349
373
|
hintRef = contentChild(HintComponent, ...(ngDevMode ? [{ debugName: "hintRef" }] : /* istanbul ignore next */ []));
|
|
350
374
|
errorRef = contentChild(ErrorComponent, ...(ngDevMode ? [{ debugName: "errorRef" }] : /* istanbul ignore next */ []));
|
|
351
375
|
labelRef = contentChild(LabelComponent, ...(ngDevMode ? [{ debugName: "labelRef" }] : /* istanbul ignore next */ []));
|
|
376
|
+
labelActionRef = contentChild(FK_LABEL_ACTION, ...(ngDevMode ? [{ debugName: "labelActionRef" }] : /* istanbul ignore next */ []));
|
|
352
377
|
prefixRef = contentChild(FK_PREFIX, ...(ngDevMode ? [{ debugName: "prefixRef" }] : /* istanbul ignore next */ []));
|
|
353
378
|
suffixRef = contentChild(FK_SUFFIX, ...(ngDevMode ? [{ debugName: "suffixRef" }] : /* istanbul ignore next */ []));
|
|
354
379
|
// ===== INJECTED SERVICES =====
|
|
@@ -375,6 +400,12 @@ class FormFieldComponent {
|
|
|
375
400
|
warnOnUnresolvedProjection() {
|
|
376
401
|
const checks = [
|
|
377
402
|
['fkPrefix', 'FkPrefixDirective', 'prefix', this.prefixRef()],
|
|
403
|
+
[
|
|
404
|
+
'fkLabelAction',
|
|
405
|
+
'FkLabelActionDirective',
|
|
406
|
+
'label-action',
|
|
407
|
+
this.labelActionRef(),
|
|
408
|
+
],
|
|
378
409
|
['fkSuffix', 'FkSuffixDirective', 'suffix', this.suffixRef()],
|
|
379
410
|
];
|
|
380
411
|
for (const [attribute, directive, slot, resolved] of checks) {
|
|
@@ -535,12 +566,12 @@ class FormFieldComponent {
|
|
|
535
566
|
control.setDescribedByIds(ids);
|
|
536
567
|
}
|
|
537
568
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
538
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: FormFieldComponent, isStandalone: true, selector: "fk-form-field", inputs: { className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, showErrorsOn: { classPropertyName: "showErrorsOn", publicName: "showErrorsOn", isSignal: true, isRequired: false, transformFunction: null }, submitted: { classPropertyName: "submitted", publicName: "submitted", isSignal: true, isRequired: false, transformFunction: null }, externalDescribedBy: { classPropertyName: "externalDescribedBy", publicName: "externalDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, fallbackControl: { classPropertyName: "fallbackControl", publicName: "fallbackControl", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "control", first: true, predicate: FIELD_CONTROL, descendants: true, isSignal: true }, { propertyName: "hintRef", first: true, predicate: HintComponent, descendants: true, isSignal: true }, { propertyName: "errorRef", first: true, predicate: ErrorComponent, descendants: true, isSignal: true }, { propertyName: "labelRef", first: true, predicate: LabelComponent, descendants: true, isSignal: true }, { propertyName: "prefixRef", first: true, predicate: FK_PREFIX, descendants: true, isSignal: true }, { propertyName: "suffixRef", first: true, predicate: FK_SUFFIX, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fk-form-field__wrapper\">\n @if (label() || labelRef()) {\n <div class=\"fk-form-field__label-row\">\n <label\n class=\"fk-form-field__label\"\n [attr.id]=\"labelId\"\n [attr.for]=\"control()?.id ?? null\"\n >\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content select=\"fk-label\" />\n }\n </label>\n <!-- The required marker lives OUTSIDE the <label> so it never leaks into\n the label's text/accessible name (keeping getByLabel + AT clean); the\n input's aria-required conveys the requirement to assistive tech. -->\n @if (isRequired()) {\n <span class=\"fk-form-field__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-form-field__control\"\n (click)=\"control()?.onContainerClick?.($event)\"\n >\n <!-- Rendered unconditionally, and deliberately so. Gating these on the\n directive resolving means a consumer who marks an element `fkPrefix`\n but forgets to import `FkPrefixDirective` gets no slot, and because an\n unprojected node is never placed in the DOM at all, their icon\n disappears with no error anywhere. Both wrappers are absolutely\n positioned and `:empty`-hidden, so rendering them always costs nothing\n and turns that failure into something visible. -->\n <div class=\"fk-form-field__prefix\">\n <ng-content select=\"[fkPrefix]\" />\n </div>\n <ng-content />\n <div class=\"fk-form-field__suffix\">\n <ng-content select=\"[fkSuffix]\" />\n </div>\n </div>\n\n <div class=\"fk-form-field__subscript\">\n @if (showError()) {\n @if (hasAutoError) {\n <span class=\"fk-error\" role=\"alert\" [attr.id]=\"autoErrorId\">\n {{ autoErrorMessage() }}\n </span>\n } @else {\n <ng-content select=\"fk-error\" />\n }\n } @else {\n <ng-content select=\"fk-hint\" />\n }\n </div>\n</div>\n", styles: [":host{display:block}.fk-form-field__wrapper{display:flex;flex-direction:column}.fk-form-field__label-row{display:flex;align-items:center;gap:.25em;margin-top:var(--fk-form-label-margin-top, var(--fk-rhythm-2, .5rem))}.fk-form-field__label{display:flex;align-items:center;gap:.25em;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-label-font-size, var(--fk-typography-label-font-size, .8125rem));font-weight:var(--fk-form-label-font-weight, var(--fk-typography-label-font-weight, 600));line-height:var(--fk-form-label-line-height, var(--fk-typography-label-line-height, 1.25));color:var(--fk-form-label-color, var(--fk-color-text-strong, #0b1420));cursor:default}.fk-form-field__label fk-icon{flex:none;color:var(--fk-form-label-icon-color, currentColor)}.fk-form-field__required{color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}.fk-form-field__control{position:relative;margin-top:var(--fk-form-label-gap, var(--fk-rhythm-2, .5rem))}.fk-form-field__prefix,.fk-form-field__suffix{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;color:var(--fk-input-placeholder-color, var(--fk-color-muted, #8a98a8));z-index:1}.fk-form-field__prefix{pointer-events:none}.fk-form-field__prefix:empty,.fk-form-field__suffix:empty{display:none}.fk-form-field__prefix{left:var(--fk-input-affix-offset, .75rem)}.fk-form-field__suffix{right:var(--fk-input-affix-offset, .75rem)}.fk-form-field__subscript{display:var(--fk-form-subscript-display, block);min-height:var(--fk-form-subscript-min-height, calc(var(--fk-form-hint-font-size, var(--fk-typography-small-font-size, .8125rem)) * 1.4));margin-top:var(--fk-form-subscript-gap, var(--fk-rhythm-1, .25rem))}.fk-form-field__subscript .fk-error{display:block;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-error-font-size, var(--fk-typography-small-font-size, .8125rem));line-height:1.4;color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}:host(.fk-form-field--focused) .fk-form-field__label{color:var(--fk-input-border-color-focus, var(--fk-color-primary, #0a84ff))}:host(.fk-form-field--disabled) .fk-form-field__label{opacity:var(--fk-input-disabled-opacity, .5);cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
569
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: FormFieldComponent, isStandalone: true, selector: "fk-form-field", inputs: { className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, showErrorsOn: { classPropertyName: "showErrorsOn", publicName: "showErrorsOn", isSignal: true, isRequired: false, transformFunction: null }, submitted: { classPropertyName: "submitted", publicName: "submitted", isSignal: true, isRequired: false, transformFunction: null }, externalDescribedBy: { classPropertyName: "externalDescribedBy", publicName: "externalDescribedBy", isSignal: true, isRequired: false, transformFunction: null }, fallbackControl: { classPropertyName: "fallbackControl", publicName: "fallbackControl", isSignal: true, isRequired: false, transformFunction: null }, errorMessages: { classPropertyName: "errorMessages", publicName: "errorMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.hostClass" } }, queries: [{ propertyName: "control", first: true, predicate: FIELD_CONTROL, descendants: true, isSignal: true }, { propertyName: "hintRef", first: true, predicate: HintComponent, descendants: true, isSignal: true }, { propertyName: "errorRef", first: true, predicate: ErrorComponent, descendants: true, isSignal: true }, { propertyName: "labelRef", first: true, predicate: LabelComponent, descendants: true, isSignal: true }, { propertyName: "labelActionRef", first: true, predicate: FK_LABEL_ACTION, descendants: true, isSignal: true }, { propertyName: "prefixRef", first: true, predicate: FK_PREFIX, descendants: true, isSignal: true }, { propertyName: "suffixRef", first: true, predicate: FK_SUFFIX, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fk-form-field__wrapper\">\n @if (label() || labelRef()) {\n <div class=\"fk-form-field__label-row\">\n <label\n class=\"fk-form-field__label\"\n [attr.id]=\"labelId\"\n [attr.for]=\"control()?.id ?? null\"\n >\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content select=\"fk-label\" />\n }\n </label>\n <!-- The required marker lives OUTSIDE the <label> so it never leaks into\n the label's text/accessible name (keeping getByLabel + AT clean); the\n input's aria-required conveys the requirement to assistive tech. -->\n @if (isRequired()) {\n <span class=\"fk-form-field__required\" aria-hidden=\"true\">*</span>\n }\n\n <!-- Trailing content on the label's row. Outside the <label> so it is not\n activated by a label click and does not join the input's accessible\n name. Rendered unconditionally for the same reason as the prefix and\n suffix slots: an unprojected node is never placed in the DOM, so\n gating this on the directive would make a forgotten import vanish\n silently. `:empty` keeps it from taking space. -->\n <div class=\"fk-form-field__label-action\">\n <ng-content select=\"[fkLabelAction]\" />\n </div>\n </div>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-form-field__control\"\n (click)=\"control()?.onContainerClick?.($event)\"\n >\n <!-- Rendered unconditionally, and deliberately so. Gating these on the\n directive resolving means a consumer who marks an element `fkPrefix`\n but forgets to import `FkPrefixDirective` gets no slot, and because an\n unprojected node is never placed in the DOM at all, their icon\n disappears with no error anywhere. Both wrappers are absolutely\n positioned and `:empty`-hidden, so rendering them always costs nothing\n and turns that failure into something visible. -->\n <div class=\"fk-form-field__prefix\">\n <ng-content select=\"[fkPrefix]\" />\n </div>\n <ng-content />\n <div class=\"fk-form-field__suffix\">\n <ng-content select=\"[fkSuffix]\" />\n </div>\n </div>\n\n <div class=\"fk-form-field__subscript\">\n @if (showError()) {\n @if (hasAutoError) {\n <span class=\"fk-error\" role=\"alert\" [attr.id]=\"autoErrorId\">\n {{ autoErrorMessage() }}\n </span>\n } @else {\n <ng-content select=\"fk-error\" />\n }\n } @else {\n <ng-content select=\"fk-hint\" />\n }\n </div>\n</div>\n", styles: [":host{display:block}.fk-form-field__wrapper{display:flex;flex-direction:column}.fk-form-field__label-action{margin-inline-start:auto;display:flex;align-items:baseline}.fk-form-field__label-action:empty{display:none}.fk-form-field__label-row{display:flex;align-items:center;gap:.25em;margin-top:var(--fk-form-label-margin-top, var(--fk-rhythm-2, .5rem))}.fk-form-field__label{display:flex;align-items:center;gap:.25em;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-label-font-size, var(--fk-typography-label-font-size, .8125rem));font-weight:var(--fk-form-label-font-weight, var(--fk-typography-label-font-weight, 600));line-height:var(--fk-form-label-line-height, var(--fk-typography-label-line-height, 1.25));color:var(--fk-form-label-color, var(--fk-color-text-strong, #0b1420));cursor:default}.fk-form-field__label fk-icon{flex:none;color:var(--fk-form-label-icon-color, currentColor)}.fk-form-field__required{color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}.fk-form-field__control{position:relative;margin-top:var(--fk-form-label-gap, var(--fk-rhythm-2, .5rem))}.fk-form-field__prefix,.fk-form-field__suffix{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;color:var(--fk-input-placeholder-color, var(--fk-color-muted, #8a98a8));z-index:1}.fk-form-field__prefix{pointer-events:none}.fk-form-field__prefix:empty,.fk-form-field__suffix:empty{display:none}.fk-form-field__prefix{left:var(--fk-input-affix-offset, .75rem)}.fk-form-field__suffix{right:var(--fk-input-affix-offset, .75rem)}.fk-form-field__subscript{display:var(--fk-form-subscript-display, block);min-height:var(--fk-form-subscript-min-height, calc(var(--fk-form-hint-font-size, var(--fk-typography-small-font-size, .8125rem)) * 1.4));margin-top:var(--fk-form-subscript-gap, var(--fk-rhythm-1, .25rem))}.fk-form-field__subscript .fk-error{display:block;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-error-font-size, var(--fk-typography-small-font-size, .8125rem));line-height:1.4;color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}:host(.fk-form-field--focused) .fk-form-field__label{color:var(--fk-input-border-color-focus, var(--fk-color-primary, #0a84ff))}:host(.fk-form-field--disabled) .fk-form-field__label{opacity:var(--fk-input-disabled-opacity, .5);cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
539
570
|
}
|
|
540
571
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: FormFieldComponent, decorators: [{
|
|
541
572
|
type: Component,
|
|
542
|
-
args: [{ selector: 'fk-form-field', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fk-form-field__wrapper\">\n @if (label() || labelRef()) {\n <div class=\"fk-form-field__label-row\">\n <label\n class=\"fk-form-field__label\"\n [attr.id]=\"labelId\"\n [attr.for]=\"control()?.id ?? null\"\n >\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content select=\"fk-label\" />\n }\n </label>\n <!-- The required marker lives OUTSIDE the <label> so it never leaks into\n the label's text/accessible name (keeping getByLabel + AT clean); the\n input's aria-required conveys the requirement to assistive tech. -->\n @if (isRequired()) {\n <span class=\"fk-form-field__required\" aria-hidden=\"true\">*</span>\n }\n </div>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-form-field__control\"\n (click)=\"control()?.onContainerClick?.($event)\"\n >\n <!-- Rendered unconditionally, and deliberately so. Gating these on the\n directive resolving means a consumer who marks an element `fkPrefix`\n but forgets to import `FkPrefixDirective` gets no slot, and because an\n unprojected node is never placed in the DOM at all, their icon\n disappears with no error anywhere. Both wrappers are absolutely\n positioned and `:empty`-hidden, so rendering them always costs nothing\n and turns that failure into something visible. -->\n <div class=\"fk-form-field__prefix\">\n <ng-content select=\"[fkPrefix]\" />\n </div>\n <ng-content />\n <div class=\"fk-form-field__suffix\">\n <ng-content select=\"[fkSuffix]\" />\n </div>\n </div>\n\n <div class=\"fk-form-field__subscript\">\n @if (showError()) {\n @if (hasAutoError) {\n <span class=\"fk-error\" role=\"alert\" [attr.id]=\"autoErrorId\">\n {{ autoErrorMessage() }}\n </span>\n } @else {\n <ng-content select=\"fk-error\" />\n }\n } @else {\n <ng-content select=\"fk-hint\" />\n }\n </div>\n</div>\n", styles: [":host{display:block}.fk-form-field__wrapper{display:flex;flex-direction:column}.fk-form-field__label-row{display:flex;align-items:center;gap:.25em;margin-top:var(--fk-form-label-margin-top, var(--fk-rhythm-2, .5rem))}.fk-form-field__label{display:flex;align-items:center;gap:.25em;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-label-font-size, var(--fk-typography-label-font-size, .8125rem));font-weight:var(--fk-form-label-font-weight, var(--fk-typography-label-font-weight, 600));line-height:var(--fk-form-label-line-height, var(--fk-typography-label-line-height, 1.25));color:var(--fk-form-label-color, var(--fk-color-text-strong, #0b1420));cursor:default}.fk-form-field__label fk-icon{flex:none;color:var(--fk-form-label-icon-color, currentColor)}.fk-form-field__required{color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}.fk-form-field__control{position:relative;margin-top:var(--fk-form-label-gap, var(--fk-rhythm-2, .5rem))}.fk-form-field__prefix,.fk-form-field__suffix{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;color:var(--fk-input-placeholder-color, var(--fk-color-muted, #8a98a8));z-index:1}.fk-form-field__prefix{pointer-events:none}.fk-form-field__prefix:empty,.fk-form-field__suffix:empty{display:none}.fk-form-field__prefix{left:var(--fk-input-affix-offset, .75rem)}.fk-form-field__suffix{right:var(--fk-input-affix-offset, .75rem)}.fk-form-field__subscript{display:var(--fk-form-subscript-display, block);min-height:var(--fk-form-subscript-min-height, calc(var(--fk-form-hint-font-size, var(--fk-typography-small-font-size, .8125rem)) * 1.4));margin-top:var(--fk-form-subscript-gap, var(--fk-rhythm-1, .25rem))}.fk-form-field__subscript .fk-error{display:block;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-error-font-size, var(--fk-typography-small-font-size, .8125rem));line-height:1.4;color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}:host(.fk-form-field--focused) .fk-form-field__label{color:var(--fk-input-border-color-focus, var(--fk-color-primary, #0a84ff))}:host(.fk-form-field--disabled) .fk-form-field__label{opacity:var(--fk-input-disabled-opacity, .5);cursor:not-allowed}\n"] }]
|
|
543
|
-
}], ctorParameters: () => [], propDecorators: { className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], showErrorsOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrorsOn", required: false }] }], submitted: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitted", required: false }] }], externalDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalDescribedBy", required: false }] }], fallbackControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackControl", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FIELD_CONTROL), { isSignal: true }] }], hintRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => HintComponent), { isSignal: true }] }], errorRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ErrorComponent), { isSignal: true }] }], labelRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => LabelComponent), { isSignal: true }] }], prefixRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_PREFIX), { isSignal: true }] }], suffixRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_SUFFIX), { isSignal: true }] }], hostClass: [{
|
|
573
|
+
args: [{ selector: 'fk-form-field', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fk-form-field__wrapper\">\n @if (label() || labelRef()) {\n <div class=\"fk-form-field__label-row\">\n <label\n class=\"fk-form-field__label\"\n [attr.id]=\"labelId\"\n [attr.for]=\"control()?.id ?? null\"\n >\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content select=\"fk-label\" />\n }\n </label>\n <!-- The required marker lives OUTSIDE the <label> so it never leaks into\n the label's text/accessible name (keeping getByLabel + AT clean); the\n input's aria-required conveys the requirement to assistive tech. -->\n @if (isRequired()) {\n <span class=\"fk-form-field__required\" aria-hidden=\"true\">*</span>\n }\n\n <!-- Trailing content on the label's row. Outside the <label> so it is not\n activated by a label click and does not join the input's accessible\n name. Rendered unconditionally for the same reason as the prefix and\n suffix slots: an unprojected node is never placed in the DOM, so\n gating this on the directive would make a forgotten import vanish\n silently. `:empty` keeps it from taking space. -->\n <div class=\"fk-form-field__label-action\">\n <ng-content select=\"[fkLabelAction]\" />\n </div>\n </div>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"fk-form-field__control\"\n (click)=\"control()?.onContainerClick?.($event)\"\n >\n <!-- Rendered unconditionally, and deliberately so. Gating these on the\n directive resolving means a consumer who marks an element `fkPrefix`\n but forgets to import `FkPrefixDirective` gets no slot, and because an\n unprojected node is never placed in the DOM at all, their icon\n disappears with no error anywhere. Both wrappers are absolutely\n positioned and `:empty`-hidden, so rendering them always costs nothing\n and turns that failure into something visible. -->\n <div class=\"fk-form-field__prefix\">\n <ng-content select=\"[fkPrefix]\" />\n </div>\n <ng-content />\n <div class=\"fk-form-field__suffix\">\n <ng-content select=\"[fkSuffix]\" />\n </div>\n </div>\n\n <div class=\"fk-form-field__subscript\">\n @if (showError()) {\n @if (hasAutoError) {\n <span class=\"fk-error\" role=\"alert\" [attr.id]=\"autoErrorId\">\n {{ autoErrorMessage() }}\n </span>\n } @else {\n <ng-content select=\"fk-error\" />\n }\n } @else {\n <ng-content select=\"fk-hint\" />\n }\n </div>\n</div>\n", styles: [":host{display:block}.fk-form-field__wrapper{display:flex;flex-direction:column}.fk-form-field__label-action{margin-inline-start:auto;display:flex;align-items:baseline}.fk-form-field__label-action:empty{display:none}.fk-form-field__label-row{display:flex;align-items:center;gap:.25em;margin-top:var(--fk-form-label-margin-top, var(--fk-rhythm-2, .5rem))}.fk-form-field__label{display:flex;align-items:center;gap:.25em;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-label-font-size, var(--fk-typography-label-font-size, .8125rem));font-weight:var(--fk-form-label-font-weight, var(--fk-typography-label-font-weight, 600));line-height:var(--fk-form-label-line-height, var(--fk-typography-label-line-height, 1.25));color:var(--fk-form-label-color, var(--fk-color-text-strong, #0b1420));cursor:default}.fk-form-field__label fk-icon{flex:none;color:var(--fk-form-label-icon-color, currentColor)}.fk-form-field__required{color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}.fk-form-field__control{position:relative;margin-top:var(--fk-form-label-gap, var(--fk-rhythm-2, .5rem))}.fk-form-field__prefix,.fk-form-field__suffix{position:absolute;top:50%;transform:translateY(-50%);display:flex;align-items:center;color:var(--fk-input-placeholder-color, var(--fk-color-muted, #8a98a8));z-index:1}.fk-form-field__prefix{pointer-events:none}.fk-form-field__prefix:empty,.fk-form-field__suffix:empty{display:none}.fk-form-field__prefix{left:var(--fk-input-affix-offset, .75rem)}.fk-form-field__suffix{right:var(--fk-input-affix-offset, .75rem)}.fk-form-field__subscript{display:var(--fk-form-subscript-display, block);min-height:var(--fk-form-subscript-min-height, calc(var(--fk-form-hint-font-size, var(--fk-typography-small-font-size, .8125rem)) * 1.4));margin-top:var(--fk-form-subscript-gap, var(--fk-rhythm-1, .25rem))}.fk-form-field__subscript .fk-error{display:block;font-family:var(--fk-font-family-base, \"Inter\", ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, \"Apple Color Emoji\", \"Segoe UI Emoji\");font-size:var(--fk-form-error-font-size, var(--fk-typography-small-font-size, .8125rem));line-height:1.4;color:var(--fk-form-error-color, var(--fk-color-danger, #e02424))}:host(.fk-form-field--focused) .fk-form-field__label{color:var(--fk-input-border-color-focus, var(--fk-color-primary, #0a84ff))}:host(.fk-form-field--disabled) .fk-form-field__label{opacity:var(--fk-input-disabled-opacity, .5);cursor:not-allowed}\n"] }]
|
|
574
|
+
}], ctorParameters: () => [], propDecorators: { className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], showErrorsOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrorsOn", required: false }] }], submitted: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitted", required: false }] }], externalDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalDescribedBy", required: false }] }], fallbackControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackControl", required: false }] }], errorMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessages", required: false }] }], control: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FIELD_CONTROL), { isSignal: true }] }], hintRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => HintComponent), { isSignal: true }] }], errorRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ErrorComponent), { isSignal: true }] }], labelRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => LabelComponent), { isSignal: true }] }], labelActionRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_LABEL_ACTION), { isSignal: true }] }], prefixRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_PREFIX), { isSignal: true }] }], suffixRef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => FK_SUFFIX), { isSignal: true }] }], hostClass: [{
|
|
544
575
|
type: HostBinding,
|
|
545
576
|
args: ['class']
|
|
546
577
|
}] } });
|
|
@@ -3719,5 +3750,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
3719
3750
|
* Generated bundle index. Do not edit.
|
|
3720
3751
|
*/
|
|
3721
3752
|
|
|
3722
|
-
export { AutocompleteComponent, CheckboxComponent, DEFAULT_ERROR_MESSAGES, DateInputComponent, DatetimeInputComponent, ERROR_MESSAGES, ErrorComponent, FIELD_CONTROL, FK_AUTOCOMPLETE_OPTION_TPL, FK_FILE_DROPZONE_ICON, FK_PREFIX, FK_SUFFIX, FORM, FieldArrayOutletComponent, FieldGroupComponent, FieldOutletComponent, FieldRegistry, FileDropzoneComponent, FileUploadComponent, FkAutocompleteOptionTplDirective, FkFileDropzoneIconDirective, FkPrefixDirective, FkSuffixDirective, FormComponent, FormFieldComponent, FormRendererComponent, FormSectionComponent, HintComponent, InputComponent, LabelComponent, NumberInputComponent, PasswordInputComponent, RadioComponent, SchemaParser, SectionOutletComponent, SegmentedBarComponent, SelectComponent, SliderComponent, SwitchComponent, TagInputComponent, TextareaComponent, TimeInputComponent, ValidationRegistry, getError, getFieldState, getInvalidFields, hasError, interpolateMessage, isFormValid, markAllTouched, resolveErrorMessage };
|
|
3753
|
+
export { AutocompleteComponent, CheckboxComponent, DEFAULT_ERROR_MESSAGES, DateInputComponent, DatetimeInputComponent, ERROR_MESSAGES, ErrorComponent, FIELD_CONTROL, FK_AUTOCOMPLETE_OPTION_TPL, FK_FILE_DROPZONE_ICON, FK_LABEL_ACTION, FK_PREFIX, FK_SUFFIX, FORM, FieldArrayOutletComponent, FieldGroupComponent, FieldOutletComponent, FieldRegistry, FileDropzoneComponent, FileUploadComponent, FkAutocompleteOptionTplDirective, FkFileDropzoneIconDirective, FkLabelActionDirective, FkPrefixDirective, FkSuffixDirective, FormComponent, FormFieldComponent, FormRendererComponent, FormSectionComponent, HintComponent, InputComponent, LabelComponent, NumberInputComponent, PasswordInputComponent, RadioComponent, SchemaParser, SectionOutletComponent, SegmentedBarComponent, SelectComponent, SliderComponent, SwitchComponent, TagInputComponent, TextareaComponent, TimeInputComponent, ValidationRegistry, getError, getFieldState, getInvalidFields, hasError, interpolateMessage, isFormValid, markAllTouched, resolveErrorMessage };
|
|
3723
3754
|
//# sourceMappingURL=frame-kit-ui-ng-forms.mjs.map
|