{"version":3,"file":"forty-cdk-fieldset.mjs","sources":["../../../projects/forty-cdk/fieldset/src/fieldset.ts","../../../projects/forty-cdk/fieldset/src/fieldset-legend.ts","../../../projects/forty-cdk/fieldset/src/forty-cdk-fieldset.ts"],"sourcesContent":["import {\n  booleanAttribute,\n  computed,\n  Directive,\n  effect,\n  ElementRef,\n  inject,\n  input,\n  isDevMode,\n  signal,\n} from '@angular/core';\n\nimport {\n  adoptHostId,\n  FOR_FIELDSET_CONTEXT,\n  type ForFieldsetContext,\n  fortyWarn,\n  hostLabelledBy,\n  IdGenerator,\n  reflectDisabled,\n} from 'forty-cdk/core';\n\n/**\n * Headless grouping container that gives a set of related fields a shared\n * accessible name — the styleless counterpart to a native `<fieldset>` +\n * `<legend>`, and the grouping companion to `ForField`.\n *\n * On a native `<fieldset>` it relies on the implicit grouping and emits no\n * role; on any other element it emits `role=\"group\"` + `aria-labelledby`\n * pointing at the `[forFieldsetLegend]` (same host-tag detection idiom as\n * `ForLabel`'s `<label>` check).\n *\n * The `disabled` input reflects `data-disabled` and is provided via context so\n * descendant `ForField` controls OR it into their own disabled state — native\n * `<fieldset disabled>` does not reach custom-role controls like `forSwitch`.\n *\n * @example\n * ```html\n * <fieldset forFieldset [disabled]=\"locked()\">\n *   <legend forFieldsetLegend>Shipping address</legend>\n *   <div forField>\n *     <label forLabel>Street</label>\n *     <input forFieldControl />\n *   </div>\n * </fieldset>\n * ```\n */\n@Directive({\n  selector: '[forFieldset]',\n  exportAs: 'forFieldset',\n  host: {\n    '[attr.role]': 'roleAttr()',\n    '[attr.aria-labelledby]': 'labelledBy()',\n    '[attr.aria-disabled]': '!isNativeFieldset() && disabled() ? \"true\" : null',\n    '[attr.data-disabled]': 'disabled() ? \"\" : null',\n  },\n  providers: [{ provide: FOR_FIELDSET_CONTEXT, useExisting: ForFieldset }],\n})\nexport class ForFieldset implements ForFieldsetContext {\n  readonly #idGen = inject(IdGenerator);\n  readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n  readonly #parent = inject(FOR_FIELDSET_CONTEXT, { optional: true, skipSelf: true });\n  readonly #legends = signal(0);\n  readonly #legendId = signal(this.#idGen.next('for-fieldset-legend'));\n\n  /**\n   * Whether the group is disabled, as bound by the consumer via `[disabled]`.\n   * The host reflection and descendant controls read the composed\n   * {@link disabled} signal below, which also folds in an enclosing disabled\n   * `[forFieldset]`.\n   */\n  readonly disabledInput = input(false, { transform: booleanAttribute, alias: 'disabled' });\n\n  /**\n   * Effective disabled: the group's own `[disabled]` OR'd with an enclosing\n   * disabled `[forFieldset]`. Reflects `data-disabled`, emits the native\n   * `disabled` attribute on a `<fieldset>` (or `aria-disabled` elsewhere), and\n   * propagates to descendant controls via context — so a disabled fieldset\n   * reaches custom-role controls (`forSwitch`, `forCheckbox`, …) a native\n   * `<fieldset disabled>` can't, and nesting composes like native fieldsets\n   * (a disabled outer group cannot be re-enabled by an inner one).\n   */\n  readonly disabled = computed(() => this.disabledInput() || (this.#parent?.disabled() ?? false));\n\n  /**\n   * Id of the legend element; the group's `aria-labelledby` resolves here. A\n   * generated `for-fieldset-legend-*` id, or the static `id` a consumer wrote on\n   * the `[forFieldsetLegend]` host once {@link adoptLegendId} has adopted it.\n   */\n  readonly legendId = this.#legendId.asReadonly();\n\n  /** Whether the host element is a native `<fieldset>` (no role/labelledby needed). */\n  protected readonly isNativeFieldset = computed(\n    () => this.#host.nativeElement.tagName === 'FIELDSET',\n  );\n\n  /**\n   * Native `disabled` is reflected only on a real `<fieldset>` (where it\n   * natively disables descendant controls); a non-`<fieldset>` host advertises\n   * its disabled state via `aria-disabled` instead.\n   */\n  protected readonly nativeDisabled = computed(() => this.isNativeFieldset() && this.disabled());\n\n  constructor() {\n    reflectDisabled(this.nativeDisabled);\n    if (isDevMode()) {\n      this.#warnOnDuplicateLegend();\n    }\n  }\n\n  /** `role=\"group\"` on a non-`<fieldset>` element, else null. */\n  protected readonly roleAttr = computed(() => (this.isNativeFieldset() ? null : 'group'));\n\n  /**\n   * Resolved `aria-labelledby`: a consumer-set static value when present, else\n   * the legend id on a non-`<fieldset>` element when a legend is registered,\n   * else null (a native `<fieldset>`/`<legend>` groups implicitly and needs\n   * none).\n   */\n  protected readonly labelledBy = hostLabelledBy(() =>\n    !this.isNativeFieldset() && this.#legends() > 0 ? this.legendId() : null,\n  );\n\n  /**\n   * Adopts a consumer-set static `id` on the `[forFieldsetLegend]` host into\n   * {@link legendId} — preserving external `aria-labelledby` /\n   * `aria-describedby` references, `<label for>` targets and test hooks —\n   * instead of letting the legend's `[id]` host binding clobber it with the\n   * generated fallback. {@link labelledBy} reads the same signal, so the group's\n   * `aria-labelledby` follows the adopted value with no second step.\n   *\n   * Only a **static** `id` is adopted: a consumer `[id]=\"expr\"` property binding\n   * evaluates after the legend's construction, so it is invisible here and still\n   * fights the host binding.\n   */\n  adoptLegendId(el: HTMLElement): void {\n    adoptHostId(el, this.#legendId);\n  }\n\n  /**\n   * Mark a legend present; returns an unregister callback. A fieldset is labelled\n   * by a single legend — `legendId` is one id, not an id list — so one\n   * `[forFieldsetLegend]` per group is the supported shape, matching a native\n   * `<fieldset>`'s single `<legend>`. Registrations are counted (mirroring\n   * `ForField`'s label / description / error slots), so unmounting one of several\n   * accidental duplicates never drops the association while another is still\n   * mounted; the last one to register owns {@link legendId}, and a duplicate\n   * emits a dev-mode warning.\n   */\n  registerLegend(): () => void {\n    this.#legends.update((n) => n + 1);\n    return () => this.#legends.update((n) => n - 1);\n  }\n\n  #warnOnDuplicateLegend(): void {\n    effect(() => {\n      const registered = this.#legends();\n      if (registered > 1) {\n        fortyWarn({\n          code: 'FORCDK-FIELDSET-001',\n          message: `A [forFieldset] is labelled by a single [forFieldsetLegend], but ${registered} are registered.`,\n          cause: 'They share one legendId, producing duplicate DOM ids and unstable aria wiring.',\n          fix: 'Keep one [forFieldsetLegend] per [forFieldset].',\n        });\n      }\n    });\n  }\n}\n","import { computed, DestroyRef, Directive, ElementRef, inject } from '@angular/core';\n\nimport { FOR_FIELDSET_CONTEXT } from 'forty-cdk/core';\n\n/**\n * Accessible group label for a `[forFieldset]`. Inside a fieldset it emits the\n * fieldset's `legendId` and registers itself so the group's `aria-labelledby`\n * resolves; on a native `<fieldset>`/`<legend>` the id is harmless extra wiring\n * (the browser groups implicitly).\n *\n * A consumer-set **static** `id` on the host wins: it is adopted into the\n * fieldset's `legendId` at construction, so external references to it keep\n * resolving and the group's `aria-labelledby` follows it. A `[id]=\"expr\"`\n * property binding is not adopted.\n *\n * Usable standalone outside a fieldset — there it is an inert marker.\n *\n * @example\n * ```html\n * <div forFieldset>\n *   <span forFieldsetLegend>Notification preferences</span>\n *   <!-- … fields … -->\n * </div>\n * ```\n */\n@Directive({\n  selector: '[forFieldsetLegend]',\n  exportAs: 'forFieldsetLegend',\n  host: {\n    '[attr.id]': 'legendId()',\n  },\n})\nexport class ForFieldsetLegend {\n  protected readonly ctx = inject(FOR_FIELDSET_CONTEXT, { optional: true });\n\n  /** The legend's id when inside a fieldset, else null. */\n  protected readonly legendId = computed(() => this.ctx?.legendId() ?? null);\n\n  constructor() {\n    const ctx = this.ctx;\n    if (ctx) {\n      ctx.adoptLegendId(inject<ElementRef<HTMLElement>>(ElementRef).nativeElement);\n      const unregister = ctx.registerLegend();\n      inject(DestroyRef).onDestroy(unregister);\n    }\n  }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;AAsBA;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MAYU,WAAW,CAAA;AACb,IAAA,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;AAC5B,IAAA,KAAK,GAAG,MAAM,CAA0B,UAAU,CAAC;AACnD,IAAA,OAAO,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1E,QAAQ,GAAG,MAAM,CAAC,CAAC;iFAAC;IACpB,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC;kFAAC;AAEpE;;;;;AAKG;AACM,IAAA,aAAa,GAAG,KAAK,CAAC,KAAK,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,eAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,GAAG;AAEzF;;;;;;;;AAQG;IACM,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,KAAK,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,KAAK,CAAC;iFAAC;AAE/F;;;;AAIG;AACM,IAAA,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE;;AAG5B,IAAA,gBAAgB,GAAG,QAAQ,CAC5C,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,KAAK,UAAU;yFACtD;AAED;;;;AAIG;AACgB,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE;uFAAC;AAE9F,IAAA,WAAA,GAAA;AACE,QAAA,eAAe,CAAC,IAAI,CAAC,cAAc,CAAC;QACpC,IAAI,SAAS,EAAE,EAAE;YACf,IAAI,CAAC,sBAAsB,EAAE;QAC/B;IACF;;AAGmB,IAAA,QAAQ,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,gBAAgB,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC;iFAAC;AAExF;;;;;AAKG;AACgB,IAAA,UAAU,GAAG,cAAc,CAAC,MAC7C,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CACzE;AAED;;;;;;;;;;;AAWG;AACH,IAAA,aAAa,CAAC,EAAe,EAAA;AAC3B,QAAA,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC;IACjC;AAEA;;;;;;;;;AASG;IACH,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAClC,QAAA,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjD;IAEA,sBAAsB,GAAA;QACpB,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE;AAClC,YAAA,IAAI,UAAU,GAAG,CAAC,EAAE;AAClB,gBAAA,SAAS,CAAC;AACR,oBAAA,IAAI,EAAE,qBAAqB;oBAC3B,OAAO,EAAE,CAAA,iEAAA,EAAoE,UAAU,CAAA,gBAAA,CAAkB;AACzG,oBAAA,KAAK,EAAE,gFAAgF;AACvF,oBAAA,GAAG,EAAE,iDAAiD;AACvD,iBAAA,CAAC;YACJ;AACF,QAAA,CAAC,CAAC;IACJ;uGA5GW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAX,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,WAAA,EAAA,YAAA,EAAA,sBAAA,EAAA,cAAA,EAAA,oBAAA,EAAA,qDAAA,EAAA,oBAAA,EAAA,0BAAA,EAAA,EAAA,EAAA,SAAA,EAFX,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAE7D,WAAW,EAAA,UAAA,EAAA,CAAA;kBAXvB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,eAAe;AACzB,oBAAA,QAAQ,EAAE,aAAa;AACvB,oBAAA,IAAI,EAAE;AACJ,wBAAA,aAAa,EAAE,YAAY;AAC3B,wBAAA,wBAAwB,EAAE,cAAc;AACxC,wBAAA,sBAAsB,EAAE,mDAAmD;AAC3E,wBAAA,sBAAsB,EAAE,wBAAwB;AACjD,qBAAA;oBACD,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAA,WAAa,EAAE,CAAC;AACzE,iBAAA;;;ACrDD;;;;;;;;;;;;;;;;;;;;AAoBG;MAQU,iBAAiB,CAAA;IACT,GAAG,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;AAGtD,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,IAAI;iFAAC;AAE1E,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG;QACpB,IAAI,GAAG,EAAE;YACP,GAAG,CAAC,aAAa,CAAC,MAAM,CAA0B,UAAU,CAAC,CAAC,aAAa,CAAC;AAC5E,YAAA,MAAM,UAAU,GAAG,GAAG,CAAC,cAAc,EAAE;YACvC,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC;QAC1C;IACF;uGAbW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAjB,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,SAAA,EAAA,YAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAjB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAP7B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,qBAAqB;AAC/B,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,IAAI,EAAE;AACJ,wBAAA,WAAW,EAAE,YAAY;AAC1B,qBAAA;AACF,iBAAA;;;AC/BD;;AAEG;;;;"}