fold-ng 0.24.0 → 0.25.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/CHANGELOG.md CHANGED
@@ -8,6 +8,47 @@ All notable changes to **fold-ng** are documented here. The format follows
8
8
 
9
9
  _Nothing yet._
10
10
 
11
+ ## [0.25.0] - 2026-09-05
12
+
13
+ ### Added
14
+
15
+ - **`fold-search` devient un contrôle, et non plus un capteur.** Sa `value` est
16
+ un `model()` : la boîte se pilote donc de l'extérieur. C'est ce qui manquait
17
+ pour qu'elle remplace une recherche écrite à la main — choisir un filtre
18
+ ailleurs doit pouvoir VIDER le champ, et une recherche en écriture seule
19
+ continuait d'afficher un terme que les résultats n'honoraient plus.
20
+
21
+ Deux façons de s'en servir, et elles répondent à deux questions : `[(value)]`
22
+ donne le terme comme **état**, à chaque frappe — c'est ce que veut un filtrage
23
+ d'un tableau déjà en mémoire, où l'anti-rebond n'ajoute que de la latence ;
24
+ `(searchChange)` le donne comme **événement**, une fois posé — c'est ce que
25
+ veut une requête au serveur. Les deux se composent. Écrire `value` de
26
+ l'extérieur n'émet jamais : celui qui écrit sait déjà.
27
+
28
+ - **`fold-search` porte enfin sa loupe, sa croix et son compte.** Les trois
29
+ étaient recopiés dans chaque écran, avec le même oubli à chaque fois : le
30
+ compte de résultats change sous une recherche, donc il doit être **annoncé**.
31
+ Il porte `role="status"` et `aria-live="polite"`, et un utilisateur qui ne
32
+ voit pas la grille apprend enfin que quatre cents lignes sont devenues trois.
33
+
34
+ `resultCount` (rien tant qu'il vaut `null`), `resultLabel` (le mot après le
35
+ nombre — « pièces », "rows") et `placement` : `top`, `end` ou `bottom`.
36
+ `end` et non `right` — la bibliothèque se pose en propriétés **logiques**, et
37
+ le compte doit suivre le sens de lecture plutôt qu'un côté de l'écran.
38
+
39
+ - **`fold-input` gagne deux affixes**, et c'est de là que `fold-search` tire les
40
+ siens : `leadingIcon` dessine un glyphe DANS la boîte, avant le texte (le
41
+ champ réserve la place lui-même, et le glyphe ne prend pas le clic) ;
42
+ `clearable` + `clearLabel` posent un `×` de fin tant qu'il y a quelque chose à
43
+ effacer, qui vide la valeur **et rend le focus** — sans quoi il faut un second
44
+ clic pour reprendre la saisie.
45
+
46
+ Les deux sont à `false` par défaut : un champ de formulaire qui s'efface tout
47
+ seul invite l'accident qu'il ne sait pas défaire. Le `×` ne paraît ni en
48
+ lecture seule ni désactivé — il promettrait un geste que le contrôle refuse —
49
+ et un mot de passe `revealable` garde la place de fin : perdre son œil casse
50
+ la saisie, perdre la croix la rend seulement moins commode.
51
+
11
52
  ## [0.24.0] - 2026-08-29
12
53
 
13
54
  ### Added
