@forgeroute/ui 0.4.39 → 0.4.40

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": "@forgeroute/ui",
3
- "version": "0.4.39",
3
+ "version": "0.4.40",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=22.0.0",
6
6
  "@angular/core": ">=22.0.0",
@@ -1141,4 +1141,114 @@ export declare class MicrodepositVerifyComponent {
1141
1141
  "verifyFailed": "verifyFailed";
1142
1142
  }, never, never, true, never>;
1143
1143
  }
1144
+ /**
1145
+ * "Connect your Stripe account": the one card every app shows where a business connects the Stripe account it collects payments into (Stripe Connect). It reads
1146
+ * the account's state from the app's backend, and Connect asks the backend for the address of Stripe's onboarding page and sends the browser there: the user
1147
+ * finishes setting up the account on Stripe and Stripe sends them back to the address the backend chose. An unfinished onboarding simply shows Connect again
1148
+ * (the backend resumes the same account); a finished one shows Connected with Reconnect.
1149
+ *
1150
+ * <ui-stripe-connect [connectParams]="{ returnTo: 'setup' }" (statusChange)="onConnected($event)" />
1151
+ *
1152
+ * The backend follows the convention of the setup wizard's `stripe` preset: `GET /integrations/stripe/status` answers `{ connected }` and
1153
+ * `GET /integrations/stripe/connect` answers `{ url }` (`authUrl` / `onboardingUrl` are read too). Both addresses and the texts can be replaced. The calls go
1154
+ * through `FORGEROUTE_CONFIG.baseUrl` and the app's HTTP interceptors (its sign-in token).
1155
+ */
1156
+ export declare class StripeConnectComponent {
1157
+ private readonly http;
1158
+ private readonly destroyRef;
1159
+ private readonly apiBase;
1160
+ /** GET: answers `{ connected }`. Relative to `FORGEROUTE_CONFIG.baseUrl`. */
1161
+ readonly statusEndpoint: import("@angular/core").InputSignal<string>;
1162
+ /** GET: answers the address of Stripe's onboarding page (`{ url }`). Relative to `FORGEROUTE_CONFIG.baseUrl`. */
1163
+ readonly connectEndpoint: import("@angular/core").InputSignal<string>;
1164
+ /** Query parameters sent with the connect request (for example `{ returnTo: 'setup' }`: where Stripe sends the user back to). */
1165
+ readonly connectParams: import("@angular/core").InputSignal<Record<string, string> | null>;
1166
+ readonly title: import("@angular/core").InputSignal<string>;
1167
+ readonly description: import("@angular/core").InputSignal<string>;
1168
+ readonly connectedText: import("@angular/core").InputSignal<string>;
1169
+ readonly connectLabel: import("@angular/core").InputSignal<string>;
1170
+ readonly reconnectLabel: import("@angular/core").InputSignal<string>;
1171
+ /** What the user sees when the status or the address could not be loaded and the server gave no message. */
1172
+ readonly loadFailedText: import("@angular/core").InputSignal<string>;
1173
+ readonly connectFailedText: import("@angular/core").InputSignal<string>;
1174
+ readonly disabled: import("@angular/core").InputSignal<boolean>;
1175
+ /** The account's state changed (it was read, or read again): true = connected. */
1176
+ readonly statusChange: import("@angular/core").OutputEmitterRef<boolean>;
1177
+ protected readonly connected: import("@angular/core").WritableSignal<boolean>;
1178
+ protected readonly statusKnown: import("@angular/core").WritableSignal<boolean>;
1179
+ protected readonly connecting: import("@angular/core").WritableSignal<boolean>;
1180
+ protected readonly error: import("@angular/core").WritableSignal<string>;
1181
+ protected readonly busy: import("@angular/core").Signal<boolean>;
1182
+ private started;
1183
+ constructor();
1184
+ /** Reads the account's state again (after the user came back from Stripe, for example). */
1185
+ refresh(): void;
1186
+ /** Asks the backend for Stripe's onboarding address and sends the browser there. */
1187
+ protected connect(): void;
1188
+ /** Sends the browser to Stripe. */
1189
+ protected redirect(url: string): void;
1190
+ /** Only an http(s) address is ever opened (never `javascript:` or `data:` from a response). */
1191
+ private isWebAddress;
1192
+ private messageOf;
1193
+ static ɵfac: i0.ɵɵFactoryDeclaration<StripeConnectComponent, never>;
1194
+ static ɵcmp: i0.ɵɵComponentDeclaration<StripeConnectComponent, "ui-stripe-connect", never, {
1195
+ "statusEndpoint": {
1196
+ "alias": "statusEndpoint";
1197
+ "required": false;
1198
+ "isSignal": true;
1199
+ };
1200
+ "connectEndpoint": {
1201
+ "alias": "connectEndpoint";
1202
+ "required": false;
1203
+ "isSignal": true;
1204
+ };
1205
+ "connectParams": {
1206
+ "alias": "connectParams";
1207
+ "required": false;
1208
+ "isSignal": true;
1209
+ };
1210
+ "title": {
1211
+ "alias": "title";
1212
+ "required": false;
1213
+ "isSignal": true;
1214
+ };
1215
+ "description": {
1216
+ "alias": "description";
1217
+ "required": false;
1218
+ "isSignal": true;
1219
+ };
1220
+ "connectedText": {
1221
+ "alias": "connectedText";
1222
+ "required": false;
1223
+ "isSignal": true;
1224
+ };
1225
+ "connectLabel": {
1226
+ "alias": "connectLabel";
1227
+ "required": false;
1228
+ "isSignal": true;
1229
+ };
1230
+ "reconnectLabel": {
1231
+ "alias": "reconnectLabel";
1232
+ "required": false;
1233
+ "isSignal": true;
1234
+ };
1235
+ "loadFailedText": {
1236
+ "alias": "loadFailedText";
1237
+ "required": false;
1238
+ "isSignal": true;
1239
+ };
1240
+ "connectFailedText": {
1241
+ "alias": "connectFailedText";
1242
+ "required": false;
1243
+ "isSignal": true;
1244
+ };
1245
+ "disabled": {
1246
+ "alias": "disabled";
1247
+ "required": false;
1248
+ "isSignal": true;
1249
+ };
1250
+ }, {
1251
+ "statusChange": "statusChange";
1252
+ }, never, never, true, never>;
1253
+ }
1144
1254
  export type { HandleReturnOptions, MicrodepositStartedBy, MicrodepositStepsContext, MicrodepositType, MicrodepositVerifyData, MicrodepositVerifyEvent, ProvideStripePaymentOptions, StripeA11yMessages, StripeAppearance, StripeBillingDetails, StripeConfirmResult, StripeConfirmedEvent, StripeConnection, StripeCreateIntentFn, StripeDeferredIntent, StripeElementChange, StripeElementsLike, StripeErrorDisplay, StripeErrorLike, StripeErrorMessageOptions, StripeFailure, StripeFailureStage, StripeIntentKind, StripeIntentLike, StripeLike, StripeLikeWithBankSetup, StripeLoadOptions, StripeLoaderFn, StripeMicrodepositNextAction, StripeMicrodepositResult, StripeOutcome, StripePaymentDefaults, StripePaymentElementLike, StripeReadyEvent, StripeReturnParams, StripeReturnResult, StripeVerification };
