@simplysm/angular 14.0.23 → 14.0.25

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/docs/core.md DELETED
@@ -1,909 +0,0 @@
1
- # Core
2
-
3
- Providers, plugins, directives, pipes, and utility functions that form the foundation of the `@simplysm/angular` framework.
4
-
5
- ## `TXT_CHANGE_IGNORE_CONFIRM`
6
-
7
- Korean string constant used for "ignore unsaved changes?" confirmation dialogs.
8
-
9
- ```typescript
10
- const TXT_CHANGE_IGNORE_CONFIRM: string;
11
- ```
12
-
13
- ## `provideSdAngular`
14
-
15
- Bootstraps all core Angular providers for a Simplysm application.
16
-
17
- ```typescript
18
- function provideSdAngular(opt: { clientName: string }): EnvironmentProviders;
19
- ```
20
-
21
- Registers: `IMAGE_CONFIG`, NgIcons, theme/local-storage initialization, global error handler, 6 event/command plugins, zoneless change detection, service worker update poller (5 min interval), and router navigation busy counter.
22
-
23
- ## `SdAngularConfigProvider`
24
-
25
- Global configuration holder for the application client name.
26
-
27
- ```typescript
28
- @Injectable({ providedIn: "root" })
29
- class SdAngularConfigProvider {
30
- clientName: string;
31
- }
32
- ```
33
-
34
- ## `SdThemeProvider`
35
-
36
- Dark/light theme toggle. When `dark` is `true`, the `sd-theme-dark` class is applied to `<body>`.
37
-
38
- ```typescript
39
- @Injectable({ providedIn: "root" })
40
- class SdThemeProvider {
41
- dark: WritableSignal<boolean>;
42
- }
43
- ```
44
-
45
- ## `SdSystemLogProvider`
46
-
47
- Centralized logging service.
48
-
49
- ```typescript
50
- @Injectable({ providedIn: "root" })
51
- class SdSystemLogProvider {
52
- writeFn?: (severity: "error" | "warn" | "log", ...data: any[]) => Promise<void> | void;
53
- async writeAsync(severity: "error" | "warn" | "log", ...data: any[]): Promise<void>;
54
- }
55
- ```
56
-
57
- | Field | Type | Description |
58
- |-------|------|-------------|
59
- | `writeFn` | `((severity, ...data) => Promise<void> \| void) \| undefined` | Optional external log handler |
60
-
61
- ## `SdAppStructureProvider`
62
-
63
- Abstract provider that maps application structure (menus, permissions) from a declarative item tree.
64
-
65
- ```typescript
66
- @Injectable({ providedIn: "root" })
67
- abstract class SdAppStructureProvider<TModule> {
68
- abstract items: TSdAppStructureItem<TModule>[];
69
- abstract usableModules: Signal<TModule[] | undefined>;
70
- abstract permRecord: Signal<Record<string, boolean> | undefined>;
71
-
72
- usableMenus: Signal<ISdMenu<TModule>[]>;
73
- usableFlatMenus: Signal<ISdFlatMenu<TModule>[]>;
74
- getPermissionsByStructure(items: TSdAppStructureItem<TModule>[], codeChain?: string[]): ISdPermission<TModule>[];
75
- getTitleByFullCode(fullCode: string): string;
76
- getItemChainByFullCode(fullCode: string): TSdAppStructureItem<TModule>[];
77
- getPermsByFullCode<K extends string>(fullCodes: string[], permKeys: K[]): K[];
78
- }
79
- ```
80
-
81
- ## `SdAppStructureUtils`
82
-
83
- Static utility class for app structure operations without provider injection.
84
-
85
- ```typescript
86
- abstract class SdAppStructureUtils {
87
- static getTitleByFullCode<TModule>(items: TSdAppStructureItem<TModule>[], fullCode: string): string;
88
- static getPermsByFullCode<TModule, K extends string>(items: TSdAppStructureItem<TModule>[], fullCodes: string[], permKeys: K[], permRecord: Record<string, boolean>): K[];
89
- static getItemChainByFullCode<TModule>(items: TSdAppStructureItem<TModule>[], fullCode: string): TSdAppStructureItem<TModule>[];
90
- static getMenus<TModule>(items: TSdAppStructureItem<TModule>[], codeChain: string[], usableModules: TModule[] | undefined, permRecord: Record<string, boolean> | undefined): ISdMenu<TModule>[];
91
- static getFlatMenus<TModule>(items: TSdAppStructureItem<TModule>[], usableModules: TModule[] | undefined, permRecord: Record<string, boolean> | undefined): ISdFlatMenu<TModule>[];
92
- static getPermissions<TModule>(items: TSdAppStructureItem<TModule>[], codeChain: string[], usableModules: TModule[] | undefined): ISdPermission<TModule>[];
93
- static getFlatPermissions<TModule>(items: TSdAppStructureItem<TModule>[], usableModules: TModule[] | undefined): ISdFlatPermission<TModule>[];
94
- }
95
- ```
96
-
97
- ## `TSdAppStructureItem`
98
-
99
- Discriminated union for app structure tree nodes.
100
-
101
- ```typescript
102
- type TSdAppStructureItem<TModule> = ISdAppStructureGroupItem<TModule> | ISdAppStructureLeafItem<TModule>;
103
- ```
104
-
105
- ## `ISdMenu`
106
-
107
- ```typescript
108
- interface ISdMenu<TModule> {
109
- title: string;
110
- codeChain: string[];
111
- icon: string | undefined;
112
- modules: TModule[] | undefined;
113
- children: ISdMenu<TModule>[] | undefined;
114
- }
115
- ```
116
-
117
- | Field | Type | Description |
118
- |-------|------|-------------|
119
- | `title` | `string` | Menu display text |
120
- | `codeChain` | `string[]` | Hierarchical code path |
121
- | `icon` | `string \| undefined` | Icon SVG string |
122
- | `modules` | `TModule[] \| undefined` | Required modules for visibility |
123
- | `children` | `ISdMenu<TModule>[] \| undefined` | Sub-menus |
124
-
125
- ## `ISdFlatMenu`
126
-
127
- ```typescript
128
- interface ISdFlatMenu<TModule> {
129
- titleChain: string[];
130
- codeChain: string[];
131
- modulesChain: TModule[][];
132
- }
133
- ```
134
-
135
- | Field | Type | Description |
136
- |-------|------|-------------|
137
- | `titleChain` | `string[]` | Flattened title breadcrumb |
138
- | `codeChain` | `string[]` | Flattened code path |
139
- | `modulesChain` | `TModule[][]` | Module requirements per level |
140
-
141
- ## `ISdPermission`
142
-
143
- ```typescript
144
- interface ISdPermission<TModule> {
145
- title: string;
146
- codeChain: string[];
147
- modules: TModule[] | undefined;
148
- perms: ("use" | "edit")[] | undefined;
149
- children: ISdPermission<TModule>[] | undefined;
150
- }
151
- ```
152
-
153
- | Field | Type | Description |
154
- |-------|------|-------------|
155
- | `title` | `string` | Permission display text |
156
- | `codeChain` | `string[]` | Hierarchical code path |
157
- | `modules` | `TModule[] \| undefined` | Required modules |
158
- | `perms` | `("use" \| "edit")[] \| undefined` | Permission keys |
159
- | `children` | `ISdPermission<TModule>[] \| undefined` | Sub-permissions |
160
-
161
- ## `ISdFlatPermission`
162
-
163
- ```typescript
164
- interface ISdFlatPermission<TModule> {
165
- titleChain: string[];
166
- codeChain: string[];
167
- modulesChain: TModule[][];
168
- }
169
- ```
170
-
171
- | Field | Type | Description |
172
- |-------|------|-------------|
173
- | `titleChain` | `string[]` | Flattened title breadcrumb |
174
- | `codeChain` | `string[]` | Flattened code path |
175
- | `modulesChain` | `TModule[][]` | Module requirements per level |
176
-
177
- ## `usePermsSignal`
178
-
179
- Reactive permission checker as a computed signal.
180
-
181
- ```typescript
182
- function usePermsSignal<K extends string>(viewCodes: string[], keys: K[]): Signal<K[]>;
183
- ```
184
-
185
- Returns a signal containing the subset of `keys` the current user has permission for across the given `viewCodes`.
186
-
187
- ## `SdFileDialogProvider`
188
-
189
- Opens a native file picker dialog via a hidden `<input type="file">`.
190
-
191
- ```typescript
192
- @Injectable({ providedIn: "root" })
193
- class SdFileDialogProvider {
194
- async showAsync(multiple?: false, accept?: string): Promise<File | undefined>;
195
- async showAsync(multiple: true, accept?: string): Promise<File[] | undefined>;
196
- }
197
- ```
198
-
199
- ## `SdLocalStorageProvider`
200
-
201
- Typed wrapper around `localStorage` with `clientName`-prefixed keys and JSON serialization.
202
-
203
- ```typescript
204
- @Injectable({ providedIn: "root" })
205
- class SdLocalStorageProvider<T> {
206
- set<K extends keyof T & string>(key: K, value: T[K]): void;
207
- get<K extends keyof T & string>(key: K): T[K] | undefined;
208
- remove(key: keyof T & string): void;
209
- }
210
- ```
211
-
212
- ## `SdSystemConfigProvider`
213
-
214
- Async config storage abstraction. Falls back to local storage when no external handler is set.
215
-
216
- ```typescript
217
- @Injectable({ providedIn: "root" })
218
- class SdSystemConfigProvider<T> {
219
- fn?: {
220
- set<K extends keyof T & string>(key: K, data: T[K]): Promise<void> | void;
221
- get(key: keyof T & string): PromiseLike<any>;
222
- };
223
- async setAsync<K extends keyof T & string>(key: K, data: T[K]): Promise<void>;
224
- async getAsync(key: keyof T & string): Promise<any>;
225
- }
226
- ```
227
-
228
- ## `SdServiceClientFactoryProvider`
229
-
230
- Manages `ServiceClient` connections by key.
231
-
232
- ```typescript
233
- @Injectable({ providedIn: "root" })
234
- class SdServiceClientFactoryProvider {
235
- async connectAsync(key: string, options?: Partial<ServiceConnectionOptions>): Promise<void>;
236
- async closeAsync(key: string): Promise<void>;
237
- get(key: string): ServiceClient;
238
- }
239
- ```
240
-
241
- ## `SdSharedDataProvider`
242
-
243
- Abstract provider for shared (cached, event-driven) data. Subclass and register data sources.
244
-
245
- ```typescript
246
- @Injectable()
247
- abstract class SdSharedDataProvider<T extends Record<string, ISharedDataBase<string | number>>> {
248
- loadingCount: WritableSignal<number>;
249
- abstract initialize(): void;
250
- register<K extends string & keyof T>(name: K, info: ISharedDataInfo<T[K]>): void;
251
- getHandle<K extends string & keyof T>(name: K): SharedDataHandle<T[K]>;
252
- async emitAsync<K extends string & keyof T>(name: K, changeKeys?: (string | number)[]): Promise<void>;
253
- async wait(): Promise<void>;
254
- }
255
- ```
256
-
257
- ## `SdSharedDataChangeEvent`
258
-
259
- Event definition for shared data change notifications across service connections.
260
-
261
- ```typescript
262
- const SdSharedDataChangeEvent: EventDef<{ name: string; filter: unknown }, (string | number)[] | undefined>;
263
- ```
264
-
265
- ## `ISharedDataBase`
266
-
267
- Base interface for shared data items.
268
-
269
- ```typescript
270
- interface ISharedDataBase<TKey extends string | number> {
271
- __valueKey: TKey;
272
- __searchText: string;
273
- __isHidden: boolean;
274
- __parentKey?: TKey;
275
- }
276
- ```
277
-
278
- | Field | Type | Description |
279
- |-------|------|-------------|
280
- | `__valueKey` | `TKey` | Unique identifier |
281
- | `__searchText` | `string` | Text used for search filtering |
282
- | `__isHidden` | `boolean` | Whether the item is hidden from display |
283
- | `__parentKey` | `TKey \| undefined` | Parent key for tree hierarchy |
284
-
285
- ## `ISharedDataInfo`
286
-
287
- Registration descriptor for a shared data source.
288
-
289
- ```typescript
290
- interface ISharedDataInfo<T extends ISharedDataBase<string | number>> {
291
- serviceKey: string;
292
- getter: (changeKeys?: (string | number)[]) => Promise<T[]>;
293
- filter?: unknown;
294
- orderBy?: (a: T, b: T) => number;
295
- }
296
- ```
297
-
298
- | Field | Type | Description |
299
- |-------|------|-------------|
300
- | `serviceKey` | `string` | Service connection key |
301
- | `getter` | `(changeKeys?) => Promise<T[]>` | Data fetch function; receives changed keys for incremental update |
302
- | `filter` | `unknown` | Optional filter passed to the service event |
303
- | `orderBy` | `((a, b) => number) \| undefined` | Optional sort comparator |
304
-
305
- ## `SharedDataHandle`
306
-
307
- Read handle returned by `SdSharedDataProvider.getHandle()`.
308
-
309
- ```typescript
310
- interface SharedDataHandle<T extends ISharedDataBase<string | number>> {
311
- items: Signal<T[]>;
312
- get(key: T["__valueKey"] | undefined): T | undefined;
313
- }
314
- ```
315
-
316
- | Field | Type | Description |
317
- |-------|------|-------------|
318
- | `items` | `Signal<T[]>` | Reactive list of all items |
319
- | `get` | `(key) => T \| undefined` | Lookup a single item by key |
320
-
321
- ## `SdNavigateWindowProvider`
322
-
323
- Manages new-window navigation with auto-close on parent `beforeunload`.
324
-
325
- ```typescript
326
- @Injectable({ providedIn: "root" })
327
- class SdNavigateWindowProvider {
328
- get isWindow(): boolean;
329
- open(navigate: string, params?: Record<string, string>, features?: string): void;
330
- }
331
- ```
332
-
333
- ## `SdPrintProvider`
334
-
335
- Dynamically renders a component for printing or PDF generation.
336
-
337
- ```typescript
338
- @Injectable({ providedIn: "root" })
339
- class SdPrintProvider {
340
- async printAsync<T extends ISdPrint>(template: ISdPrintInput<T>, options?: { size?: string; margin?: string }): Promise<void>;
341
- async getPdfBufferAsync<T extends ISdPrint>(template: ISdPrintInput<T>, options?: { orientation?: "portrait" | "landscape"; pageSize?: string }): Promise<Uint8Array>;
342
- }
343
- ```
344
-
345
- ## `ISdPrint`
346
-
347
- Contract for printable components.
348
-
349
- ```typescript
350
- interface ISdPrint {
351
- initialized: Signal<boolean>;
352
- }
353
- ```
354
-
355
- ## `ISdPrintInput`
356
-
357
- Input descriptor for `SdPrintProvider`.
358
-
359
- ```typescript
360
- interface ISdPrintInput<T, X extends keyof any = ""> {
361
- type: Type<T>;
362
- inputs: Omit<TDirectiveInputSignals<T>, X>;
363
- }
364
- ```
365
-
366
- | Field | Type | Description |
367
- |-------|------|-------------|
368
- | `type` | `Type<T>` | Component class to render |
369
- | `inputs` | `Omit<TDirectiveInputSignals<T>, X>` | Input values to set on the component |
370
-
371
- ## `SdGlobalErrorHandlerPlugin`
372
-
373
- Global error handler that logs via `SdSystemLogProvider`, shows a full-screen error overlay, and reloads on click.
374
-
375
- ```typescript
376
- @Injectable({ providedIn: null })
377
- class SdGlobalErrorHandlerPlugin implements ErrorHandler {
378
- handleError(event: any): void;
379
- }
380
- ```
381
-
382
- ## `SdOptionEventPlugin`
383
-
384
- Event plugin that adds `.capture`, `.passive`, `.once` suffix support to native DOM events.
385
-
386
- ```typescript
387
- @Injectable({ providedIn: null })
388
- class SdOptionEventPlugin extends EventManagerPlugin {
389
- supports(eventName: string): boolean;
390
- addEventListener(element: HTMLElement, eventName: string, handler: Function): () => void;
391
- }
392
- ```
393
-
394
- ## `SdResizeEventPlugin`
395
-
396
- Event plugin for the `sdResize` custom event using `ResizeObserver`.
397
-
398
- ```typescript
399
- @Injectable({ providedIn: null })
400
- class SdResizeEventPlugin extends EventManagerPlugin {
401
- supports(eventName: string): boolean;
402
- addEventListener(element: HTMLElement, eventName: string, handler: Function): () => void;
403
- }
404
- ```
405
-
406
- ## `ISdResizeEvent`
407
-
408
- ```typescript
409
- interface ISdResizeEvent {
410
- heightChanged: boolean;
411
- widthChanged: boolean;
412
- target: Element;
413
- contentRect: DOMRectReadOnly;
414
- }
415
- ```
416
-
417
- | Field | Type | Description |
418
- |-------|------|-------------|
419
- | `heightChanged` | `boolean` | Whether height changed |
420
- | `widthChanged` | `boolean` | Whether width changed |
421
- | `target` | `Element` | Observed element |
422
- | `contentRect` | `DOMRectReadOnly` | New content rect |
423
-
424
- ## `SdIntersectionEventPlugin`
425
-
426
- Event plugin for the `sdIntersection` custom event using `IntersectionObserver`.
427
-
428
- ```typescript
429
- @Injectable({ providedIn: null })
430
- class SdIntersectionEventPlugin extends EventManagerPlugin {
431
- supports(eventName: string): boolean;
432
- addEventListener(element: HTMLElement, eventName: string, handler: Function): () => void;
433
- }
434
- ```
435
-
436
- ## `ISdIntersectionEvent`
437
-
438
- ```typescript
439
- interface ISdIntersectionEvent {
440
- entry: IntersectionObserverEntry;
441
- }
442
- ```
443
-
444
- | Field | Type | Description |
445
- |-------|------|-------------|
446
- | `entry` | `IntersectionObserverEntry` | Intersection observer entry |
447
-
448
- ## `SdSaveCommandEventPlugin`
449
-
450
- Event plugin for `sdSaveCommand` — fires on `Ctrl+S` (no Alt/Shift). Scoped to the topmost open modal.
451
-
452
- ```typescript
453
- @Injectable({ providedIn: null })
454
- class SdSaveCommandEventPlugin extends EventManagerPlugin { }
455
- ```
456
-
457
- ## `SdRefreshCommandEventPlugin`
458
-
459
- Event plugin for `sdRefreshCommand` — fires on `Ctrl+Alt+L`.
460
-
461
- ```typescript
462
- @Injectable({ providedIn: null })
463
- class SdRefreshCommandEventPlugin extends EventManagerPlugin { }
464
- ```
465
-
466
- ## `SdInsertCommandEventPlugin`
467
-
468
- Event plugin for `sdInsertCommand` — fires on `Ctrl+Insert`.
469
-
470
- ```typescript
471
- @Injectable({ providedIn: null })
472
- class SdInsertCommandEventPlugin extends EventManagerPlugin { }
473
- ```
474
-
475
- ## `SdEventsDirective`
476
-
477
- Directive that exposes captured/passive/once event variants and custom events as Angular outputs.
478
-
479
- ```typescript
480
- @Directive({ standalone: true })
481
- class SdEventsDirective {
482
- // Outputs include:
483
- // "click.capture", "click.once", "click.capture.once",
484
- // "mousedown.capture", "mouseup.capture", "mouseover.capture", "mouseout.capture",
485
- // "keydown.capture", "keyup.capture", "focus.capture", "blur.capture",
486
- // "invalid.capture", "scroll.capture", "scroll.passive", "scroll.capture.passive",
487
- // "wheel.passive", "wheel.capture.passive",
488
- // "touchstart.passive", "touchstart.capture.passive",
489
- // "touchmove.passive", "touchmove.capture.passive",
490
- // "touchend.passive", "dragover.capture", "dragenter.capture",
491
- // "dragleave.capture", "drop.capture",
492
- // "transitionend.once", "animationend.once",
493
- // "sdResize", "sdRefreshCommand", "sdSaveCommand", "sdInsertCommand"
494
- }
495
- ```
496
-
497
- ## `SdRippleDirective`
498
-
499
- Applies a material-style ripple effect to the host element.
500
-
501
- ```typescript
502
- @Directive({ standalone: true, selector: "[sd-ripple]" })
503
- class SdRippleDirective {
504
- enabled: InputSignal<boolean>; // alias: "sd-ripple"
505
- }
506
- ```
507
-
508
- ## `SdShowEffectDirective`
509
-
510
- Applies an entrance animation (fade + slide) when the host element enters the viewport.
511
-
512
- ```typescript
513
- @Directive({ standalone: true, selector: "[sd-show-effect]" })
514
- class SdShowEffectDirective {
515
- enabled: InputSignal<boolean>; // alias: "sd-show-effect"
516
- sdShowEffectType: InputSignal<"l2r" | "t2b">; // default: "t2b"
517
- }
518
- ```
519
-
520
- ## `SdInvalidDirective`
521
-
522
- Adds a validation indicator dot and hidden `<input>` with `setCustomValidity` to the host element.
523
-
524
- ```typescript
525
- @Directive({ standalone: true, selector: "[sd-invalid]" })
526
- class SdInvalidDirective {
527
- invalidMessage: InputSignal<string>; // alias: "sd-invalid"
528
- }
529
- ```
530
-
531
- ## `SdTypedTemplateDirective`
532
-
533
- Provides type-safe template context via Angular's `ngTemplateContextGuard`.
534
-
535
- ```typescript
536
- @Directive({ standalone: true, selector: "ng-template[typed]" })
537
- class SdTypedTemplateDirective<T> {
538
- typed: InputSignal<T>;
539
- static ngTemplateContextGuard<TypeToken>(dir: SdTypedTemplateDirective<TypeToken>, ctx: unknown): ctx is TypeToken;
540
- }
541
- ```
542
-
543
- ## `SdItemOfTemplateDirective`
544
-
545
- Template directive for typed item iteration with context.
546
-
547
- ```typescript
548
- @Directive({ standalone: true, selector: "ng-template[itemOf]" })
549
- class SdItemOfTemplateDirective<TItem> {
550
- itemOf: InputSignal<TItem[]>;
551
- static ngTemplateContextGuard<TContextItem>(dir: SdItemOfTemplateDirective<TContextItem>, ctx: unknown): ctx is SdItemOfTemplateContext<TContextItem>;
552
- }
553
- ```
554
-
555
- ## `SdItemOfTemplateContext`
556
-
557
- ```typescript
558
- interface SdItemOfTemplateContext<TItem> {
559
- $implicit: TItem;
560
- item: TItem;
561
- index: number;
562
- depth: number;
563
- }
564
- ```
565
-
566
- | Field | Type | Description |
567
- |-------|------|-------------|
568
- | `$implicit` | `TItem` | Current item (default template variable) |
569
- | `item` | `TItem` | Current item (named) |
570
- | `index` | `number` | Item index |
571
- | `depth` | `number` | Nesting depth (for tree structures) |
572
-
573
- ## `SdRouterLinkDirective`
574
-
575
- Enhanced router link with support for Ctrl/Shift-click (new tab), window popup mode, and outlet navigation.
576
-
577
- ```typescript
578
- @Directive({ standalone: true, selector: "[sd-router-link]" })
579
- class SdRouterLinkDirective {
580
- option: InputSignal<{
581
- link: string;
582
- params?: Record<string, string>;
583
- window?: { width?: number; height?: number };
584
- outletName?: string;
585
- queryParams?: Record<string, string>;
586
- } | undefined>; // alias: "sd-router-link"
587
- }
588
- ```
589
-
590
- ## `FormatPipe`
591
-
592
- Pipe that formats `DateTime`, `DateOnly`, or `string` values.
593
-
594
- ```typescript
595
- @Pipe({ name: "format", standalone: true })
596
- class FormatPipe implements PipeTransform {
597
- transform(value: string | DateTime | DateOnly | undefined, format: string): string;
598
- }
599
- ```
600
-
601
- - `DateTime`/`DateOnly`: calls `toFormatString(format)`
602
- - `string`: applies `X`-placeholder pattern matching (patterns separated by `|`)
603
- - `undefined`: returns `""`
604
-
605
- ## `setSafeStyle`
606
-
607
- Applies multiple CSS style properties at once via `Renderer2.setStyle`.
608
-
609
- ```typescript
610
- function setSafeStyle(renderer: Renderer2, el: HTMLElement, style: Partial<CSSStyleDeclaration>): void;
611
- ```
612
-
613
- ## `setupBgTheme`
614
-
615
- Sets the body `--background-color` CSS variable to a theme token during component lifetime.
616
-
617
- ```typescript
618
- function setupBgTheme(options?: {
619
- theme?: "primary" | "secondary" | "info" | "success" | "warning" | "danger" | "gray" | "blue-gray";
620
- lightness?: "lightest" | "lighter";
621
- }): void;
622
- ```
623
-
624
- ## `setupRipple`
625
-
626
- Attaches ripple effect event handlers to the current component's host element.
627
-
628
- ```typescript
629
- function setupRipple(enableFn?: () => boolean): void;
630
- ```
631
-
632
- ## `setupRevealOnShow`
633
-
634
- Applies an IntersectionObserver-driven entrance animation to the component host.
635
-
636
- ```typescript
637
- function setupRevealOnShow(optFn?: () => { type?: "l2r" | "t2b"; enabled?: boolean }): void;
638
- ```
639
-
640
- ## `setupInvalid`
641
-
642
- Injects a validation indicator and hidden input with custom validity into the host element.
643
-
644
- ```typescript
645
- function setupInvalid(getInvalidMessage: () => string): void;
646
- ```
647
-
648
- ## `setupModelHook`
649
-
650
- Intercepts `WritableSignal.set` to guard value changes with a sync or async predicate.
651
-
652
- ```typescript
653
- function setupModelHook<T, S extends WritableSignal<T>>(model: S, canFn: Signal<(item: T) => boolean | Promise<boolean>>): void;
654
- ```
655
-
656
- ## `setupCanDeactivate`
657
-
658
- Registers a deactivation guard on the current modal or route.
659
-
660
- ```typescript
661
- function setupCanDeactivate(fn: () => boolean): void;
662
- ```
663
-
664
- ## `setupCumulateSelectedKeys`
665
-
666
- Keeps `selectedItems` and `selectedItemKeys` in sync as the `items` list changes.
667
-
668
- ```typescript
669
- function setupCumulateSelectedKeys<TItem, TKey>(options: {
670
- items: Signal<TItem[]>;
671
- selectedItems: WritableSignal<TItem[]>;
672
- selectedItemKeys: WritableSignal<TKey[]>;
673
- selectMode: () => "single" | "multi" | undefined;
674
- keySelectorFn: (item: TItem) => TKey | undefined;
675
- }): void;
676
- ```
677
-
678
- ## `setupCloserWhenSingleSelectionChange`
679
-
680
- Auto-emits `close` when selection changes in single-select mode.
681
-
682
- ```typescript
683
- function setupCloserWhenSingleSelectionChange<TItem, TKey>(options: {
684
- selectedItemKeys: Signal<TKey[]>;
685
- selectedItems: Signal<TItem[]>;
686
- selectMode: () => "single" | "multi" | undefined;
687
- close: OutputEmitterRef<{ selectedItemKeys: TKey[]; selectedItems: TItem[] }>;
688
- }): void;
689
- ```
690
-
691
- ## `useSdSystemConfigResource`
692
-
693
- Angular `resource` wrapper backed by `SdSystemConfigProvider`.
694
-
695
- ```typescript
696
- function useSdSystemConfigResource<T>(options: {
697
- key: Signal<string | undefined>;
698
- }): {
699
- value: Signal<T | undefined>;
700
- isLoading: Signal<boolean>;
701
- status: Signal<ResourceStatus>;
702
- hasValue(): boolean;
703
- reload(): void;
704
- set(value: T): void;
705
- update(fn: (prev: T | undefined) => T): void;
706
- };
707
- ```
708
-
709
- ## `useCurrentPageCodeSignal`
710
-
711
- Returns a signal with the current route's page code (dot-separated path segments).
712
-
713
- ```typescript
714
- function useCurrentPageCodeSignal(): Signal<string> | undefined;
715
- ```
716
-
717
- ## `useFullPageCodeSignal`
718
-
719
- Returns a signal with the full URL path converted to dot-separated page code. Updates on `NavigationEnd`.
720
-
721
- ```typescript
722
- function useFullPageCodeSignal(): Signal<string>;
723
- ```
724
-
725
- ## `useViewTitleSignal`
726
-
727
- Returns the current view title from modal or app structure.
728
-
729
- ```typescript
730
- function useViewTitleSignal(): Signal<string>;
731
- ```
732
-
733
- ## `useViewTypeSignal`
734
-
735
- Returns the current view context type.
736
-
737
- ```typescript
738
- function useViewTypeSignal(getComp: () => object): Signal<TSdViewType>;
739
- ```
740
-
741
- ## `TSdViewType`
742
-
743
- ```typescript
744
- type TSdViewType = "page" | "modal" | "control";
745
- ```
746
-
747
- ## `useExpandingManager`
748
-
749
- Manages tree expand/collapse state for hierarchical item lists.
750
-
751
- ```typescript
752
- function useExpandingManager<T>(binding: {
753
- items: Signal<T[]>;
754
- expandedItems: WritableSignal<T[]>;
755
- getChildrenFn: Signal<((item: T, index: number) => T[] | undefined) | undefined>;
756
- sort: (items: T[]) => T[];
757
- }): {
758
- displayItems: Signal<T[]>;
759
- hasExpandable: Signal<boolean>;
760
- isAllExpanded: Signal<boolean>;
761
- toggle(item: T): void;
762
- toggleAll(): void;
763
- isVisible(item: T): boolean;
764
- def(item: T): IExpandItemDef<T>;
765
- };
766
- ```
767
-
768
- ## `IExpandItemDef`
769
-
770
- ```typescript
771
- interface IExpandItemDef<T> {
772
- item: T;
773
- parentDef: IExpandItemDef<T> | undefined;
774
- hasChildren: boolean;
775
- depth: number;
776
- }
777
- ```
778
-
779
- | Field | Type | Description |
780
- |-------|------|-------------|
781
- | `item` | `T` | The data item |
782
- | `parentDef` | `IExpandItemDef<T> \| undefined` | Parent node definition |
783
- | `hasChildren` | `boolean` | Whether this node has children |
784
- | `depth` | `number` | Nesting depth (0-based) |
785
-
786
- ## `useSelectionManager`
787
-
788
- Manages item selection state with single/multi mode support.
789
-
790
- ```typescript
791
- function useSelectionManager<T>(options: {
792
- displayItems: Signal<T[]>;
793
- selectedItems: WritableSignal<T[]>;
794
- selectMode: Signal<"single" | "multi" | undefined>;
795
- getItemSelectableFn: Signal<((item: T) => boolean | string) | undefined>;
796
- }): {
797
- hasSelectable: Signal<boolean>;
798
- isAllSelected: Signal<boolean>;
799
- getSelectable(item: T): true | string | undefined;
800
- getCanChangeFn(item: T): () => boolean;
801
- select(item: T): void;
802
- deselect(item: T): void;
803
- toggle(item: T): void;
804
- toggleAll(): void;
805
- isSelected(item: T): boolean;
806
- };
807
- ```
808
-
809
- ## `useSortingManager`
810
-
811
- Manages multi-column sorting state with toggle behavior.
812
-
813
- ```typescript
814
- function useSortingManager(options: {
815
- sorts: WritableSignal<ISortingDef[]>;
816
- }): {
817
- defMap: Signal<Map<string, { indexText?: string; desc: boolean }>>;
818
- toggle(key: string, multiple: boolean): void;
819
- sort<T>(items: T[]): T[];
820
- };
821
- ```
822
-
823
- - `toggle`: cycles none → asc → desc → remove. `multiple` preserves existing sorts.
824
- - `sort`: sorts items by current `sorts` definitions. Strings use `localeCompare`; nulls sort first.
825
-
826
- ## `ISortingDef`
827
-
828
- ```typescript
829
- interface ISortingDef {
830
- key: string;
831
- desc: boolean;
832
- }
833
- ```
834
-
835
- | Field | Type | Description |
836
- |-------|------|-------------|
837
- | `key` | `string` | Property name to sort by |
838
- | `desc` | `boolean` | Descending order when `true` |
839
-
840
- ## `injectParent`
841
-
842
- Traverses the Angular component tree to find a parent component instance.
843
-
844
- ```typescript
845
- function injectParent(): unknown;
846
- function injectParent<T>(type: AbstractType<T>): T;
847
- function injectParent<T>(type: AbstractType<T>, options: { optional: true }): T | undefined;
848
- ```
849
-
850
- ## `TDirectiveInputSignals`
851
-
852
- Extracts input signal value types from a component/directive class, converting `undefined`-accepting inputs to optional properties.
853
-
854
- ```typescript
855
- type TDirectiveInputSignals<T> = /* mapped type extracting InputSignal value types with TUndefToOptional */;
856
- ```
857
-
858
- Example: `{ name = input.required<string>(); age = input(0) }` → `{ name: string; age: number }`
859
-
860
- ## `TUndefToOptional`
861
-
862
- Converts properties whose type includes `undefined` to optional properties.
863
-
864
- ```typescript
865
- type TUndefToOptional<T> = /* { a: string; b: number | undefined } → { a: string; b?: number } */;
866
- ```
867
-
868
- ## `TWithOptional`
869
-
870
- Converts specified keys of a type to optional.
871
-
872
- ```typescript
873
- type TWithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
874
- ```
875
-
876
- ## `withBusy`
877
-
878
- Wraps an async function with a busy signal increment/decrement. Increments `busyCount` before execution and decrements in `finally`.
879
-
880
- ```typescript
881
- async function withBusy(
882
- busyCount: WritableSignal<number>,
883
- fn: () => Promise<void>,
884
- ): Promise<void>;
885
- ```
886
-
887
- ## `mark`
888
-
889
- Manually notifies signal consumers of a change. Useful when an object/array is mutated in place rather than replaced.
890
-
891
- ```typescript
892
- function mark(sig: WritableSignal<any>, clone?: boolean): void;
893
- ```
894
-
895
- | Parameter | Type | Description |
896
- |-----------|------|-------------|
897
- | `sig` | `WritableSignal<any>` | The signal to mark as changed |
898
- | `clone` | `boolean` (optional) | If `true`, performs a shallow clone via `update()` (array spread or object spread). If `false`/omitted, directly increments the signal version using Angular internal primitives (`producerIncrementEpoch`, `producerNotifyConsumers`). |
899
-
900
- ## `setupModelHook`
901
-
902
- Intercepts a `WritableSignal.set` to guard value changes with a sync/async predicate.
903
-
904
- ```typescript
905
- function setupModelHook<T, S extends WritableSignal<T>>(
906
- model: S,
907
- canFn: Signal<(item: T) => boolean | Promise<boolean>>,
908
- ): void;
909
- ```