@@ -2414,7 +2455,8 @@ design-token stylesheet.
2414
2455
  `currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
2415
2456
  strings localise via inputs / providers (`provideFoldPanelLabels`).
2416
2457
 
2417
- [unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.24.0...HEAD
2458
+ [unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.25.0...HEAD
2459
+ [0.25.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.25.0
2418
2460
  [0.24.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.24.0
2419
2461
  [0.23.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.23.0
2420
2462
  [0.22.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.22.1
package/README.md CHANGED
@@ -353,7 +353,7 @@ ships it.
353
353
  | `FoldFieldsetComponent` | `fold-fieldset` | Named group of controls — a real `<fieldset>`/`<legend>` with the browser's margin/padding/3D border undone and the rhythm on tokens. `disabled` disables every control inside (the element's unique power); `hint` wired through `aria-describedby` (`hintPosition` `under`/`inline`); `legend` (empty renders none) or `ariaLabel`; `optional` marks the whole group (not each member); `legendVariant` (`eyebrow`/`heading` — the same two registers as a page-section's title), `direction` (`vertical`/`horizontal`), `appearance` (`plain`/`border`); `--fold-fieldset-gap`. |
354
354
  | `FoldPasswordFieldComponent` | `fold-password-field` | Password input + a live requirements checklist (a dot/tick per rule). Rules injected via `FoldPasswordRule` (`{ label, test }` — regex/zod/anything); `revealable` eye (a `fold-input` capability); `marker` dot/check; `[rules]` slot to redesign the list; `validChange`; Signal Forms. |
355
355
  | `FoldViewToggleComponent` | `fold-view-toggle` | Segmented single-select (Cards/Table, density, chart-mode…). Generic `options` (`{ value, icon?, label?, ariaLabel?, disabled? }`) + `[(value)]`; a real `role="radiogroup"` — roving tabindex, arrow keys, Home/End, disabled-skip; `size`, `iconOnly`, `activeStyle` (raised / accent). |
356
- | `FoldSearchComponent` | `fold-search` | Debounced search box — an `fold-input` that emits `searchChange` once typing settles (`delayMs`), trimmed + de-duplicated. |
356
+ | `FoldSearchComponent` | `fold-search` | Search box — magnifier, clear `×`, optional announced result count (`resultCount` / `resultLabel` / `placement`). `[(value)]` is the term as state (every keystroke); `searchChange` emits it once typing settles (`delayMs`), trimmed + de-duplicated. |
357
357
  | `FoldListboxComponent` / `FoldOptionComponent` | `fold-listbox` / `fold-option` | Styleable single-select — the richer sibling of `fold-select` (native `<select>`) for options that need custom rows (icon, second line, status). On `fold-popover`; `role="listbox"` + `aria-activedescendant`, full keyboard (↑/↓, `Home`/`End`, type-ahead, `Enter`). Signal Forms (`FormValueControl<string>`, `[formField]`/`[(value)]`); shares `fold-input`'s box chrome. |
358
358
  | `FoldMultiselectComponent` | `fold-multiselect` | Multi-select sibling of `fold-listbox` (same popover + `fold-option` rows). Value is a set (`readonly string[]`); activating a row toggles it and the panel stays open. Separate component — not a `multiple` flag — so the Signal-Forms value type stays honest. `role="listbox"` + `aria-multiselectable`; the trigger summarises the picks. |
359
359
  | `FoldOptgroupComponent` | `fold-optgroup` | Labelled group of `<fold-option>`s inside a `fold-listbox` / `fold-multiselect` — the styleable `<optgroup>`. Presentational: `role="group"` + `aria-labelledby` header (no `role="option"`, so keyboard nav skips it); the owner discovers grouped options in document order, so roving crosses groups seamlessly. |
@@ -3070,6 +3070,31 @@ class FoldInputComponent {
3070
3070
  /** Placeholder text. */
3071
3071
  placeholder = input("", /* @ts-ignore */
3072
3072
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
3073
+ /**
3074
+ * An icon drawn **inside the box, before the text** — a magnifier on a search
3075
+ * field, a currency mark on an amount.
3076
+ *
3077
+ * The input reserves the room itself, so the glyph never sits on the text.
3078
+ * Purely decorative: it is `aria-hidden`, and it never replaces a `label` or
3079
+ * an `ariaLabel` — an icon is not an accessible name.
3080
+ */
3081
+ leadingIcon = input(undefined, /* @ts-ignore */
3082
+ ...(ngDevMode ? [{ debugName: "leadingIcon" }] : /* istanbul ignore next */ []));
3083
+ /**
3084
+ * Show a trailing **clear** button while the field holds text.
3085
+ *
3086
+ * The affordance every search box grows by hand: a conditional `×` that empties
3087
+ * the value and gives the focus back, so typing can resume without a second
3088
+ * click. Off by default — a form field that clears itself invites the accident
3089
+ * it cannot undo.
3090
+ *
3091
+ * A `revealable` password wins the trailing slot: the two never make sense
3092
+ * together, and hiding the reveal would be the worse of the two losses.
3093
+ */
3094
+ clearable = input(false, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
3095
+ /** Accessible name of the clear button. Override it to translate. */
3096
+ clearLabel = input("Clear", /* @ts-ignore */
3097
+ ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
3073
3098
  /** Render as read-only. Named `readOnly` (not `readonly`) to avoid the
3074
3099
  * signal-forms `FormField` reserved `readonly` field-state binding. */
3075
3100
  readOnly = input(false, /* @ts-ignore */
@@ -3094,6 +3119,9 @@ class FoldInputComponent {
3094
3119
  ...(ngDevMode ? [{ debugName: "autocomplete" }] : /* istanbul ignore next */ []));
3095
3120
  /** Unique, SSR-safe id for label association (see {@link FoldIdService}). */
3096
3121
  inputId = inject(FoldIdService).next("fold-input");
3122
+ /** The native control — the clear button hands the focus back to it. */
3123
+ field = viewChild("field", /* @ts-ignore */
3124
+ ...(ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []));
3097
3125
  /** The message to show under the field: the first error, once touched. */
3098
3126
  errorMessage = computed(() => {
3099
3127
  if (!this.touched()) {
@@ -3123,9 +3151,25 @@ class FoldInputComponent {
3123
3151
  /** The reveal control's accessible name, tracking its state. */
3124
3152
  revealAria = computed(() => this.revealed() ? this.hideLabel() : this.revealLabel(), /* @ts-ignore */
3125
3153
  ...(ngDevMode ? [{ debugName: "revealAria" }] : /* istanbul ignore next */ []));
3154
+ /**
3155
+ * Whether to render the clear button: asked for, something to clear, and a
3156
+ * field that can still be edited. A `×` over a read-only value would promise
3157
+ * a gesture the control refuses.
3158
+ */
3159
+ showClear = computed(() => this.clearable() &&
3160
+ this.value() !== "" &&
3161
+ !this.disabled() &&
3162
+ !this.readOnly() &&
3163
+ !this.showReveal(), /* @ts-ignore */
3164
+ ...(ngDevMode ? [{ debugName: "showClear" }] : /* istanbul ignore next */ []));
3126
3165
  toggleReveal() {
3127
3166
  this.revealed.update((shown) => !shown);
3128
3167
  }
3168
+ /** Empties the field and returns the focus, so typing resumes in place. */
3169
+ clear() {
3170
+ this.value.set("");
3171
+ this.field()?.nativeElement.focus();
3172
+ }
3129
3173
  /** Handles native input event. `value.set()` also fires the model's
3130
3174
  * auto `valueChange` output for standalone `(valueChange)` consumers. */
3131
3175
  onInputChange(event) {
@@ -3136,14 +3180,14 @@ class FoldInputComponent {
3136
3180
  this.touched.set(true);
3137
3181
  }
3138
3182
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3139
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldInputComponent, isStandalone: true, selector: "fold-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, revealable: { classPropertyName: "revealable", publicName: "revealable", isSignal: true, isRequired: false, transformFunction: null }, revealLabel: { classPropertyName: "revealLabel", publicName: "revealLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, optionalLabel: { classPropertyName: "optionalLabel", publicName: "optionalLabel", isSignal: true, isRequired: false, transformFunction: null }, info: { classPropertyName: "info", publicName: "info", isSignal: true, isRequired: false, transformFunction: null }, infoLabel: { classPropertyName: "infoLabel", publicName: "infoLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { properties: { "class": "size() + \" \" + align() + \" \" + variant()" } }, ngImport: i0, template: "<fold-input-base\n [label]=\"label()\"\n [for]=\"inputId\"\n [required]=\"required()\"\n [optional]=\"optional()\"\n [optionalLabel]=\"optionalLabel()\"\n [info]=\"info()\"\n [infoLabel]=\"infoLabel()\"\n [hint]=\"hint()\"\n [error]=\"errorMessage()\"\n>\n <div class=\"in-field\">\n <input\n [id]=\"inputId\"\n [class.has-reveal]=\"showReveal()\"\n [attr.type]=\"effectiveType()\"\n [attr.placeholder]=\"placeholder()\"\n [attr.readonly]=\"readOnly() || null\"\n [attr.disabled]=\"disabled() || null\"\n [attr.required]=\"required() || null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.autocomplete]=\"autocomplete()\"\n [value]=\"value()\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n />\n @if (showReveal()) {\n <button\n type=\"button\"\n class=\"in-reveal\"\n [attr.aria-label]=\"revealAria()\"\n [attr.aria-pressed]=\"revealed()\"\n [disabled]=\"disabled() || readOnly()\"\n (click)=\"toggleReveal()\"\n >\n <fold-icon\n [name]=\"revealed() ? 'eye-off' : 'eye'\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n </button>\n }\n </div>\n</fold-input-base>\n", styles: ["@charset \"UTF-8\";:host{display:block}input,select,textarea{all:unset;box-sizing:border-box;width:100%;font-family:inherit;color:var(--fold-color-text);background:var(--fold-color-surface-card);border:1px solid var(--fold-color-border-subtle);transition:border-color var(--fold-motion-fast),box-shadow var(--fold-motion-fast)}input::placeholder,select::placeholder,textarea::placeholder{color:var(--fold-color-text-faded)}input:hover:not(:disabled):not(:read-only):not(:focus),select:hover:not(:disabled):not(:read-only):not(:focus),textarea:hover:not(:disabled):not(:read-only):not(:focus){border-color:var(--fold-color-border)}input:focus,select:focus,textarea:focus{border-color:var(--fold-color-primary);box-shadow:0 0 0 2px var(--fold-color-primary-border)}input:disabled,select:disabled,textarea:disabled{opacity:.4;cursor:not-allowed}input:read-only,select:read-only,textarea:read-only{opacity:.6;cursor:default}input[type=number],select[type=number],textarea[type=number]{appearance:textfield;-moz-appearance:textfield}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,select[type=number]::-webkit-inner-spin-button,select[type=number]::-webkit-outer-spin-button,textarea[type=number]::-webkit-inner-spin-button,textarea[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}:host(.sm) input,:host(.sm) select{height:1.75rem;font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.sm) textarea{font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.md) input,:host(.md) select{height:2.25rem;font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.md) textarea{font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.lg) input,:host(.lg) select{height:2.75rem;font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.lg) textarea{font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.center) input{text-align:center}:host(.panel) input,:host(.panel) select,:host(.panel) textarea{height:auto;padding:var(--fold-space-sm) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised)}:host(.panel) input:focus,:host(.panel) select:focus,:host(.panel) textarea:focus{box-shadow:none}.in-field{position:relative}:host input.has-reveal{padding-inline-end:2.1rem}.in-reveal{all:unset;position:absolute;inset-inline-end:.4rem;top:50%;transform:translateY(-50%);display:grid;place-items:center;padding:.2rem;border-radius:var(--fold-radius-xs);color:var(--fold-color-text-muted);cursor:pointer}.in-reveal:hover:not(:disabled),.in-reveal:focus-visible{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.in-reveal:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:1px}.in-reveal:disabled{cursor:not-allowed;opacity:.4}@media(forced-colors:active){.in-reveal:focus-visible{outline-color:Highlight}}\n"], dependencies: [{ kind: "component", type: FoldInputBaseComponent, selector: "fold-input-base", inputs: ["label", "for", "required", "optional", "optionalLabel", "hint", "error", "info", "infoLabel"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
3183
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldInputComponent, isStandalone: true, selector: "fold-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, revealable: { classPropertyName: "revealable", publicName: "revealable", isSignal: true, isRequired: false, transformFunction: null }, revealLabel: { classPropertyName: "revealLabel", publicName: "revealLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, optionalLabel: { classPropertyName: "optionalLabel", publicName: "optionalLabel", isSignal: true, isRequired: false, transformFunction: null }, info: { classPropertyName: "info", publicName: "info", isSignal: true, isRequired: false, transformFunction: null }, infoLabel: { classPropertyName: "infoLabel", publicName: "infoLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, leadingIcon: { classPropertyName: "leadingIcon", publicName: "leadingIcon", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, host: { properties: { "class": "size() + \" \" + align() + \" \" + variant()" } }, viewQueries: [{ propertyName: "field", first: true, predicate: ["field"], descendants: true, isSignal: true }], ngImport: i0, template: "<fold-input-base\n [label]=\"label()\"\n [for]=\"inputId\"\n [required]=\"required()\"\n [optional]=\"optional()\"\n [optionalLabel]=\"optionalLabel()\"\n [info]=\"info()\"\n [infoLabel]=\"infoLabel()\"\n [hint]=\"hint()\"\n [error]=\"errorMessage()\"\n>\n <div class=\"in-field\">\n @if (leadingIcon(); as glyph) {\n <fold-icon class=\"in-lead\" [name]=\"glyph\" size=\"sm\" aria-hidden=\"true\" />\n }\n <input\n #field\n [id]=\"inputId\"\n [class.has-lead]=\"leadingIcon() !== undefined\"\n [class.has-reveal]=\"showReveal() || showClear()\"\n [attr.type]=\"effectiveType()\"\n [attr.placeholder]=\"placeholder()\"\n [attr.readonly]=\"readOnly() || null\"\n [attr.disabled]=\"disabled() || null\"\n [attr.required]=\"required() || null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.autocomplete]=\"autocomplete()\"\n [value]=\"value()\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n />\n @if (showReveal()) {\n <button\n type=\"button\"\n class=\"in-reveal\"\n [attr.aria-label]=\"revealAria()\"\n [attr.aria-pressed]=\"revealed()\"\n [disabled]=\"disabled() || readOnly()\"\n (click)=\"toggleReveal()\"\n >\n <fold-icon\n [name]=\"revealed() ? 'eye-off' : 'eye'\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n </button>\n } @else if (showClear()) {\n <button\n type=\"button\"\n class=\"in-reveal\"\n [attr.aria-label]=\"clearLabel()\"\n (click)=\"clear()\"\n >\n <fold-icon name=\"close\" size=\"sm\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n</fold-input-base>\n", styles: ["@charset \"UTF-8\";:host{display:block}input,select,textarea{all:unset;box-sizing:border-box;width:100%;font-family:inherit;color:var(--fold-color-text);background:var(--fold-color-surface-card);border:1px solid var(--fold-color-border-subtle);transition:border-color var(--fold-motion-fast),box-shadow var(--fold-motion-fast)}input::placeholder,select::placeholder,textarea::placeholder{color:var(--fold-color-text-faded)}input:hover:not(:disabled):not(:read-only):not(:focus),select:hover:not(:disabled):not(:read-only):not(:focus),textarea:hover:not(:disabled):not(:read-only):not(:focus){border-color:var(--fold-color-border)}input:focus,select:focus,textarea:focus{border-color:var(--fold-color-primary);box-shadow:0 0 0 2px var(--fold-color-primary-border)}input:disabled,select:disabled,textarea:disabled{opacity:.4;cursor:not-allowed}input:read-only,select:read-only,textarea:read-only{opacity:.6;cursor:default}input[type=number],select[type=number],textarea[type=number]{appearance:textfield;-moz-appearance:textfield}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,select[type=number]::-webkit-inner-spin-button,select[type=number]::-webkit-outer-spin-button,textarea[type=number]::-webkit-inner-spin-button,textarea[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}:host(.sm) input,:host(.sm) select{height:1.75rem;font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.sm) textarea{font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.md) input,:host(.md) select{height:2.25rem;font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.md) textarea{font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.lg) input,:host(.lg) select{height:2.75rem;font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.lg) textarea{font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.center) input{text-align:center}:host(.panel) input,:host(.panel) select,:host(.panel) textarea{height:auto;padding:var(--fold-space-sm) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised)}:host(.panel) input:focus,:host(.panel) select:focus,:host(.panel) textarea:focus{box-shadow:none}.in-field{position:relative}:host input.has-reveal{padding-inline-end:2.1rem}:host input.has-lead{padding-inline-start:2.1rem}.in-lead{position:absolute;inset-inline-start:.6rem;top:50%;transform:translateY(-50%);display:grid;place-items:center;color:var(--fold-color-text-muted);pointer-events:none}.in-reveal{all:unset;position:absolute;inset-inline-end:.4rem;top:50%;transform:translateY(-50%);display:grid;place-items:center;padding:.2rem;border-radius:var(--fold-radius-xs);color:var(--fold-color-text-muted);cursor:pointer}.in-reveal:hover:not(:disabled),.in-reveal:focus-visible{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.in-reveal:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:1px}.in-reveal:disabled{cursor:not-allowed;opacity:.4}@media(forced-colors:active){.in-reveal:focus-visible{outline-color:Highlight}}\n"], dependencies: [{ kind: "component", type: FoldInputBaseComponent, selector: "fold-input-base", inputs: ["label", "for", "required", "optional", "optionalLabel", "hint", "error", "info", "infoLabel"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
3140
3184
  }
3141
3185
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldInputComponent, decorators: [{
3142
3186
  type: Component,
3143
3187
  args: [{ selector: "fold-input", standalone: true, imports: [FoldInputBaseComponent, FoldIconComponent], host: {
3144
3188
  "[class]": 'size() + " " + align() + " " + variant()',
3145
- }, template: "<fold-input-base\n [label]=\"label()\"\n [for]=\"inputId\"\n [required]=\"required()\"\n [optional]=\"optional()\"\n [optionalLabel]=\"optionalLabel()\"\n [info]=\"info()\"\n [infoLabel]=\"infoLabel()\"\n [hint]=\"hint()\"\n [error]=\"errorMessage()\"\n>\n <div class=\"in-field\">\n <input\n [id]=\"inputId\"\n [class.has-reveal]=\"showReveal()\"\n [attr.type]=\"effectiveType()\"\n [attr.placeholder]=\"placeholder()\"\n [attr.readonly]=\"readOnly() || null\"\n [attr.disabled]=\"disabled() || null\"\n [attr.required]=\"required() || null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.autocomplete]=\"autocomplete()\"\n [value]=\"value()\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n />\n @if (showReveal()) {\n <button\n type=\"button\"\n class=\"in-reveal\"\n [attr.aria-label]=\"revealAria()\"\n [attr.aria-pressed]=\"revealed()\"\n [disabled]=\"disabled() || readOnly()\"\n (click)=\"toggleReveal()\"\n >\n <fold-icon\n [name]=\"revealed() ? 'eye-off' : 'eye'\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n </button>\n }\n </div>\n</fold-input-base>\n", styles: ["@charset \"UTF-8\";:host{display:block}input,select,textarea{all:unset;box-sizing:border-box;width:100%;font-family:inherit;color:var(--fold-color-text);background:var(--fold-color-surface-card);border:1px solid var(--fold-color-border-subtle);transition:border-color var(--fold-motion-fast),box-shadow var(--fold-motion-fast)}input::placeholder,select::placeholder,textarea::placeholder{color:var(--fold-color-text-faded)}input:hover:not(:disabled):not(:read-only):not(:focus),select:hover:not(:disabled):not(:read-only):not(:focus),textarea:hover:not(:disabled):not(:read-only):not(:focus){border-color:var(--fold-color-border)}input:focus,select:focus,textarea:focus{border-color:var(--fold-color-primary);box-shadow:0 0 0 2px var(--fold-color-primary-border)}input:disabled,select:disabled,textarea:disabled{opacity:.4;cursor:not-allowed}input:read-only,select:read-only,textarea:read-only{opacity:.6;cursor:default}input[type=number],select[type=number],textarea[type=number]{appearance:textfield;-moz-appearance:textfield}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,select[type=number]::-webkit-inner-spin-button,select[type=number]::-webkit-outer-spin-button,textarea[type=number]::-webkit-inner-spin-button,textarea[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}:host(.sm) input,:host(.sm) select{height:1.75rem;font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.sm) textarea{font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.md) input,:host(.md) select{height:2.25rem;font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.md) textarea{font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.lg) input,:host(.lg) select{height:2.75rem;font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.lg) textarea{font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.center) input{text-align:center}:host(.panel) input,:host(.panel) select,:host(.panel) textarea{height:auto;padding:var(--fold-space-sm) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised)}:host(.panel) input:focus,:host(.panel) select:focus,:host(.panel) textarea:focus{box-shadow:none}.in-field{position:relative}:host input.has-reveal{padding-inline-end:2.1rem}.in-reveal{all:unset;position:absolute;inset-inline-end:.4rem;top:50%;transform:translateY(-50%);display:grid;place-items:center;padding:.2rem;border-radius:var(--fold-radius-xs);color:var(--fold-color-text-muted);cursor:pointer}.in-reveal:hover:not(:disabled),.in-reveal:focus-visible{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.in-reveal:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:1px}.in-reveal:disabled{cursor:not-allowed;opacity:.4}@media(forced-colors:active){.in-reveal:focus-visible{outline-color:Highlight}}\n"] }]
3146
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], revealable: [{ type: i0.Input, args: [{ isSignal: true, alias: "revealable", required: false }] }], revealLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "revealLabel", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], optionalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabel", required: false }] }], info: [{ type: i0.Input, args: [{ isSignal: true, alias: "info", required: false }] }], infoLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "infoLabel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], autofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autofocus", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }] } });
3189
+ }, template: "<fold-input-base\n [label]=\"label()\"\n [for]=\"inputId\"\n [required]=\"required()\"\n [optional]=\"optional()\"\n [optionalLabel]=\"optionalLabel()\"\n [info]=\"info()\"\n [infoLabel]=\"infoLabel()\"\n [hint]=\"hint()\"\n [error]=\"errorMessage()\"\n>\n <div class=\"in-field\">\n @if (leadingIcon(); as glyph) {\n <fold-icon class=\"in-lead\" [name]=\"glyph\" size=\"sm\" aria-hidden=\"true\" />\n }\n <input\n #field\n [id]=\"inputId\"\n [class.has-lead]=\"leadingIcon() !== undefined\"\n [class.has-reveal]=\"showReveal() || showClear()\"\n [attr.type]=\"effectiveType()\"\n [attr.placeholder]=\"placeholder()\"\n [attr.readonly]=\"readOnly() || null\"\n [attr.disabled]=\"disabled() || null\"\n [attr.required]=\"required() || null\"\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.autocomplete]=\"autocomplete()\"\n [value]=\"value()\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onBlur()\"\n />\n @if (showReveal()) {\n <button\n type=\"button\"\n class=\"in-reveal\"\n [attr.aria-label]=\"revealAria()\"\n [attr.aria-pressed]=\"revealed()\"\n [disabled]=\"disabled() || readOnly()\"\n (click)=\"toggleReveal()\"\n >\n <fold-icon\n [name]=\"revealed() ? 'eye-off' : 'eye'\"\n size=\"sm\"\n aria-hidden=\"true\"\n />\n </button>\n } @else if (showClear()) {\n <button\n type=\"button\"\n class=\"in-reveal\"\n [attr.aria-label]=\"clearLabel()\"\n (click)=\"clear()\"\n >\n <fold-icon name=\"close\" size=\"sm\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n</fold-input-base>\n", styles: ["@charset \"UTF-8\";:host{display:block}input,select,textarea{all:unset;box-sizing:border-box;width:100%;font-family:inherit;color:var(--fold-color-text);background:var(--fold-color-surface-card);border:1px solid var(--fold-color-border-subtle);transition:border-color var(--fold-motion-fast),box-shadow var(--fold-motion-fast)}input::placeholder,select::placeholder,textarea::placeholder{color:var(--fold-color-text-faded)}input:hover:not(:disabled):not(:read-only):not(:focus),select:hover:not(:disabled):not(:read-only):not(:focus),textarea:hover:not(:disabled):not(:read-only):not(:focus){border-color:var(--fold-color-border)}input:focus,select:focus,textarea:focus{border-color:var(--fold-color-primary);box-shadow:0 0 0 2px var(--fold-color-primary-border)}input:disabled,select:disabled,textarea:disabled{opacity:.4;cursor:not-allowed}input:read-only,select:read-only,textarea:read-only{opacity:.6;cursor:default}input[type=number],select[type=number],textarea[type=number]{appearance:textfield;-moz-appearance:textfield}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button,select[type=number]::-webkit-inner-spin-button,select[type=number]::-webkit-outer-spin-button,textarea[type=number]::-webkit-inner-spin-button,textarea[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}:host(.sm) input,:host(.sm) select{height:1.75rem;font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.sm) textarea{font-size:var(--fold-text-sm);padding:.25rem .5rem;border-radius:var(--fold-radius-xs)}:host(.md) input,:host(.md) select{height:2.25rem;font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.md) textarea{font-size:var(--fold-text-base);padding:.4rem .65rem;border-radius:var(--fold-radius-sm)}:host(.lg) input,:host(.lg) select{height:2.75rem;font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.lg) textarea{font-size:var(--fold-text-lg);padding:.5rem .75rem;border-radius:var(--fold-radius-sm)}:host(.center) input{text-align:center}:host(.panel) input,:host(.panel) select,:host(.panel) textarea{height:auto;padding:var(--fold-space-sm) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised)}:host(.panel) input:focus,:host(.panel) select:focus,:host(.panel) textarea:focus{box-shadow:none}.in-field{position:relative}:host input.has-reveal{padding-inline-end:2.1rem}:host input.has-lead{padding-inline-start:2.1rem}.in-lead{position:absolute;inset-inline-start:.6rem;top:50%;transform:translateY(-50%);display:grid;place-items:center;color:var(--fold-color-text-muted);pointer-events:none}.in-reveal{all:unset;position:absolute;inset-inline-end:.4rem;top:50%;transform:translateY(-50%);display:grid;place-items:center;padding:.2rem;border-radius:var(--fold-radius-xs);color:var(--fold-color-text-muted);cursor:pointer}.in-reveal:hover:not(:disabled),.in-reveal:focus-visible{color:var(--fold-color-text);background:var(--fold-color-surface-hover)}.in-reveal:focus-visible{outline:2px solid var(--fold-color-primary-border);outline-offset:1px}.in-reveal:disabled{cursor:not-allowed;opacity:.4}@media(forced-colors:active){.in-reveal:focus-visible{outline-color:Highlight}}\n"] }]
3190
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], revealable: [{ type: i0.Input, args: [{ isSignal: true, alias: "revealable", required: false }] }], revealLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "revealLabel", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], optionalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabel", required: false }] }], info: [{ type: i0.Input, args: [{ isSignal: true, alias: "info", required: false }] }], infoLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "infoLabel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], leadingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadingIcon", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], autofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autofocus", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], field: [{ type: i0.ViewChild, args: ["field", { isSignal: true }] }] } });
3147
3191
 
3148
3192
  /** The English defaults — the base every override merges onto. */
3149
3193
  const FOLD_INLINE_CONFIRM_DEFAULT_LABELS = {
@@ -3386,7 +3430,7 @@ class FoldInlineConfirmComponent {
3386
3430
  this.cancelled.emit();
3387
3431
  }
3388
3432
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldInlineConfirmComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3389
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldInlineConfirmComponent, isStandalone: true, selector: "fold-inline-confirm", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, match: { classPropertyName: "match", publicName: "match", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, confirmIcon: { classPropertyName: "confirmIcon", publicName: "confirmIcon", isSignal: true, isRequired: false, transformFunction: null }, cancelIcon: { classPropertyName: "cancelIcon", publicName: "cancelIcon", isSignal: true, isRequired: false, transformFunction: null }, keepOpenOnConfirm: { classPropertyName: "keepOpenOnConfirm", publicName: "keepOpenOnConfirm", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmed: "confirmed", cancelled: "cancelled", open: "openChange" }, host: { properties: { "class.is-open": "open()" } }, viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerWrap"], descendants: true, isSignal: true }, { propertyName: "groupEl", first: true, predicate: ["groupEl"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!open()) {\n <!-- Idle: the host's projected trigger. A click anywhere in it starts the\n flow; the trigger itself stays a real focusable control (button / anchor),\n so keyboard activation is native (Enter/Space \u2192 click) \u2014 no extra\n role/tabindex, and no keydown handler that would double-fire. -->\n <span #triggerWrap class=\"fic-trigger\" (click)=\"activate()\">\n <ng-content />\n </span>\n} @else {\n <div\n #groupEl\n class=\"fic-confirm\"\n role=\"group\"\n [attr.aria-label]=\"l().group\"\n (keydown.escape)=\"cancel(); $event.stopPropagation()\"\n >\n @if (message(); as text) {\n <p class=\"fic-message\" [id]=\"msgId\">{{ text }}</p>\n }\n\n @if (needsInput()) {\n <fold-input\n class=\"fic-field\"\n [label]=\"prompt()\"\n [type]=\"fieldType()\"\n [size]=\"size() === 'lg' ? 'lg' : 'sm'\"\n [placeholder]=\"placeholder() ?? ''\"\n [autocomplete]=\"password() ? 'current-password' : 'off'\"\n [(value)]=\"typed\"\n (keydown.enter)=\"confirm()\"\n />\n }\n\n <div class=\"fic-actions\">\n <button\n foldButton\n emphasis=\"solid\"\n [intent]=\"intent()\"\n [size]=\"size()\"\n [icon]=\"confirmIcon()\"\n [disabled]=\"!canConfirm()\"\n [attr.aria-describedby]=\"message() ? msgId : null\"\n (click)=\"confirm()\"\n >\n {{ loading() ? l().busy : l().confirm }}\n </button>\n\n @if (cancelIcon(); as icon) {\n <fold-button-icon\n [icon]=\"icon\"\n tone=\"ghost\"\n [size]=\"size()\"\n [disabled]=\"loading()\"\n [tooltip]=\"l().cancelAria\"\n (clicked)=\"cancel()\"\n />\n } @else {\n <button\n foldButton\n emphasis=\"soft\"\n intent=\"neutral\"\n [size]=\"size()\"\n [disabled]=\"loading()\"\n (click)=\"cancel()\"\n >\n {{ l().cancel }}\n </button>\n }\n </div>\n </div>\n}\n", styles: [":host{display:inline-flex;align-items:center;min-width:0}.fic-trigger{display:contents}.fic-confirm{display:inline-flex;flex-direction:column;gap:var(--fold-space-sm);min-width:0;animation:fic-in var(--fold-motion-fast)}.fic-message{margin:0;font-size:var(--fold-text-xs);line-height:var(--fold-leading-normal);color:var(--fold-color-text-secondary)}.fic-field{display:block;width:15rem;max-width:100%}.fic-actions{display:inline-flex;align-items:center;gap:var(--fold-space-xs)}@keyframes fic-in{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.fic-confirm{animation:none}}\n"], dependencies: [{ kind: "component", type: FoldButtonComponent, selector: "button[foldButton], a[foldButton]", inputs: ["emphasis", "intent", "size", "shape", "block", "icon", "iconTrailing", "type", "disabled", "loading"] }, { kind: "component", type: FoldButtonIconComponent, selector: "fold-button-icon", inputs: ["icon", "shape", "size", "tone", "disabled", "loading", "tooltip", "type"], outputs: ["clicked"] }, { kind: "component", type: FoldInputComponent, selector: "fold-input", inputs: ["value", "disabled", "touched", "errors", "type", "revealable", "revealLabel", "hideLabel", "size", "align", "variant", "label", "required", "optional", "optionalLabel", "info", "infoLabel", "ariaLabel", "hint", "placeholder", "readOnly", "autofocus", "autocomplete"], outputs: ["valueChange", "touchedChange"] }] });
3433
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldInlineConfirmComponent, isStandalone: true, selector: "fold-inline-confirm", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, match: { classPropertyName: "match", publicName: "match", isSignal: true, isRequired: false, transformFunction: null }, password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, confirmIcon: { classPropertyName: "confirmIcon", publicName: "confirmIcon", isSignal: true, isRequired: false, transformFunction: null }, cancelIcon: { classPropertyName: "cancelIcon", publicName: "cancelIcon", isSignal: true, isRequired: false, transformFunction: null }, keepOpenOnConfirm: { classPropertyName: "keepOpenOnConfirm", publicName: "keepOpenOnConfirm", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { confirmed: "confirmed", cancelled: "cancelled", open: "openChange" }, host: { properties: { "class.is-open": "open()" } }, viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerWrap"], descendants: true, isSignal: true }, { propertyName: "groupEl", first: true, predicate: ["groupEl"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!open()) {\n <!-- Idle: the host's projected trigger. A click anywhere in it starts the\n flow; the trigger itself stays a real focusable control (button / anchor),\n so keyboard activation is native (Enter/Space \u2192 click) \u2014 no extra\n role/tabindex, and no keydown handler that would double-fire. -->\n <span #triggerWrap class=\"fic-trigger\" (click)=\"activate()\">\n <ng-content />\n </span>\n} @else {\n <div\n #groupEl\n class=\"fic-confirm\"\n role=\"group\"\n [attr.aria-label]=\"l().group\"\n (keydown.escape)=\"cancel(); $event.stopPropagation()\"\n >\n @if (message(); as text) {\n <p class=\"fic-message\" [id]=\"msgId\">{{ text }}</p>\n }\n\n @if (needsInput()) {\n <fold-input\n class=\"fic-field\"\n [label]=\"prompt()\"\n [type]=\"fieldType()\"\n [size]=\"size() === 'lg' ? 'lg' : 'sm'\"\n [placeholder]=\"placeholder() ?? ''\"\n [autocomplete]=\"password() ? 'current-password' : 'off'\"\n [(value)]=\"typed\"\n (keydown.enter)=\"confirm()\"\n />\n }\n\n <div class=\"fic-actions\">\n <button\n foldButton\n emphasis=\"solid\"\n [intent]=\"intent()\"\n [size]=\"size()\"\n [icon]=\"confirmIcon()\"\n [disabled]=\"!canConfirm()\"\n [attr.aria-describedby]=\"message() ? msgId : null\"\n (click)=\"confirm()\"\n >\n {{ loading() ? l().busy : l().confirm }}\n </button>\n\n @if (cancelIcon(); as icon) {\n <fold-button-icon\n [icon]=\"icon\"\n tone=\"ghost\"\n [size]=\"size()\"\n [disabled]=\"loading()\"\n [tooltip]=\"l().cancelAria\"\n (clicked)=\"cancel()\"\n />\n } @else {\n <button\n foldButton\n emphasis=\"soft\"\n intent=\"neutral\"\n [size]=\"size()\"\n [disabled]=\"loading()\"\n (click)=\"cancel()\"\n >\n {{ l().cancel }}\n </button>\n }\n </div>\n </div>\n}\n", styles: [":host{display:inline-flex;align-items:center;min-width:0}.fic-trigger{display:contents}.fic-confirm{display:inline-flex;flex-direction:column;gap:var(--fold-space-sm);min-width:0;animation:fic-in var(--fold-motion-fast)}.fic-message{margin:0;font-size:var(--fold-text-xs);line-height:var(--fold-leading-normal);color:var(--fold-color-text-secondary)}.fic-field{display:block;width:15rem;max-width:100%}.fic-actions{display:inline-flex;align-items:center;gap:var(--fold-space-xs)}@keyframes fic-in{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.fic-confirm{animation:none}}\n"], dependencies: [{ kind: "component", type: FoldButtonComponent, selector: "button[foldButton], a[foldButton]", inputs: ["emphasis", "intent", "size", "shape", "block", "icon", "iconTrailing", "type", "disabled", "loading"] }, { kind: "component", type: FoldButtonIconComponent, selector: "fold-button-icon", inputs: ["icon", "shape", "size", "tone", "disabled", "loading", "tooltip", "type"], outputs: ["clicked"] }, { kind: "component", type: FoldInputComponent, selector: "fold-input", inputs: ["value", "disabled", "touched", "errors", "type", "revealable", "revealLabel", "hideLabel", "size", "align", "variant", "label", "required", "optional", "optionalLabel", "info", "infoLabel", "ariaLabel", "hint", "placeholder", "leadingIcon", "clearable", "clearLabel", "readOnly", "autofocus", "autocomplete"], outputs: ["valueChange", "touchedChange"] }] });
3390
3434
  }
3391
3435
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldInlineConfirmComponent, decorators: [{
3392
3436
  type: Component,
@@ -9293,23 +9337,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
9293
9337
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], optionalLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionalLabel", required: false }] }], info: [{ type: i0.Input, args: [{ isSignal: true, alias: "info", required: false }] }], infoLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "infoLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }] } });
9294
9338
 
9295
9339
  /**
9296
- * `<fold-search>` — an {@link FoldInputComponent} that **debounces its emit**: it
9297
- * fires `searchChange` only once typing pauses for `delayMs`, so a fast typer
9298
- * triggers one query instead of one per keystroke. The delay is adjustable; the
9299
- * emitted term is trimmed and de-duplicated (no emit when the settled value is
9300
- * unchanged). A thin wrapper over the text input — the search *behaviour*, not a
9301
- * new control.
9340
+ * `<fold-search>` — a search box: the magnifier, the clear `×`, an optional
9341
+ * **announced result count**, and a **debounced emit**. `searchChange` fires only once typing pauses for
9342
+ * `delayMs`, so a fast typer triggers one query instead of one per keystroke;
9343
+ * the emitted term is trimmed and de-duplicated.
9344
+ *
9345
+ * `value` is a `model()`, and that is what makes it a control rather than a
9346
+ * one-way sensor. Bind it and the box becomes **steerable from outside** —
9347
+ * picking a filter elsewhere can empty the field, which a write-only search
9348
+ * cannot do: it would keep showing a term the results no longer honour.
9349
+ *
9350
+ * Two ways to use it, and they answer different questions:
9351
+ *
9352
+ * - `[(value)]` — the term as **state**, updated on every keystroke. Filtering
9353
+ * an array already in memory wants this; a debounce there only adds lag.
9354
+ * - `(searchChange)` — the term as an **event**, once it settles. A request to
9355
+ * a server wants this.
9356
+ *
9357
+ * They compose: bind both when a screen filters locally *and* refetches.
9358
+ * Writing `value` from outside never emits `searchChange` — whoever wrote it
9359
+ * already knows.
9302
9360
  *
9303
9361
  * @selector `fold-search`
9304
9362
  *
9305
9363
  * @example
9306
9364
  * ```html
