@atelier-ui/angular 0.2.26 → 0.2.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atelier-ui/angular",
3
- "version": "0.2.26",
3
+ "version": "0.2.35",
4
4
  "description": "Atelier component library for Angular — LLM-optimised, accessible, design-token-driven",
5
5
  "keywords": [
6
6
  "angular",
@@ -143,6 +143,23 @@
143
143
  --ui-type-action: var(--ui-font-weight-semibold) var(--ui-font-size-md) /
144
144
  var(--ui-line-height-tight) var(--ui-font-family);
145
145
 
146
+ /* The row roles (ADR-0085). Where `control` is the label ON a control and
147
+ * `action` is the text of a control that acts, these two are the text IN a
148
+ * row: a menu item, an option, a table cell, a checkbox or radio label. They
149
+ * are regular weight, not medium, and they sit at the two default sizes the
150
+ * row ladder uses — `row` at md for the standard rung, `row-sm` at sm for the
151
+ * compact one. Same tight leading as the rest of the ladder: a row's height
152
+ * comes from --ui-row-height-*, so its leading must not grow with the text.
153
+ *
154
+ * The ADR-0073 carve-out applies here exactly as it does above: a control's
155
+ * own VALUE text keeps its longhands. `row` describes what the row DISPLAYS,
156
+ * not what an input CONTAINS.
157
+ */
158
+ --ui-type-row: var(--ui-font-weight-normal) var(--ui-font-size-md) /
159
+ var(--ui-line-height-tight) var(--ui-font-family);
160
+ --ui-type-row-sm: var(--ui-font-weight-normal) var(--ui-font-size-sm) /
161
+ var(--ui-line-height-tight) var(--ui-font-family);
162
+
146
163
  /* ── Colours · light mode (default) ────────────────────────── */
147
164
 
148
165
  /* Primary — Conciso deep teal */
@@ -210,6 +210,7 @@ declare class AtlIcon {
210
210
  * ```html
211
211
  * <atl-input type="email" placeholder="you@example.com" [(value)]="email" />
212
212
  * <atl-input [formField]="loginForm.email" placeholder="Email" />
213
+ * <atl-input label="Email" type="email" [(value)]="email" />
213
214
  * ```
214
215
  */
215
216
  declare class AtlInput implements FormValueControl<string> {
@@ -217,8 +218,29 @@ declare class AtlInput implements FormValueControl<string> {
217
218
  readonly value: _angular_core.ModelSignal<string>;
218
219
  /** The type of input field. */
219
220
  readonly type: _angular_core.InputSignal<"number" | "text" | "email" | "password" | "tel" | "url">;
221
+ /**
222
+ * Visible caption rendered as a `<label>` associated with the input via
223
+ * `for`/`id`. Omit it when the field is captioned some other way (an
224
+ * external `<label>`, or `aria-label`) — without one of these the input
225
+ * has no accessible name.
226
+ */
227
+ readonly label: _angular_core.InputSignal<string>;
228
+ /**
229
+ * Accessible name for the native input, for when there is no visible
230
+ * `label`. An aliased input rather than a plain host attribute: an
231
+ * unrecognized `aria-label="…"` on `<atl-input>` would sit on the host
232
+ * element, which has no role, leaving the actual control unnamed.
233
+ */
234
+ readonly ariaLabel: _angular_core.InputSignal<string>;
220
235
  /** Placeholder text shown when the input is empty. */
221
236
  readonly placeholder: _angular_core.InputSignal<string>;
237
+ /**
238
+ * Explicit id for the native input. Wins over the auto-generated id — set
239
+ * this when something outside this component (an external `<label for>`,
240
+ * or `aria-describedby` from elsewhere on the page) needs a known, stable
241
+ * id to point at.
242
+ */
243
+ readonly id: _angular_core.InputSignal<string>;
222
244
  /** Whether the input is disabled. Bound by [formField] directive. */
223
245
  readonly disabled: _angular_core.InputSignal<boolean>;
224
246
  /** Whether the input is read-only. Bound by [formField] directive. */
@@ -235,6 +257,31 @@ declare class AtlInput implements FormValueControl<string> {
235
257
  readonly name: _angular_core.InputSignal<string>;
236
258
  /** @internal */
237
259
  protected readonly errorId: string;
260
+ /**
261
+ * @internal
262
+ * Fallback id, used only when the caller does not supply one. A
263
+ * module-scoped counter — the idiom every other Angular form control in
264
+ * this lib already uses for its own ids (checkbox, radio, toggle, select,
265
+ * textarea all do the same `` `atl-<name>-${nextId++}` `` thing for
266
+ * errorId) — rather than reaching for a `useId()`-equivalent. Collision-free
267
+ * across every instance rendered within one running copy of this module
268
+ * (one browser tab, or one server-render pass), which is the guarantee this
269
+ * lib actually needs: none of these adapters are server-rendered today.
270
+ *
271
+ * This is NOT the guarantee React's/Vue's `useId()` gives. `nextId` is a
272
+ * plain module-level variable, not reset per request: a persistent Node SSR
273
+ * process keeps incrementing it across requests while a fresh client always
274
+ * starts at 0, so server and client render would diverge the moment this
275
+ * component is server-rendered — the exact hydration mismatch this file
276
+ * used to (wrongly) claim the counter avoided. Two independently bundled
277
+ * copies of this module (e.g. two versions loaded by separate
278
+ * micro-frontends on one page) would likewise each start their own `nextId`
279
+ * at 0 and could collide. Neither risk is exercised today; revisit this if
280
+ * SSR or module-duplication ever applies here.
281
+ */
282
+ private readonly generatedId;
283
+ /** @internal */
284
+ protected readonly inputId: _angular_core.Signal<string>;
238
285
  /** @internal */
239
286
  /**
240
287
  * The message renders when there is a message. Gating it on `touched` as well was
@@ -249,7 +296,7 @@ declare class AtlInput implements FormValueControl<string> {
249
296
  /** @internal */
250
297
  protected onInput(event: Event): void;
251
298
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AtlInput, never>;
252
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AtlInput, "atl-input", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
299
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AtlInput, "atl-input", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
253
300
  }
254
301
 
255
302
  /**
@@ -259,6 +306,7 @@ declare class AtlInput implements FormValueControl<string> {
259
306
  * ```html
260
307
  * <atl-textarea placeholder="Enter a description" [(value)]="description" />
261
308
  * <atl-textarea [formField]="form.bio" [rows]="4" />
309
+ * <atl-textarea label="Bio" [(value)]="bio" />
262
310
  * ```
263
311
  */
264
312
  declare class AtlTextarea implements FormValueControl<string> {
@@ -266,8 +314,28 @@ declare class AtlTextarea implements FormValueControl<string> {
266
314
  readonly value: _angular_core.ModelSignal<string>;
267
315
  /** Number of visible text rows. */
268
316
  readonly rows: _angular_core.InputSignal<number>;
317
+ /**
318
+ * Visible caption rendered as a `<label>` associated with the textarea via
319
+ * `for`/`id`. Omit it when the field is captioned some other way (an
320
+ * external `<label>`, or `aria-label`) — without one of these the textarea
321
+ * has no accessible name.
322
+ */
323
+ readonly label: _angular_core.InputSignal<string>;
324
+ /**
325
+ * Accessible name for the native textarea, for when there is no visible
326
+ * `label`. An aliased input rather than a plain host attribute — see
327
+ * `atl-input.ts`'s identical `ariaLabel` for why.
328
+ */
329
+ readonly ariaLabel: _angular_core.InputSignal<string>;
269
330
  /** Placeholder text shown when the textarea is empty. */
270
331
  readonly placeholder: _angular_core.InputSignal<string>;
332
+ /**
333
+ * Explicit id for the native textarea. Wins over the auto-generated id —
334
+ * set this when something outside this component (an external
335
+ * `<label for>`, or `aria-describedby` from elsewhere on the page) needs a
336
+ * known, stable id to point at.
337
+ */
338
+ readonly id: _angular_core.InputSignal<string>;
271
339
  /** Whether the textarea is disabled. Bound by [formField] directive. */
272
340
  readonly disabled: _angular_core.InputSignal<boolean>;
273
341
  /** Whether the textarea is read-only. Bound by [formField] directive. */
@@ -286,6 +354,17 @@ declare class AtlTextarea implements FormValueControl<string> {
286
354
  readonly autoResize: _angular_core.InputSignal<boolean>;
287
355
  /** @internal */
288
356
  protected readonly errorId: string;
357
+ /**
358
+ * @internal
359
+ * Fallback id, used only when the caller does not supply one. Same
360
+ * module-scoped counter idiom as `errorId` above and as every other
361
+ * Angular form control in this lib — see `atl-input.ts`'s `generatedId`
362
+ * for the honest account of what guarantee this idiom actually gives
363
+ * (same-module-instance uniqueness, not `useId()`-equivalent SSR safety).
364
+ */
365
+ private readonly generatedId;
366
+ /** @internal */
367
+ protected readonly inputId: _angular_core.Signal<string>;
289
368
  /** @internal */
290
369
  /**
291
370
  * The message renders when there is a message. Gating it on `touched` as well was
@@ -300,7 +379,7 @@ declare class AtlTextarea implements FormValueControl<string> {
300
379
  /** @internal */
301
380
  protected onInput(event: Event): void;
302
381
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AtlTextarea, never>;
303
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AtlTextarea, "atl-textarea", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "autoResize": { "alias": "autoResize"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
382
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AtlTextarea, "atl-textarea", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "id": { "alias": "id"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "autoResize": { "alias": "autoResize"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, never, true, never>;
304
383
  }
305
384
 
306
385
  /**
@@ -586,6 +665,10 @@ declare const ATL_SELECT: InjectionToken<AtlSelectContext>;
586
665
  * <atl-select [formField]="form.country" placeholder="Select a country">
587
666
  * <atl-option optionValue="us">United States</atl-option>
588
667
  * </atl-select>
668
+ *
669
+ * <atl-select label="Country" [(value)]="country" placeholder="Select a country">
670
+ * <atl-option optionValue="us">United States</atl-option>
671
+ * </atl-select>
589
672
  * ```
590
673
  */
591
674
  declare class AtlSelect implements FormValueControl<string>, AtlSelectContext, OnDestroy {
@@ -595,6 +678,20 @@ declare class AtlSelect implements FormValueControl<string>, AtlSelectContext, O
595
678
  readonly touched: _angular_core.ModelSignal<boolean>;
596
679
  /** Placeholder text shown when no option is selected. */
597
680
  readonly placeholder: _angular_core.InputSignal<string>;
681
+ /**
682
+ * Visible caption rendered as a `<label>` associated with the trigger
683
+ * button via `for`/`id`. Omit it when the field is captioned some other
684
+ * way (an external `<label>`, or `aria-label`) — without one of these the
685
+ * select has no accessible name (this is the L1 backlog item: a select
686
+ * with neither produces exactly that).
687
+ */
688
+ readonly label: _angular_core.InputSignal<string>;
689
+ /**
690
+ * Accessible name for the trigger button, for when there is no visible
691
+ * `label`. An aliased input rather than a plain host attribute — see
692
+ * `atl-input.ts`'s identical `ariaLabel` for why.
693
+ */
694
+ readonly ariaLabel: _angular_core.InputSignal<string>;
598
695
  /** Whether the select is disabled. Bound by [formField] directive. */
599
696
  readonly disabled: _angular_core.InputSignal<boolean>;
600
697
  /** Whether the select has validation errors. Bound by [formField] directive. */
@@ -662,7 +759,7 @@ declare class AtlSelect implements FormValueControl<string>, AtlSelectContext, O
662
759
  private close;
663
760
  private createOverlay;
664
761
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AtlSelect, never>;
665
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AtlSelect, "atl-select", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, ["*"], true, never>;
762
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AtlSelect, "atl-select", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "errors": { "alias": "errors"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touched": "touchedChange"; }, never, ["*"], true, never>;
666
763
  }
667
764
 
668
765
  /**