@@ -298,6 +298,8 @@ export type BulkUpdateOption<T = any> = string | {
298
298
  * It is also the inline select's accessible name, the default confirm's title and confirm button, and the default confirm message reads
299
299
  * "<label>: <option> for N items?" (instead of "Change <column> to <option> for N items?"). Host `confirm` copy still wins; its
300
300
  * `ctx.columnLabel` stays the column's label. Trimmed; blank = ignored. Ignored for the reserved `delete` key. Omit it and nothing changes.
301
+ * Direct actions (`action: true`): the bar button text, default confirm title and confirm button (required in practice; trimmed,
302
+ * blank = the key split on `_`, `-` and camelCase with only the first word capitalised: 'resend' -> 'Resend', 'send_reminder' / 'sendReminder' -> 'Send reminder'); `ctx.columnLabel` is this label.
301
303
  *
302
304
  * { field: 'state', label: 'Archive / Restore' }
303
305
  */
@@ -330,8 +332,32 @@ export type BulkUpdateOption<T = any> = string | {
330
332
  * { field: 'status', allowedFrom: { SENT: ['DRAFT'] }, canChange: (row, target) => target !== 'SENT' || canSend(row) }
331
333
  */
332
334
  canChange?: (row: T, target: string) => boolean;
335
+ /**
336
+ * Direct bulk action (`{ field: 'resend', action: true, label: 'Resend' }`): a bulk-bar button that is neither a field change nor
337
+ * Delete. `field` is the action key (no column needed), the button type is `action-<field>` and there is no inline select.
338
+ * Clicking it opens the library confirm, then POSTs `<endpoint>/bulk/<field>` with exactly `{ ids }` (the eligible rows). The response is
339
+ * handled like a field change (`updated`, `skipped`, `notAllowed`, readable `message`). Ignored for the reserved `delete` key.
340
+ * Read-only users get no bulk bar, so nothing changes for them. Omit it and nothing changes.
341
+ * `confirm` on an action takes only the function form; a map (target value -> function) is ignored and the default copy is used.
342
+ *
343
+ * { field: 'resend', action: true, label: 'Resend', eligible: (row: Request) => row.status === 'PENDING' }
344
+ */
345
+ action?: boolean;
346
+ /** Direct action only: button style, default 'secondary'. 'danger' also makes the default confirm button red. */
347
+ variant?: 'secondary' | 'danger';
348
+ /**
349
+ * Direct action only: true when the server will accept the action for this row (keep it identical to the backend rule). Rows it
350
+ * refuses are skipped (counted, NEVER sent; "N selected rows don't qualify for <label lower-cased> and will be skipped."). When no selected loaded row passes,
351
+ * the button is disabled with a visible reason ("None of the selected rows qualify for <label lower-cased>."). Omit it and every selected row is sent. A predicate that throws counts as "row not eligible" (never breaks rendering).
352
+ */
353
+ eligible?: (row: T) => boolean;
354
+ /**
355
+ * Direct action only: the past-tense word in the result toast. "N <doneLabel>, M skipped." when anything was skipped / not allowed,
356
+ * else "N <itemLabel>(s) <doneLabel>.". Default 'updated'.
357
+ */
358
+ doneLabel?: string;
333
359
  };
334
- /** What a bulk confirm function receives. For bulk Delete: `targetValue`/`targetLabel` are '', `columnLabel` is 'Delete', skipped counts are 0. */
360
+ /** What a bulk confirm function receives. For a direct bulk action: `columnLabel` is the action label, `targetValue`/`targetLabel` are '', `rows`/`skippedRows` the eligible / refused selected rows. For bulk Delete: `targetValue`/`targetLabel` are '', `columnLabel` is 'Delete', skipped counts are 0. */
335
361
  export interface BulkConfirmContext<T = any> {
336
362
  /** Rows that WILL be sent (eligible). For Delete: the selected count. */
337
363
  count: number;
@@ -391,6 +417,12 @@ export interface BulkActionDef {
391
417
  deletable?: (row: any) => boolean;
392
418
  /** Field changes: per-row check that the server will accept the move to a target (from `{ field, canChange }`). */
393
419
  canChange?: (row: any, target: string) => boolean;
420
+ /** True for a direct bulk action (from `{ field, action: true, label }`); `type` is `action-<key>` and `field` is not set (no inline select). */
421
+ action?: boolean;
422
+ /** Direct action: which rows the server will accept (from `{ field, action: true, eligible }`). */
423
+ eligible?: (row: any) => boolean;
424
+ /** Direct action: past-tense word in the result toast (from `{ doneLabel }`), default 'updated'. */
425
+ doneLabel?: string;
394
426
  /**
395
427
  * The item field this action targets (e.g. 'status', 'type').
396
428
  * When set the table shows an inline select populated from the column's option sources.
@@ -1056,7 +1088,7 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1056
1088
  readonly error: import("@angular/core").InputSignal<string>;
1057
1089
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
1058
1090
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
1059
- readonly size: import("@angular/core").InputSignal<"sm" | "default">;
1091
+ readonly size: import("@angular/core").InputSignal<"default" | "sm">;
1060
1092
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
1061
1093
  private readonly _cvaDisabled;
1062
1094
  protected readonly disabled: import("@angular/core").Signal<boolean>;
@@ -1392,6 +1424,10 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1392
1424
  * `[{ field: 'status', exclude: ['EXPIRED'] }, 'delete']` (see `BulkUpdateOption`).
1393
1425
  * Use `{ field, allowedFrom: { TARGET: [sourceValues] } }` for a status workflow: only targets some selected row can
1394
1426
  * legally move to are offered, and rows that can't move are skipped (never sent).
1427
+ * Use `{ field: 'resend', action: true, label: 'Resend', eligible?, confirm?, variant?, doneLabel? }` for a direct bulk action: a bar button
1428
+ * that confirms and POSTs `<endpoint>/bulk/<field>` with `{ ids }` of the eligible rows (no select, no column needed).
1429
+ * A blank `label` falls back to the key split on `_`, `-` and camelCase with only the first word capitalised ('send_reminder' -> 'Send reminder');
1430
+ * two actions with the same key collapse to the first; an `eligible` that throws counts as "row not eligible".
1395
1431
  */
1396
1432
  readonly bulkUpdateOptions: import("@angular/core").InputSignal<BulkUpdateOption<T>[]>;
1397
1433
  readonly rowClick: import("@angular/core").OutputEmitterRef<T>;
@@ -1582,9 +1618,14 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1582
1618
  /**
1583
1619
  * Derives internal action definitions from the `bulkUpdateOptions` string array.
1584
1620
  * 'delete' → built-in danger action with table-managed confirm dialog.
1621
+ * `{ field, action: true, label }` → direct action (type `action-<key>`, no column needed, no select).
1585
1622
  * Everything else → matched to a column: label = the entry's `label` when given, else "Change {col.label}"; options from column config.
1586
1623
  */
1587
1624
  protected readonly _bulkDefs: Signal<BulkActionDef[]>;
1625
+ /** Fallback label of a direct action without one: splits the key on `_`, `-` and camelCase, capitalises the first word only ('send_reminder' / 'sendReminder' -> 'Send reminder'). */
1626
+ private _actionKeyLabel;
1627
+ /** Runs a direct action's `eligible` predicate; a predicate that throws counts as "row not eligible". */
1628
+ private _isActionEligible;
1588
1629
  /** Options for a field-based bulk action: the field's options minus the entry's `exclude` values. */
1589
1630
  private _bulkOptionsFor;
1590
1631
  /** True when a row whose field currently holds `current` may be moved to `target` by this action. */
@@ -1638,12 +1679,20 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1638
1679
  * skipped-rows sentence, appended on a new paragraph unless the copy sets `omitSkippedNote`.
1639
1680
  */
1640
1681
  private _hostConfirm;
1641
- /** Why a bulk action can't be used right now ('' = it can). Only Delete with `deletable` can be blocked. */
1682
+ /** Why a bulk action can't be used right now ('' = it can). Only Delete with `deletable` and a direct action with `eligible` can be blocked. */
1642
1683
  protected _bulkBlockedReason(def: BulkActionDef): string;
1643
1684
  /** The distinct reasons of the currently blocked bulk actions, shown as visible text next to the disabled buttons. */
1644
1685
  protected _bulkBlockedHints(): string[];
1645
1686
  /** Selected rows (loaded page) split by the delete option's `deletable` predicate; without it every selected row is deletable. */
1646
1687
  private _deleteSplit;
1688
+ /** Selected rows (loaded page) split by a direct action's `eligible` predicate; without it every selected row is eligible. */
1689
+ private _actionSplit;
1690
+ /** Type of the direct bulk action whose request is in flight (null = none). */
1691
+ protected readonly _runningAction: import("@angular/core").WritableSignal<string | null>;
1692
+ /** True while a direct action's confirm dialog is open (guards against a second click). */
1693
+ private _confirmingAction;
1694
+ /** Direct bulk action: confirm, then POST `<endpoint>/bulk/<key>` with `{ ids }` of the eligible rows. */
1695
+ private _runDirectAction;
1647
1696
  /** Called when the user clicks a bulk action button in the selection bar. */
1648
1697
  protected onBulkActionClick(def: BulkActionDef): void;
1649
1698
  /** True while the field-change confirmation dialog is open (guards against a second Apply click). */
@@ -1692,6 +1741,11 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1692
1741
  */
1693
1742
  private _fetchCounts;
1694
1743
  ngOnInit(): void;
1744
+ /**
1745
+ * Retry from the error state. A failed table shows no search box or quick tabs (there is nothing to search), so a search term that was
1746
+ * active when the request failed could not be cleared any more: the retry therefore asks for the unsearched list on page 1.
1747
+ */
1748
+ protected _retryAfterError(): void;
1695
1749
  protected onSearchChange(val: string): void;
1696
1750
  /** Phone sort control: "Default" (value '') + one entry per sortable visible column and direction ("<key>:asc|desc"). */
1697
1751
  protected readonly _phoneSortOptions: Signal<{
@@ -2751,7 +2805,7 @@ export declare class CheckboxComponent implements ControlValueAccessor, Validato
2751
2805
  * clicking it still toggles the box - e.g. a product name that is both the heading of its card and the label of its checkbox.
2752
2806
  * Default null: plain label text, exactly as before. Single mode only.
2753
2807
  */
2754
- readonly headingLevel: import("@angular/core").InputSignal<2 | 1 | 3 | 4 | 5 | 6 | null>;
2808
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
2755
2809
  readonly indeterminate: import("@angular/core").InputSignal<boolean>;
2756
2810
  readonly checked: import("@angular/core").ModelSignal<boolean>;
2757
2811
  /**
@@ -3662,7 +3716,7 @@ export declare class PhoneNumberPickerComponent {
3662
3716
  protected readonly modeCtl: FormControl<string>;
3663
3717
  protected readonly zipCtl: FormControl<string>;
3664
3718
  protected readonly areaCtl: FormControl<string>;
3665
- protected readonly step: import("@angular/core").WritableSignal<2 | 1 | 3>;
3719
+ protected readonly step: import("@angular/core").WritableSignal<1 | 2 | 3>;
3666
3720
  protected readonly mode: import("@angular/core").WritableSignal<PhoneNumberSearchMode>;
3667
3721
  private readonly _zip;
3668
3722
  private readonly _area;
@@ -3776,7 +3830,7 @@ export declare class ButtonComponent {
3776
3830
  * `ghost-start`: a ghost button for list / section toggles - a full-width row with its content aligned to the start, transparent
3777
3831
  * background, hover tint and the normal focus ring. Pair it with `ariaExpanded` / `ariaPressed`; the label may contain a heading element.
3778
3832
  */
3779
- readonly variant: import("@angular/core").InputSignal<"link" | "primary" | "secondary" | "danger" | "warning" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
3833
+ readonly variant: import("@angular/core").InputSignal<"primary" | "secondary" | "danger" | "warning" | "link" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
3780
3834
  /** Renders an anchor to this route instead of a button (use with `variant="link"` for an inline text link). `['/settings']` or `'/settings'`. While `disabled` or `loading` it renders a non-clickable `<span role="link" aria-disabled>` with no href (like `href`). */
3781
3835
  readonly routerLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
3782
3836
  /** Query params of the `routerLink` (e.g. `{ section: 'deal-defaults' }`). */
@@ -3815,13 +3869,13 @@ export declare class ButtonComponent {
3815
3869
  * shows when the viewport is narrower than this; from the width itself the long text shows (`640`: >= 640px long, < 640px short, like a
3816
3870
  * `min-width: 640px` switch). Tokens are pure CSS; a number is tracked with `matchMedia`. Default `'md'`.
3817
3871
  */
3818
- readonly shortBelow: import("@angular/core").InputSignal<number | "sm" | "lg" | "md">;
3872
+ readonly shortBelow: import("@angular/core").InputSignal<number | "sm" | "md" | "lg">;
3819
3873
  /** Classes of the two label spans: the token class, or `btn-sl-narrow` while a pixel breakpoint is active. */
3820
3874
  protected readonly _slClass: import("@angular/core").Signal<string>;
3821
3875
  private readonly _narrow;
3822
3876
  readonly color: import("@angular/core").InputSignal<string | undefined>;
3823
3877
  readonly active: import("@angular/core").InputSignal<boolean>;
3824
- readonly size: import("@angular/core").InputSignal<"sm" | "lg" | "md" | "xs">;
3878
+ readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xs">;
3825
3879
  readonly type: import("@angular/core").InputSignal<"reset" | "submit" | "button">;
3826
3880
  readonly disabled: import("@angular/core").InputSignal<boolean>;
3827
3881
  readonly loading: import("@angular/core").InputSignal<boolean>;
@@ -4254,7 +4308,7 @@ export declare class BulkMessagePanelComponent {
4254
4308
  readonly sending: import("@angular/core").InputSignal<boolean>;
4255
4309
  readonly closed: import("@angular/core").OutputEmitterRef<void>;
4256
4310
  readonly send: import("@angular/core").OutputEmitterRef<BulkMessageSendEvent>;
4257
- readonly channel: import("@angular/core").WritableSignal<"email" | "text">;
4311
+ readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
4258
4312
  private readonly _subject;
4259
4313
  private readonly _body;
4260
4314
  get subject(): string;
@@ -4618,7 +4672,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4618
4672
  readonly passwordRequirements: import("@angular/core").InputSignal<boolean>;
4619
4673
  /** Rules for `passwordRequirements`; default = the library's five rules (8+ characters, upper, lower, digit, special). */
4620
4674
  readonly passwordRules: import("@angular/core").InputSignal<readonly PasswordRule[] | undefined>;
4621
- readonly type: import("@angular/core").InputSignal<"number" | "email" | "text" | "tel" | "password" | "url">;
4675
+ readonly type: import("@angular/core").InputSignal<"number" | "text" | "email" | "tel" | "password" | "url">;
4622
4676
  readonly maxlength: import("@angular/core").InputSignal<number | undefined>;
4623
4677
  readonly required: import("@angular/core").InputSignal<boolean>;
4624
4678
  readonly autocomplete: import("@angular/core").InputSignal<string>;
@@ -4627,7 +4681,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4627
4681
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
4628
4682
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
4629
4683
  */
4630
- readonly inputmode: import("@angular/core").InputSignal<"" | "email" | "none" | "text" | "search" | "tel" | "url" | "decimal" | "numeric">;
4684
+ readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
4631
4685
  readonly readonly: import("@angular/core").InputSignal<boolean>;
4632
4686
  readonly hint: import("@angular/core").InputSignal<string>;
4633
4687
  readonly error: import("@angular/core").InputSignal<string>;
@@ -4691,7 +4745,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4691
4745
  protected readonly _stepAttr: import("@angular/core").Signal<string | null>;
4692
4746
  protected readonly _revealable: import("@angular/core").Signal<boolean>;
4693
4747
  protected readonly _shown: import("@angular/core").WritableSignal<boolean>;
4694
- protected readonly _inputType: import("@angular/core").Signal<"number" | "email" | "text" | "tel" | "password" | "url">;
4748
+ protected readonly _inputType: import("@angular/core").Signal<"number" | "text" | "email" | "tel" | "password" | "url">;
4695
4749
  protected readonly _eyePath: string;
4696
4750
  protected readonly _eyeOffPath: string;
4697
4751
  protected readonly _showRequirements: import("@angular/core").Signal<boolean>;
@@ -6031,7 +6085,11 @@ export interface DropdownItem {
6031
6085
  count?: number;
6032
6086
  /** Greyed-out, not selectable and skipped by keyboard navigation. */
6033
6087
  disabled?: boolean;
6088
+ /** Optional 14px icon before the label: an SVG path (the `d` value, like a toolbar action's `icon`). Decorative (hidden from assistive tech). */
6089
+ icon?: string;
6034
6090
  }
6091
+ /** Which edge of the trigger the menu lines up with: `auto` (default) opens from the trigger's left edge and switches to its right edge when the menu would run off the right of the screen. */
6092
+ export type DropdownAlign = 'auto' | 'start' | 'end';
6035
6093
  export declare class DropdownComponent {
6036
6094
  readonly label: import("@angular/core").InputSignal<string>;
6037
6095
  readonly items: import("@angular/core").InputSignal<DropdownItem[]>;
@@ -6048,12 +6106,19 @@ export declare class DropdownComponent {
6048
6106
  */
6049
6107
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
6050
6108
  readonly itemClick: import("@angular/core").OutputEmitterRef<DropdownItem>;
6109
+ /** Which edge of the trigger the menu lines up with (default `auto`: from the left edge, switching to the right edge when it would run off the screen). */
6110
+ readonly align: import("@angular/core").InputSignal<DropdownAlign>;
6051
6111
  protected readonly open: import("@angular/core").WritableSignal<boolean>;
6052
6112
  protected readonly loading: import("@angular/core").WritableSignal<boolean>;
6113
+ /** Placement measured when the menu opens: right-aligned, above the trigger, and the height left on that side (the menu scrolls inside it). */
6114
+ protected readonly alignEnd: import("@angular/core").WritableSignal<boolean>;
6115
+ protected readonly openUp: import("@angular/core").WritableSignal<boolean>;
6116
+ protected readonly menuMaxHeight: import("@angular/core").WritableSignal<number | null>;
6053
6117
  private readonly _loaded;
6054
6118
  private readonly _id;
6055
6119
  private readonly _host;
6056
6120
  private readonly _cdr;
6121
+ private readonly _injector;
6057
6122
  private _pendingFocus;
6058
6123
  private _typeahead;
6059
6124
  private _typeaheadTimer;
@@ -6083,6 +6148,12 @@ export declare class DropdownComponent {
6083
6148
  protected onMenuKeydown(event: KeyboardEvent): void;
6084
6149
  protected onEscape(event: Event): void;
6085
6150
  private _setOpen;
6151
+ /**
6152
+ * Places the open menu from its measured size and the trigger's screen position: it keeps 16px clear of the screen edges, lines up with the trigger's
6153
+ * right edge instead of the left when that is the side with room (`align` = auto), opens above the trigger when there is more room there, and is capped to
6154
+ * the room left on that side (so it scrolls inside only when it truly does not fit). No layout APIs (server rendering) = the default placement.
6155
+ */
6156
+ private _place;
6086
6157
  private _openAndFocus;
6087
6158
  /** Renders the menu synchronously, then focuses the pending first / last enabled item. */
6088
6159
  private _focusPending;
@@ -6131,6 +6202,11 @@ export declare class DropdownComponent {
6131
6202
  "required": false;
6132
6203
  "isSignal": true;
6133
6204
  };
6205
+ "align": {
6206
+ "alias": "align";
6207
+ "required": false;
6208
+ "isSignal": true;
6209
+ };
6134
6210
  }, {
6135
6211
  "itemClick": "itemClick";
6136
6212
  }, never, never, true, never>;
@@ -6220,7 +6296,7 @@ export declare class FormSectionComponent {
6220
6296
  }, {}, never, ["*"], true, never>;
6221
6297
  }
6222
6298
  export declare class FormRowComponent {
6223
- readonly cols: import("@angular/core").InputSignal<2 | 1 | 3 | 4>;
6299
+ readonly cols: import("@angular/core").InputSignal<1 | 2 | 3 | 4>;
6224
6300
  static ɵfac: i0.ɵɵFactoryDeclaration<FormRowComponent, never>;
6225
6301
  static ɵcmp: i0.ɵɵComponentDeclaration<FormRowComponent, "ui-form-row", never, {
6226
6302
  "cols": {
@@ -6237,7 +6313,7 @@ export declare class FormRowComponent {
6237
6313
  * child simply takes the full width. Keep a numeric span within the row's `cols` (use `all` for the whole row).
6238
6314
  */
6239
6315
  export declare class FormColSpanDirective {
6240
- readonly uiColSpan: import("@angular/core").InputSignal<"" | 2 | "2" | "3" | 3 | "all">;
6316
+ readonly uiColSpan: import("@angular/core").InputSignal<"" | "2" | "3" | 2 | 3 | "all">;
6241
6317
  protected readonly _class: import("@angular/core").Signal<string>;
6242
6318
  static ɵfac: i0.ɵɵFactoryDeclaration<FormColSpanDirective, never>;
6243
6319
  static ɵdir: i0.ɵɵDirectiveDeclaration<FormColSpanDirective, "[uiColSpan]", never, {
@@ -7259,11 +7335,11 @@ export declare class ChipComponent implements ControlValueAccessor {
7259
7335
  */
7260
7336
  export declare class ChipGroupComponent {
7261
7337
  /** Space between each chip. */
7262
- readonly gap: import("@angular/core").InputSignal<"sm" | "lg" | "md">;
7338
+ readonly gap: import("@angular/core").InputSignal<"sm" | "md" | "lg">;
7263
7339
  /** Space above the chip group. */
7264
- readonly spaceAbove: import("@angular/core").InputSignal<"sm" | "none" | "md">;
7340
+ readonly spaceAbove: import("@angular/core").InputSignal<"none" | "sm" | "md">;
7265
7341
  /** Space below the chip group. */
7266
- readonly spaceBelow: import("@angular/core").InputSignal<"sm" | "none" | "md">;
7342
+ readonly spaceBelow: import("@angular/core").InputSignal<"none" | "sm" | "md">;
7267
7343
  protected readonly _gap: import("@angular/core").Signal<"6px" | "12px" | "8px">;
7268
7344
  protected readonly _spaceAbove: import("@angular/core").Signal<"0" | "6px" | "12px">;
7269
7345
  protected readonly _spaceBelow: import("@angular/core").Signal<"0" | "6px" | "12px">;
@@ -9171,7 +9247,7 @@ export declare class DetailCardComponent {
9171
9247
  /** true (default) = the title is displayed in capitals (CSS only); false = shown as written. The text, aria-label and heading name are never changed. */
9172
9248
  readonly uppercaseTitle: import("@angular/core").InputSignal<boolean>;
9173
9249
  /** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
9174
- readonly headingLevel: import("@angular/core").InputSignal<2 | 1 | 3 | 4 | 5 | 6 | null>;
9250
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
9175
9251
  /** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
9176
9252
  readonly titleId: import("@angular/core").InputSignal<string>;
9177
9253
  /** Accessible name of the card when the header gives none (no header, or no title). A visible title wins; blank = no name. */
@@ -9204,6 +9280,8 @@ export declare class DetailCardComponent {
9204
9280
  readonly editAriaLabel: import("@angular/core").InputSignal<string>;
9205
9281
  /** true = the card fills the height of its container (a grid cell / flex item) so sibling cards line up; the body grows. Spacing between cells comes from the gap: the filled card's margin-bottom is 0. Default false: unchanged. */
9206
9282
  readonly fill: import("@angular/core").InputSignal<boolean>;
9283
+ /** Max height of the card body (any CSS length, e.g. `360px`): a longer body scrolls inside the card so the card never gets crazy long. Empty = no limit (or the `--dc-body-max-height` custom property, which a page can set on the card or an ancestor). */
9284
+ readonly maxBodyHeight: import("@angular/core").InputSignal<string>;
9207
9285
  /** true = a click on the card (outside interactive controls and text selections) toggles `selected`. The card must contain its own checkbox for keyboard / screen-reader users. Default false: no handler, cursor or outline. */
9208
9286
  readonly selectable: import("@angular/core").InputSignal<boolean>;
9209
9287
  /** Two-way: whether the card is selected (only shown / toggled when `selectable`). */
@@ -9318,6 +9396,11 @@ export declare class DetailCardComponent {
9318
9396
  "required": false;
9319
9397
  "isSignal": true;
9320
9398
  };
9399
+ "maxBodyHeight": {
9400
+ "alias": "maxBodyHeight";
9401
+ "required": false;
9402
+ "isSignal": true;
9403
+ };
9321
9404
  "selectable": {
9322
9405
  "alias": "selectable";
9323
9406
  "required": false;
@@ -9921,7 +10004,7 @@ export declare class SectionHeaderComponent {
9921
10004
  /** 1px border and 10px corners. */
9922
10005
  readonly bordered: import("@angular/core").InputSignal<boolean>;
9923
10006
  /** Visual size: 'sm', 'md' (default), 'lg' or 'xl'. Independent of `level`; anything else renders as 'md'. */
9924
- readonly size: import("@angular/core").InputSignal<"sm" | "lg" | "md" | "xl">;
10007
+ readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xl">;
9925
10008
  /** Remove the built-in top padding. */
9926
10009
  readonly noPaddingTop: import("@angular/core").InputSignal<boolean>;
9927
10010
  /** Remove the built-in left padding. */
@@ -11005,8 +11088,8 @@ export declare class ShowComponent {
11005
11088
  readonly from: import("@angular/core").InputSignal<ShowBreakpoint | null>;
11006
11089
  readonly below: import("@angular/core").InputSignal<ShowBreakpoint | null>;
11007
11090
  private readonly win;
11008
- protected readonly fromToken: import("@angular/core").Signal<"sm" | "lg" | "md" | null>;
11009
- protected readonly belowToken: import("@angular/core").Signal<"sm" | "lg" | "md" | null>;
11091
+ protected readonly fromToken: import("@angular/core").Signal<"sm" | "md" | "lg" | null>;
11092
+ protected readonly belowToken: import("@angular/core").Signal<"sm" | "md" | "lg" | null>;
11010
11093
  protected readonly fromMatch: import("@angular/core").WritableSignal<boolean>;
11011
11094
  protected readonly belowMatch: import("@angular/core").WritableSignal<boolean>;
11012
11095
  constructor();
@@ -11230,7 +11313,7 @@ export interface IntegrationPlainText {
11230
11313
  export declare function integrationPlainText(html: string): IntegrationPlainText;
11231
11314
  /**
11232
11315
  * How a connect button for an integration works.
11233
- * - `oauth`: GET `authorizeEndpoint` answers `{ url }` and the browser goes there (QuickBooks, Slack, Gmail, Outlook, Google / Outlook calendar).
11316
+ * - `oauth`: GET `authorizeEndpoint` answers `{ url }` (or `{ authUrl }`) and the browser goes there (QuickBooks, Slack, Gmail, Outlook, Google / Outlook calendar, Stripe, Square).
11234
11317
  * - `area-code`: asks for a US area code and POSTs `{ areaCode }` to `connectEndpoint` (Twilio buys a number that way); the status is reloaded after.
11235
11318
  */
11236
11319
  export type SetupIntegrationConnect = {
@@ -11373,7 +11456,9 @@ export interface SetupWizardApi {
11373
11456
  markCompleted(...keys: string[]): void;
11374
11457
  }
11375
11458
  /**
11376
- * The integrations every app can offer in a setup step. The endpoints follow the convention the apps' backends already use (`GET <x>/status`,
11459
+ * The integrations every app can offer in a setup step. Payment processing (`stripe`, `square`) belongs in almost every app's wizard:
11460
+ * `setupIntegrations('stripe', 'square')` is the ready-made "connect payments" step (an app that has one processor passes just that one; the
11461
+ * backend answers 409 when the other is already connected, and the step shows it). The endpoints follow the convention the apps' backends already use (`GET <x>/status`,
11377
11462
  * `GET <x>/authorize` answering `{ url }`); an app whose routes differ spreads a preset and overrides what differs:
11378
11463
  * `{ ...SETUP_INTEGRATIONS['quickbooks'], statusEndpoint: '/accounting/status' }`.
11379
11464
  */
@@ -11465,7 +11550,7 @@ export declare class SetupWizardComponent {
11465
11550
  /** An import step with `requireImport` keeps Continue off until something came in (a CSV import or `markCompleted`, e.g. a live sync). */
11466
11551
  protected readonly importBlocked: import("@angular/core").Signal<boolean>;
11467
11552
  /** The step's own two parts (`splitLayout`) show as two tabs, one card at a time; this is the open one (it starts on the app's part on every visit). */
11468
- protected readonly splitTab: import("@angular/core").WritableSignal<"extra" | "main">;
11553
+ protected readonly splitTab: import("@angular/core").WritableSignal<"main" | "extra">;
11469
11554
  protected readonly splitTabs: import("@angular/core").Signal<{
11470
11555
  key: string;
11471
11556
  label: string;
@@ -11554,6 +11639,7 @@ export declare class SetupWizardComponent {
11554
11639
  protected detailFor(i: SetupIntegration): string;
11555
11640
  protected connect(i: SetupIntegration): void;
11556
11641
  private startConnect;
11642
+ private isWebAddress;
11557
11643
  /** SVG path of a library icon (the buttons' leading / trailing glyph). */
11558
11644
  protected iconD(name: string): string;
11559
11645
  protected areaCodeLabelFor(i: SetupIntegration): string;