9365
+ * <!-- Local filtering, instant, with the count beside the box -->
9366
+ * <fold-search
9367
+ * placeholder="Filter…"
9368
+ * [(value)]="term"
9369
+ * [resultCount]="rows().length"
9370
+ * resultLabel="rows" />
9371
+ *
9372
+ * <!-- Remote query, once typing settles -->
9307
9373
  * <fold-search
9308
9374
  * placeholder="Search name, email, job…"
9309
9375
  * (searchChange)="store.setSearch($event)" />
9310
9376
  * ```
9311
9377
  */
9312
9378
  class FoldSearchComponent {
9379
+ /**
9380
+ * The term in the box — the SOURCE of truth, not a copy of it.
9381
+ *
9382
+ * Two-way, so a screen can clear or preset it: choosing a category that
9383
+ * supersedes the search empties the field in the same gesture, instead of
9384
+ * leaving a stale term above results that ignore it.
9385
+ */
9386
+ value = model("", /* @ts-ignore */
9387
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
9313
9388
  placeholder = input("", /* @ts-ignore */
9314
9389
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
9315
9390
  size = input("md", /* @ts-ignore */
@@ -9318,18 +9393,74 @@ class FoldSearchComponent {
9318
9393
  * forms; `default` elsewhere). */
9319
9394
  variant = input("default", /* @ts-ignore */
9320
9395
  ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
9396
+ /**
9397
+ * Accessible name, when the design leaves no room for a visible label — the
9398
+ * magnifier is decorative and names nothing.
9399
+ */
9400
+ ariaLabel = input(undefined, /* @ts-ignore */
9401
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
9402
+ /** The `×` that empties the box. On by default: it is what a search box is. */
9403
+ clearable = input(true, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
9404
+ /** Accessible name of the clear button. Override it to translate. */
9405
+ clearLabel = input("Clear search", /* @ts-ignore */
9406
+ ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
9407
+ /**
9408
+ * How many results the term found — `null` (the default) shows nothing.
9409
+ *
9410
+ * It belongs here rather than beside the box because it is the ANSWER to what
9411
+ * the box asked, and because every screen that wrote it by hand forgot the
9412
+ * same thing: a count that changes under a search has to be **announced**.
9413
+ * It carries `role="status"` and `aria-live="polite"`, so a user who cannot
9414
+ * see the grid still learns that four hundred rows became three.
9415
+ */
9416
+ resultCount = input(null, /* @ts-ignore */
9417
+ ...(ngDevMode ? [{ debugName: "resultCount" }] : /* istanbul ignore next */ []));
9418
+ /**
9419
+ * The word after the number — « pièces », "results", "matches".
9420
+ *
9421
+ * A plain string and not a template: the count reads `12 pièces`, and a
9422
+ * language that needs another order or a plural rule formats the whole thing
9423
+ * upstream and passes it as {@link resultLabel} with `resultCount` left null…
9424
+ * which it cannot. So: this covers `<number> <word>`, and anything else stays
9425
+ * the consumer's own markup beside the box.
9426
+ */
9427
+ resultLabel = input("results", /* @ts-ignore */
9428
+ ...(ngDevMode ? [{ debugName: "resultLabel" }] : /* istanbul ignore next */ []));
9429
+ /**
9430
+ * Where the count sits: above the box, after it on the same line, or below.
9431
+ *
9432
+ * `end` and not `right` — the whole library lays out in **logical**
9433
+ * properties, so the count follows the reading direction instead of pinning
9434
+ * itself to a side of the screen.
9435
+ */
9436
+ placement = input("end", /* @ts-ignore */
9437
+ ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
9321
9438
  /** Quiet period after the last keystroke before emitting, in ms. */
9322
9439
  delayMs = input(300, /* @ts-ignore */
9323
9440
  ...(ngDevMode ? [{ debugName: "delayMs" }] : /* istanbul ignore next */ []));
9324
9441
  /** Emits the trimmed term once typing pauses for `delayMs` (deduped). */
9325
9442
  searchChange = output();
9443
+ showCount = computed(() => this.resultCount() !== null, /* @ts-ignore */
9444
+ ...(ngDevMode ? [{ debugName: "showCount" }] : /* istanbul ignore next */ []));
9445
+ countText = computed(() => `${String(this.resultCount() ?? 0)} ${this.resultLabel()}`, /* @ts-ignore */
9446
+ ...(ngDevMode ? [{ debugName: "countText" }] : /* istanbul ignore next */ []));
9326
9447
  timer = null;
9327
9448
  lastEmitted = "";
9328
9449
  constructor() {
9329
9450
  // A pending timer that outlives the view would fire a stray emit.
9330
9451
  inject(DestroyRef).onDestroy(() => this.clear());
9331
9452
  }
9453
+ /**
9454
+ * The value moves **now**, the event waits.
9455
+ *
9456
+ * The box must show what was typed on the keystroke — deferring the text
9457
+ * itself would make the field feel broken — while the query it triggers is
9458
+ * what deserves the quiet period. Clearing settles like any other edit: the
9459
+ * empty term goes out after the same delay, so a consumer sees one contract
9460
+ * and not two.
9461
+ */
9332
9462
  onInput(value) {
9463
+ this.value.set(value);
9333
9464
  const term = value.trim();
9334
9465
  this.clear();
9335
9466
  this.timer = setTimeout(() => {
@@ -9346,28 +9477,14 @@ class FoldSearchComponent {
9346
9477
  }
9347
9478
  }
9348
9479
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9349
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.8", type: FoldSearchComponent, isStandalone: true, selector: "fold-search", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, delayMs: { classPropertyName: "delayMs", publicName: "delayMs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { searchChange: "searchChange" }, ngImport: i0, template: `
9350
- <fold-input
9351
- type="text"
9352
- [placeholder]="placeholder()"
9353
- [size]="size()"
9354
- [variant]="variant()"
9355
- (valueChange)="onInput($event)"
9356
- />
9357
- `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: FoldInputComponent, selector: "fold-input", inputs: ["value", "disabled", "touched", "errors", "type", "revealable", "revealLabel", "hideLabel", "size", "align", "variant", "label", "required", "optional", "optionalLabel", "info", "infoLabel", "ariaLabel", "hint", "placeholder", "readOnly", "autofocus", "autocomplete"], outputs: ["valueChange", "touchedChange"] }] });
9480
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldSearchComponent, isStandalone: true, selector: "fold-search", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, resultCount: { classPropertyName: "resultCount", publicName: "resultCount", isSignal: true, isRequired: false, transformFunction: null }, resultLabel: { classPropertyName: "resultLabel", publicName: "resultLabel", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, delayMs: { classPropertyName: "delayMs", publicName: "delayMs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", searchChange: "searchChange" }, host: { properties: { "class": "placement()" } }, ngImport: i0, template: "@if (showCount() && placement() === \"top\") {\n <p class=\"se-count\" role=\"status\" aria-live=\"polite\">{{ countText() }}</p>\n}\n\n<fold-input\n type=\"text\"\n leadingIcon=\"search\"\n [clearable]=\"clearable()\"\n [clearLabel]=\"clearLabel()\"\n [placeholder]=\"placeholder()\"\n [ariaLabel]=\"ariaLabel()\"\n [size]=\"size()\"\n [variant]=\"variant()\"\n [value]=\"value()\"\n (valueChange)=\"onInput($event)\"\n/>\n\n@if (showCount() && placement() !== \"top\") {\n <p class=\"se-count\" role=\"status\" aria-live=\"polite\">{{ countText() }}</p>\n}\n", styles: [":host{display:grid;gap:var(--fold-space-2xs)}:host(.end){grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--fold-space-sm)}.se-count{margin:0;font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);white-space:nowrap}:host(.top) .se-count,:host(.bottom) .se-count{justify-self:end}\n"], dependencies: [{ kind: "component", type: FoldInputComponent, selector: "fold-input", inputs: ["value", "disabled", "touched", "errors", "type", "revealable", "revealLabel", "hideLabel", "size", "align", "variant", "label", "required", "optional", "optionalLabel", "info", "infoLabel", "ariaLabel", "hint", "placeholder", "leadingIcon", "clearable", "clearLabel", "readOnly", "autofocus", "autocomplete"], outputs: ["valueChange", "touchedChange"] }] });
9358
9481
  }
9359
9482
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldSearchComponent, decorators: [{
9360
9483
  type: Component,
9361
- args: [{ selector: "fold-search", standalone: true, imports: [FoldInputComponent], template: `
9362
- <fold-input
9363
- type="text"
9364
- [placeholder]="placeholder()"
9365
- [size]="size()"
9366
- [variant]="variant()"
9367
- (valueChange)="onInput($event)"
9368
- />
9369
- `, styles: [":host{display:block}\n"] }]
9370
- }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], delayMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "delayMs", required: false }] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }] } });
9484
+ args: [{ selector: "fold-search", standalone: true, imports: [FoldInputComponent], host: {
9485
+ "[class]": "placement()",
9486
+ }, template: "@if (showCount() && placement() === \"top\") {\n <p class=\"se-count\" role=\"status\" aria-live=\"polite\">{{ countText() }}</p>\n}\n\n<fold-input\n type=\"text\"\n leadingIcon=\"search\"\n [clearable]=\"clearable()\"\n [clearLabel]=\"clearLabel()\"\n [placeholder]=\"placeholder()\"\n [ariaLabel]=\"ariaLabel()\"\n [size]=\"size()\"\n [variant]=\"variant()\"\n [value]=\"value()\"\n (valueChange)=\"onInput($event)\"\n/>\n\n@if (showCount() && placement() !== \"top\") {\n <p class=\"se-count\" role=\"status\" aria-live=\"polite\">{{ countText() }}</p>\n}\n", styles: [":host{display:grid;gap:var(--fold-space-2xs)}:host(.end){grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--fold-space-sm)}.se-count{margin:0;font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);white-space:nowrap}:host(.top) .se-count,:host(.bottom) .se-count{justify-self:end}\n"] }]
9487
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], resultCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultCount", required: false }] }], resultLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "resultLabel", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], delayMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "delayMs", required: false }] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }] } });
9371
9488
 
9372
9489
  /**
9373
9490
  * `<fold-select>` — the dropdown sibling of {@link FoldInputComponent} and
@@ -10503,7 +10620,7 @@ class FoldPasswordFieldComponent {
10503
10620
  effect(() => this.validChange.emit(this.allValid()));
10504
10621
  }
10505
10622
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldPasswordFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10506
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldPasswordFieldComponent, isStandalone: true, selector: "fold-password-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, revealable: { classPropertyName: "revealable", publicName: "revealable", isSignal: true, isRequired: false, transformFunction: null }, revealLabel: { classPropertyName: "revealLabel", publicName: "revealLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, rules: { classPropertyName: "rules", publicName: "rules", isSignal: true, isRequired: false, transformFunction: null }, marker: { classPropertyName: "marker", publicName: "marker", isSignal: true, isRequired: false, transformFunction: null }, rulesLabel: { classPropertyName: "rulesLabel", publicName: "rulesLabel", isSignal: true, isRequired: false, transformFunction: null }, metLabel: { classPropertyName: "metLabel", publicName: "metLabel", isSignal: true, isRequired: false, transformFunction: null }, unmetLabel: { classPropertyName: "unmetLabel", publicName: "unmetLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", validChange: "validChange" }, exportAs: ["foldPasswordField"], ngImport: i0, template: "<fold-input\n type=\"password\"\n [label]=\"label()\"\n [placeholder]=\"placeholder()\"\n [hint]=\"hint()\"\n [required]=\"required()\"\n [size]=\"size()\"\n [variant]=\"variant()\"\n [disabled]=\"disabled()\"\n [revealable]=\"revealable()\"\n [revealLabel]=\"revealLabel()\"\n [hideLabel]=\"hideLabel()\"\n [autocomplete]=\"autocomplete()\"\n [errors]=\"errors()\"\n [(value)]=\"value\"\n [(touched)]=\"touched\"\n/>\n\n<!-- Project into `[rules]` to redesign the checklist off the same state\n (`#pw=\"foldPasswordField\"` \u2192 `pw.checklist()`); otherwise the default list\n below is the fallback content. -->\n<ng-content select=\"[rules]\">\n @if (checklist().length) {\n <ul class=\"pw-rules\" [attr.aria-label]=\"rulesLabel()\" aria-live=\"polite\">\n @for (rule of checklist(); track rule.label) {\n <li class=\"pw-rule\" [class.is-met]=\"rule.met\">\n @if (marker() === \"check\") {\n <span class=\"pw-mark\" aria-hidden=\"true\">\n @if (rule.met) {\n <fold-icon name=\"check\" size=\"sm\" />\n }\n </span>\n } @else {\n <span class=\"pw-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"pw-rule-label\">{{ rule.label }}</span>\n <!-- The met/unmet word is real text (not just an attribute), so the\n aria-live region actually announces a rule flipping. -->\n <span class=\"pw-sr\"\n >\u2014 {{ rule.met ? metLabel() : unmetLabel() }}</span\n >\n </li>\n }\n </ul>\n }\n</ng-content>\n", styles: [":host{display:block}.pw-rules{list-style:none;margin:.5rem 0 0;padding:0;display:flex;flex-direction:column;gap:.25rem}.pw-rule{display:flex;align-items:center;gap:.45rem;font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);transition:color var(--fold-motion-fast)}.pw-dot{flex:none;width:.5rem;height:.5rem;border-radius:var(--fold-radius-round);border:1.5px solid var(--fold-color-text-faded);box-sizing:border-box;transition:background var(--fold-motion-fast),border-color var(--fold-motion-fast)}.pw-rule.is-met{color:var(--fold-color-text)}.pw-rule.is-met .pw-dot{border-color:var(--fold-color-primary);background:var(--fold-color-primary)}.pw-mark{flex:none;width:.85rem;height:.85rem;display:grid;place-items:center;color:var(--fold-color-primary)}.pw-rule:not(.is-met) .pw-mark{border:1.5px solid var(--fold-color-text-faded);border-radius:var(--fold-radius-round);box-sizing:border-box}@media(forced-colors:active){.pw-rule.is-met .pw-dot{background:Highlight;border-color:Highlight}.pw-mark{color:Highlight}}.pw-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"], dependencies: [{ kind: "component", type: FoldInputComponent, selector: "fold-input", inputs: ["value", "disabled", "touched", "errors", "type", "revealable", "revealLabel", "hideLabel", "size", "align", "variant", "label", "required", "optional", "optionalLabel", "info", "infoLabel", "ariaLabel", "hint", "placeholder", "readOnly", "autofocus", "autocomplete"], outputs: ["valueChange", "touchedChange"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
10623
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldPasswordFieldComponent, isStandalone: true, selector: "fold-password-field", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, autocomplete: { classPropertyName: "autocomplete", publicName: "autocomplete", isSignal: true, isRequired: false, transformFunction: null }, revealable: { classPropertyName: "revealable", publicName: "revealable", isSignal: true, isRequired: false, transformFunction: null }, revealLabel: { classPropertyName: "revealLabel", publicName: "revealLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null }, rules: { classPropertyName: "rules", publicName: "rules", isSignal: true, isRequired: false, transformFunction: null }, marker: { classPropertyName: "marker", publicName: "marker", isSignal: true, isRequired: false, transformFunction: null }, rulesLabel: { classPropertyName: "rulesLabel", publicName: "rulesLabel", isSignal: true, isRequired: false, transformFunction: null }, metLabel: { classPropertyName: "metLabel", publicName: "metLabel", isSignal: true, isRequired: false, transformFunction: null }, unmetLabel: { classPropertyName: "unmetLabel", publicName: "unmetLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", validChange: "validChange" }, exportAs: ["foldPasswordField"], ngImport: i0, template: "<fold-input\n type=\"password\"\n [label]=\"label()\"\n [placeholder]=\"placeholder()\"\n [hint]=\"hint()\"\n [required]=\"required()\"\n [size]=\"size()\"\n [variant]=\"variant()\"\n [disabled]=\"disabled()\"\n [revealable]=\"revealable()\"\n [revealLabel]=\"revealLabel()\"\n [hideLabel]=\"hideLabel()\"\n [autocomplete]=\"autocomplete()\"\n [errors]=\"errors()\"\n [(value)]=\"value\"\n [(touched)]=\"touched\"\n/>\n\n<!-- Project into `[rules]` to redesign the checklist off the same state\n (`#pw=\"foldPasswordField\"` \u2192 `pw.checklist()`); otherwise the default list\n below is the fallback content. -->\n<ng-content select=\"[rules]\">\n @if (checklist().length) {\n <ul class=\"pw-rules\" [attr.aria-label]=\"rulesLabel()\" aria-live=\"polite\">\n @for (rule of checklist(); track rule.label) {\n <li class=\"pw-rule\" [class.is-met]=\"rule.met\">\n @if (marker() === \"check\") {\n <span class=\"pw-mark\" aria-hidden=\"true\">\n @if (rule.met) {\n <fold-icon name=\"check\" size=\"sm\" />\n }\n </span>\n } @else {\n <span class=\"pw-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"pw-rule-label\">{{ rule.label }}</span>\n <!-- The met/unmet word is real text (not just an attribute), so the\n aria-live region actually announces a rule flipping. -->\n <span class=\"pw-sr\"\n >\u2014 {{ rule.met ? metLabel() : unmetLabel() }}</span\n >\n </li>\n }\n </ul>\n }\n</ng-content>\n", styles: [":host{display:block}.pw-rules{list-style:none;margin:.5rem 0 0;padding:0;display:flex;flex-direction:column;gap:.25rem}.pw-rule{display:flex;align-items:center;gap:.45rem;font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);transition:color var(--fold-motion-fast)}.pw-dot{flex:none;width:.5rem;height:.5rem;border-radius:var(--fold-radius-round);border:1.5px solid var(--fold-color-text-faded);box-sizing:border-box;transition:background var(--fold-motion-fast),border-color var(--fold-motion-fast)}.pw-rule.is-met{color:var(--fold-color-text)}.pw-rule.is-met .pw-dot{border-color:var(--fold-color-primary);background:var(--fold-color-primary)}.pw-mark{flex:none;width:.85rem;height:.85rem;display:grid;place-items:center;color:var(--fold-color-primary)}.pw-rule:not(.is-met) .pw-mark{border:1.5px solid var(--fold-color-text-faded);border-radius:var(--fold-radius-round);box-sizing:border-box}@media(forced-colors:active){.pw-rule.is-met .pw-dot{background:Highlight;border-color:Highlight}.pw-mark{color:Highlight}}.pw-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}\n"], dependencies: [{ kind: "component", type: FoldInputComponent, selector: "fold-input", inputs: ["value", "disabled", "touched", "errors", "type", "revealable", "revealLabel", "hideLabel", "size", "align", "variant", "label", "required", "optional", "optionalLabel", "info", "infoLabel", "ariaLabel", "hint", "placeholder", "leadingIcon", "clearable", "clearLabel", "readOnly", "autofocus", "autocomplete"], outputs: ["valueChange", "touchedChange"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
10507
10624
  }
10508
10625
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldPasswordFieldComponent, decorators: [{
10509
10626
  type: Component,