@simplysm/angular 14.0.22 → 14.0.24

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/features.md DELETED
@@ -1,402 +0,0 @@
1
- # Features
2
-
3
- High-level feature components: address search, base container, data sheet/detail views, and shared-data-backed controls.
4
-
5
- ## `SdAddressSearchModal`
6
-
7
- Modal component that embeds the Daum Postcode widget for Korean address lookup. Implements `ISdModal<IAddress>`.
8
-
9
- ```typescript
10
- @Component({ selector: "sd-address-search-modal" })
11
- class SdAddressSearchModal implements ISdModal<IAddress>, OnInit {
12
- close = output<IAddress>();
13
- initialized = signal(false);
14
- }
15
- ```
16
-
17
- ## `IAddress`
18
-
19
- ```typescript
20
- interface IAddress {
21
- postNumber: string | undefined;
22
- address: string | undefined;
23
- buildingName: string | undefined;
24
- }
25
- ```
26
-
27
- | Field | Type | Description |
28
- |-------|------|-------------|
29
- | `postNumber` | `string \| undefined` | Postal (zone) code |
30
- | `address` | `string \| undefined` | Full road/lot address |
31
- | `buildingName` | `string \| undefined` | Building name |
32
-
33
- ## `SdPermissionTableControl`
34
-
35
- Matrix table component that displays a hierarchical permission structure with use/edit checkboxes. Groups and leaf items are rendered with depth-based coloring and collapse/expand support.
36
-
37
- ```typescript
38
- @Component({ selector: "sd-permission-table" })
39
- class SdPermissionTableControl<TModule> {
40
- value = model<Record<string, boolean>>({});
41
- items = input<ISdPermission<TModule>[]>([]);
42
- disabled = input(false, { transform: booleanAttribute });
43
- }
44
- ```
45
-
46
- | Input/Model | Type | Description |
47
- |-------------|------|-------------|
48
- | `value` | `Record<string, boolean>` | Two-way binding of permission key-value map (e.g., `{ "admin.users.use": true }`) |
49
- | `items` | `ISdPermission<TModule>[]` | Hierarchical permission tree from `SdAppStructureProvider` |
50
- | `disabled` | `boolean` | Disables all checkboxes |
51
-
52
- Behaviors:
53
- - Unchecking "use" automatically unchecks "edit" for the same item
54
- - "edit" checkbox is disabled when "use" is unchecked
55
- - Checking/unchecking a parent cascades to all children
56
- - Collapsible groups with depth-based theme coloring (info/warning/success cycle)
57
-
58
- ## `SdBaseContainerControl`
59
-
60
- Layout shell that wraps a page or modal. Handles busy state, access restriction, and auto-resolves title from app structure or modal context.
61
-
62
- ```typescript
63
- @Component({ selector: "sd-base-container" })
64
- class SdBaseContainerControl {
65
- viewType = input<TSdViewType>();
66
- header = input<string>();
67
- initialized = input<boolean | undefined>(undefined);
68
- restricted = input(false, { transform: booleanAttribute });
69
- busy = input(false, { transform: booleanAttribute });
70
- busyMessage = input<string>();
71
- }
72
- ```
73
-
74
- | Input | Type | Description |
75
- |-------|------|-------------|
76
- | `viewType` | `TSdViewType \| undefined` | Override view type |
77
- | `header` | `string \| undefined` | Explicit title override |
78
- | `initialized` | `boolean \| undefined` | Controls rendering gate |
79
- | `restricted` | `boolean` | Shows "no permission" message |
80
- | `busy` | `boolean` | Shows busy spinner |
81
- | `busyMessage` | `string \| undefined` | Message shown during busy |
82
-
83
- Content templates: `#contentTpl` (required), `#pageTopbarTpl`, `#modalBottomTpl`.
84
-
85
- ## `SdDataSheetControl`
86
-
87
- Presentation component for data sheet views. Must be placed inside an `AbsSdDataSheet`-extending component. Delegates all logic to the parent.
88
-
89
- ```typescript
90
- @Component({ selector: "sd-data-sheet" })
91
- class SdDataSheetControl {
92
- insertText = input<string>();
93
- deleteText = input<string>();
94
- restoreText = input<string>();
95
- deleteIcon = input(tablerEraser);
96
- restoreIcon = input(tablerRestore);
97
- }
98
- ```
99
-
100
- Content templates: `#pageTopbarTpl`, `#prevTpl`, `#filterTpl`, `#beforeToolTpl`, `#toolTpl`, `#modalBottomTpl`. Content children: `SdDataSheetColumnDirective`.
101
-
102
- ## `AbsSdDataSheet`
103
-
104
- Abstract base directive for data sheet screens. Manages state, change tracking, pagination, sorting, and CRUD.
105
-
106
- ```typescript
107
- @Directive()
108
- abstract class AbsSdDataSheet<TFilter, TItem, TKey> {
109
- // Abstract (must implement)
110
- abstract canUse: Signal<boolean>;
111
- abstract canEdit: Signal<boolean>;
112
- abstract editMode: "inline" | "modal" | undefined;
113
- abstract selectMode: InputSignal<"single" | "multi" | undefined>;
114
- abstract itemPropInfo: ISdDataSheetItemPropInfo<TItem>;
115
- abstract getItemInfoFn: (item: TItem) => ISdDataSheetItemInfo<TKey>;
116
- abstract bindFilter(): TFilter;
117
- abstract search(usePagination: boolean): Promise<ISdDataSheetSearchResult<TItem>> | ISdDataSheetSearchResult<TItem>;
118
-
119
- // Optional abstract
120
- hideTool?: Signal<boolean>;
121
- diffsExcludes?: string[];
122
- prepareRefreshEffect?(): void;
123
- editItem?(item?: TItem): Promise<boolean | undefined> | boolean | undefined;
124
- toggleDeleteItems?(del: boolean): Promise<boolean>;
125
- newItem?(): Promise<TItem> | TItem;
126
- submit?(diffs: ArrayOneWayDiffResult<TItem>[]): Promise<boolean> | boolean;
127
- downloadExcel?(items: TItem[]): Promise<void> | void;
128
- uploadExcel?(file: File): Promise<void> | void;
129
-
130
- // State
131
- busyCount = signal(0);
132
- busyMessage = signal<string | undefined>(undefined);
133
- initialized = signal(false);
134
- items = signal<TItem[]>([]);
135
- selectedItems = signal<TItem[]>([]);
136
- selectedItemKeys = model<TKey[]>([]);
137
- summaryData = signal<Partial<TItem>>({});
138
- page = signal(0);
139
- pageLength = signal(0);
140
- sortingDefs = signal<ISortingDef[]>([]);
141
- filter = signal<TFilter>({} as TFilter);
142
- lastFilter = signal<TFilter>({} as TFilter);
143
-
144
- // Output
145
- close = output<{ selectedItemKeys: TKey[]; selectedItems: TItem[] }>();
146
- submitted = output<boolean>();
147
-
148
- // Public methods
149
- checkIgnoreChanges(): boolean;
150
- doFilterSubmit(): void;
151
- doRefresh(): void;
152
- async refresh(): Promise<void>;
153
- async doAddItem(): Promise<void>;
154
- async doSubmit(opt?): Promise<void>;
155
- doToggleDeleteItem(item: TItem): void;
156
- async doEditItem(item?: TItem): Promise<void>;
157
- async doToggleDeleteItems(del: boolean): Promise<void>;
158
- async doDownloadExcel(): Promise<void>;
159
- async doUploadExcel(): Promise<void>;
160
- doModalConfirm(): void;
161
- doModalCancel(): void;
162
- }
163
- ```
164
-
165
- ## `ISdDataSheetItemPropInfo`
166
-
167
- Maps property names for metadata columns.
168
-
169
- ```typescript
170
- interface ISdDataSheetItemPropInfo<I> {
171
- isDeleted: (keyof I & string) | undefined;
172
- lastModifiedAt: (keyof I & string) | undefined;
173
- lastModifiedBy: (keyof I & string) | undefined;
174
- }
175
- ```
176
-
177
- | Field | Type | Description |
178
- |-------|------|-------------|
179
- | `isDeleted` | `(keyof I & string) \| undefined` | Property name for soft-delete flag |
180
- | `lastModifiedAt` | `(keyof I & string) \| undefined` | Property name for last modified timestamp |
181
- | `lastModifiedBy` | `(keyof I & string) \| undefined` | Property name for last modifier |
182
-
183
- ## `ISdDataSheetItemInfo`
184
-
185
- Per-item capability flags.
186
-
187
- ```typescript
188
- interface ISdDataSheetItemInfo<K> {
189
- key: K;
190
- canSelect: boolean;
191
- canEdit: boolean;
192
- canDelete: boolean;
193
- }
194
- ```
195
-
196
- | Field | Type | Description |
197
- |-------|------|-------------|
198
- | `key` | `K` | Item unique key |
199
- | `canSelect` | `boolean` | Whether item can be selected |
200
- | `canEdit` | `boolean` | Whether item can be edited |
201
- | `canDelete` | `boolean` | Whether item can be deleted |
202
-
203
- ## `ISdDataSheetSearchResult`
204
-
205
- Return shape of `AbsSdDataSheet.search()`.
206
-
207
- ```typescript
208
- interface ISdDataSheetSearchResult<I> {
209
- items: I[];
210
- pageLength?: number;
211
- summary?: Partial<I>;
212
- }
213
- ```
214
-
215
- | Field | Type | Description |
216
- |-------|------|-------------|
217
- | `items` | `I[]` | Result items |
218
- | `pageLength` | `number \| undefined` | Total page count for pagination |
219
- | `summary` | `Partial<I> \| undefined` | Optional summary row data |
220
-
221
- ## `SdDataSheetColumnDirective`
222
-
223
- Extends `SdSheetColumnDirective` with an additional `edit` input for modal edit mode.
224
-
225
- ```typescript
226
- @Directive({ selector: "sd-data-sheet-column" })
227
- class SdDataSheetColumnDirective extends SdSheetColumnDirective {
228
- edit = input(false, { transform: booleanAttribute });
229
- }
230
- ```
231
-
232
- ## `SdDataDetailControl`
233
-
234
- Presentation component for detail/form screens. Delegates logic to parent `AbsSdDataDetail`.
235
-
236
- ```typescript
237
- @Component({ selector: "sd-data-detail" })
238
- class SdDataDetailControl { }
239
- ```
240
-
241
- Content templates: `#contentTpl` (required), `#toolTpl`, `#prevTpl`, `#nextTpl`.
242
-
243
- ## `AbsSdDataDetail`
244
-
245
- Abstract base directive for detail (form) screens. Manages data load, change detection, save, and delete.
246
-
247
- ```typescript
248
- @Directive()
249
- abstract class AbsSdDataDetail<T, R = boolean> implements ISdModal<R> {
250
- // Abstract (must implement)
251
- abstract canUse: Signal<boolean>;
252
- abstract canEdit: Signal<boolean>;
253
- abstract load(): Promise<{ data: T; info: ISdDataDetailDataInfo }> | { data: T; info: ISdDataDetailDataInfo };
254
-
255
- // Optional abstract
256
- canDelete?: Signal<boolean>;
257
- prepareRefreshEffect?(): void;
258
- toggleDelete?(del: boolean): Promise<R | undefined> | R | undefined;
259
- submit?(data: T): Promise<R | undefined> | R | undefined;
260
-
261
- // State
262
- busyCount = signal(0);
263
- busyMessage = signal<string | undefined>(undefined);
264
- initialized = signal(false);
265
- data = signal<T>({} as T);
266
- dataInfo = signal<ISdDataDetailDataInfo | undefined>(undefined);
267
-
268
- // Output
269
- close = output<R>();
270
-
271
- // Public methods
272
- checkIgnoreChanges(): boolean;
273
- async doRefresh(): Promise<void>;
274
- async refresh(): Promise<void>;
275
- async doToggleDelete(del: boolean): Promise<void>;
276
- async doSubmit(opt?): Promise<void>;
277
- }
278
- ```
279
-
280
- ## `ISdDataDetailDataInfo`
281
-
282
- Metadata about the current detail record.
283
-
284
- ```typescript
285
- interface ISdDataDetailDataInfo {
286
- isNew: boolean;
287
- isDeleted: boolean;
288
- lastModifiedAt: DateTime | undefined;
289
- lastModifiedBy: string | undefined;
290
- }
291
- ```
292
-
293
- | Field | Type | Description |
294
- |-------|------|-------------|
295
- | `isNew` | `boolean` | Whether this is a new (unsaved) record |
296
- | `isDeleted` | `boolean` | Whether this record is soft-deleted |
297
- | `lastModifiedAt` | `DateTime \| undefined` | Last modification timestamp |
298
- | `lastModifiedBy` | `string \| undefined` | Last modifier identity |
299
-
300
- ## `SdDataSelectButtonControl`
301
-
302
- Presentation component for modal-backed select buttons. Delegates to parent `AbsSdDataSelectButton`.
303
-
304
- ```typescript
305
- @Component({ selector: "sd-data-select-button" })
306
- class SdDataSelectButtonControl { }
307
- ```
308
-
309
- Content template: `SdItemOfTemplateDirective` for rendering each selected item.
310
-
311
- ## `AbsSdDataSelectButton`
312
-
313
- Abstract base directive for select-button components backed by a modal.
314
-
315
- ```typescript
316
- @Directive()
317
- abstract class AbsSdDataSelectButton<TItem, TKey> {
318
- abstract modal: Signal<TSdSelectModalInfo<ISdSelectModal<TKey>>>;
319
- abstract load(keys: TKey[]): Promise<TItem[]> | TItem[];
320
-
321
- value = model<TSelectModeValue<TKey>>();
322
- disabled = input(false, { transform: booleanAttribute });
323
- required = input(false, { transform: booleanAttribute });
324
- inset = input(false, { transform: booleanAttribute });
325
- size = input<"sm" | "lg">();
326
- selectMode = input<"single" | "multi">("single");
327
-
328
- selectedItems = signal<TItem[]>([]);
329
- isNoValue = computed(/* true when value is null/empty */);
330
-
331
- async doShowModal(options?: ISdModalOptions): Promise<void>;
332
- doInitialValue(): void;
333
- }
334
- ```
335
-
336
- ## `SdSharedDataSelectControl`
337
-
338
- Dropdown select backed by shared data items. Supports single/multi selection, tree hierarchy, search, and modal selection.
339
-
340
- ```typescript
341
- @Component({ selector: "sd-shared-data-select" })
342
- class SdSharedDataSelectControl<TItem extends ISharedDataBase<string | number>> {
343
- value = model<TSelectModeValue<TItem["__valueKey"]>>();
344
- items = input.required<TItem[]>();
345
- disabled = input(false, { transform: booleanAttribute });
346
- required = input(false, { transform: booleanAttribute });
347
- useUndefined = input(false, { transform: booleanAttribute });
348
- inset = input(false, { transform: booleanAttribute });
349
- inline = input(false, { transform: booleanAttribute });
350
- size = input<"sm" | "lg">();
351
- selectMode = input<"single" | "multi">("single");
352
- filterFn = input<(item: TItem, index: number, ...params: any[]) => boolean>();
353
- filterFnParams = input<any[]>();
354
- modal = input<TSdSelectModalInfo<any>>();
355
- editModal = input<ISdModalInfo<ISdModal<boolean>>>();
356
- selectClass = input<string>();
357
- multiSelectionDisplayDirection = input<"vertical">();
358
- getIsHiddenFn = input<(item: TItem, index: number) => boolean>();
359
- getSearchTextFn = input<(item: TItem, index: number) => string>();
360
- displayOrderKeyProp = input<string>();
361
- }
362
- ```
363
-
364
- Content templates: `SdItemOfTemplateDirective`, `#undefinedTpl`.
365
-
366
- ## `SdSharedDataSelectButtonControl`
367
-
368
- Concrete `AbsSdDataSelectButton` for shared data with numeric keys.
369
-
370
- ```typescript
371
- @Component({ selector: "sd-shared-data-select-button" })
372
- class SdSharedDataSelectButtonControl<TItem extends ISharedDataBase<number>> extends AbsSdDataSelectButton<TItem, number> {
373
- items = input<TItem[]>([]);
374
- modal = input.required<TSdSelectModalInfo<ISdSelectModal<any>>>();
375
- }
376
- ```
377
-
378
- Content template: `SdItemOfTemplateDirective` (required).
379
-
380
- ## `SdSharedDataSelectListControl`
381
-
382
- List-style single-selection control for shared data. Supports search, pagination, and modal launch.
383
-
384
- ```typescript
385
- @Component({ selector: "sd-shared-data-select-list" })
386
- class SdSharedDataSelectListControl<TItem extends ISharedDataBase<string | number>> {
387
- selectedItem = model<TItem>();
388
- canChangeFn = input<(item: TItem | undefined) => boolean | Promise<boolean>>(() => true);
389
- items = input.required<TItem[]>();
390
- selectedIcon = input<string>();
391
- useUndefined = input(false, { transform: booleanAttribute });
392
- filterFn = input<(item: TItem, index: number) => boolean>();
393
- modal = input<TSdSelectModalInfo<any>>();
394
- header = input<string>();
395
- pageItemCount = input<number>();
396
-
397
- select(item: TItem | undefined): void;
398
- toggle(item: TItem | undefined): void;
399
- }
400
- ```
401
-
402
- Content templates: `#headerTpl`, `#filterTpl`, `SdItemOfTemplateDirective`, `#undefinedTpl`.
package/docs/styling.md DELETED
@@ -1,309 +0,0 @@
1
- # Styling
2
-
3
- CSS classes, custom properties, themes, and SCSS mixins provided by the `@simplysm/angular` package.
4
-
5
- ## CSS Classes
6
-
7
- ### Flex Layout
8
-
9
- | Class | Description |
10
- |-------|-------------|
11
- | `.flex-row` | `display: flex; flex-direction: row; flex-wrap: nowrap` |
12
- | `.flex-column` | `display: flex; flex-direction: column; flex-wrap: nowrap` |
13
- | `.flex-row-inline` | `display: inline-flex; flex-direction: row` |
14
- | `.flex-column-inline` | `display: inline-flex; flex-direction: column` |
15
- | `.flex-auto` | `flex: 1 0 auto` — grows but does not shrink |
16
- | `.flex-fill` | `flex: 1 1 auto; overflow: auto` — fills remaining space |
17
- | `.flex-min` | `flex: 0 0 0` — collapses to minimum |
18
-
19
- ### Grid Layout
20
-
21
- | Class | Description |
22
- |-------|-------------|
23
- | `.grid` | 12-column CSS grid |
24
- | `.grid-{1…12}` | Span N columns |
25
- | `.grid-sm-{1…12}` | Span N columns at ≤1280px |
26
- | `.grid-xs-{1…12}` | Span N columns at ≤1024px |
27
- | `.grid-xxs-{1…12}` | Span N columns at ≤800px |
28
-
29
- ### Card
30
-
31
- | Class | Description |
32
- |-------|-------------|
33
- | `.card` | Block with control-color background, border-radius, elevation 2 shadow, entrance animation. Elevation 4 on hover/focus-within |
34
-
35
- ### Font Size
36
-
37
- | Class | Description |
38
- |-------|-------------|
39
- | `.ft-size-{key}` | `font-size: var(--font-size-{key})` — keys: `lg`, `default`, `sm`, `h1`–`h6` |
40
-
41
- ### Background
42
-
43
- | Class | Description |
44
- |-------|-------------|
45
- | `.bg-theme-{theme}-{shade}` | Background from theme color. Themes: `gray`, `blue-gray`, `primary`, `secondary`, `info`, `success`, `warning`, `danger`. Shades: `lightest`–`darkest` |
46
- | `.bg-trans-{key}` | Translucent black background. Keys: `darkest`–`lightest`, `rev-default`–`rev-lightest` |
47
- | `.bg-default` | Background color set to `--background-color` |
48
- | `.bg-control` | Background set to `--control-color` |
49
-
50
- ### Text Color
51
-
52
- | Class | Description |
53
- |-------|-------------|
54
- | `.tx-trans-{key}` | Text color from `--text-trans-{key}`. Keys: `dark`, `default`, `light`, `lighter`, `lightest`, `rev-default`, `rev-dark`, `rev-darker` |
55
- | `.tx-theme-{theme}-{shade}` | Text color from theme palette |
56
- | `.tx-line-through` | `text-decoration: line-through` |
57
- | `.tx-underline` | `text-decoration: underline` |
58
- | `.tx-left` | `text-align: left` |
59
- | `.tx-right` | `text-align: right` |
60
- | `.tx-center` | `text-align: center` |
61
-
62
- ### Border
63
-
64
- | Class | Description |
65
- |-------|-------------|
66
- | `.bd` | `border: 1px solid` |
67
- | `.bd-theme-{theme}-{shade}` | Border color from theme palette |
68
- | `.bd-trans-{key}` | Border color from transparent scale |
69
- | `.bd-color-{key}` | Border color from semantic scale: `lighter`, `light`, `default`, `dark`, `darker` |
70
- | `.bd-none` | Removes border |
71
- | `.bd-transparent` | Transparent border-color |
72
- | `.bd{t\|r\|b\|l}` | Directional border (e.g., `.bdt`, `.bdr`, `.bdb`, `.bdl`) |
73
- | `.bd{t\|r\|b\|l}-theme-{theme}-{shade}` | Directional border color from theme |
74
- | `.bd{t\|r\|b\|l}-trans-{key}` | Directional border color from transparent scale |
75
- | `.bd{t\|r\|b\|l}-color-{key}` | Directional border color from semantic scale |
76
- | `.bd{t\|r\|b\|l}-none` | Removes directional border |
77
- | `.bd{t\|r\|b\|l}-transparent` | Transparent directional border |
78
-
79
- ### Border Width
80
-
81
- | Class | Description |
82
- |-------|-------------|
83
- | `.bd-width-{key}` | Border width from gap scale: `xxs`–`xxl`, `0`, `auto` |
84
- | `.bd{t\|r\|b\|l}-width-{key}` | Directional border width |
85
-
86
- ### Border Radius
87
-
88
- | Class | Description |
89
- |-------|-------------|
90
- | `.bd-radius-{key}` | `border-radius: var(--border-radius-{key})` — keys: `xs`–`xxl` |
91
- | `.bdt-radius-{key}` | Top-left + top-right radius |
92
- | `.bdb-radius-{key}` | Bottom-left + bottom-right radius |
93
- | `.bdl-radius-{key}` | Top-left + bottom-left radius |
94
- | `.bdr-radius-{key}` | Top-right + bottom-right radius |
95
-
96
- ### Spacing (Padding / Margin / Position)
97
-
98
- Gap keys: `xxs` (0.0833rem), `xs` (0.1667rem), `sm` (0.3333rem), `default` (0.5rem), `lg` (0.6667rem), `xl` (1rem), `xxl` (1.5rem), `0`, `auto`.
99
-
100
- | Class | Description |
101
- |-------|-------------|
102
- | `.p-{key}` | Padding all sides |
103
- | `.pv-{key}` | Padding top + bottom |
104
- | `.ph-{key}` | Padding left + right |
105
- | `.p{t\|r\|b\|l}-{key}` | Directional padding |
106
- | `.m-{key}` | Margin all sides |
107
- | `.mv-{key}` | Margin top + bottom |
108
- | `.mh-{key}` | Margin left + right |
109
- | `.m{t\|r\|b\|l}-{key}` | Directional margin |
110
- | `.{t\|r\|b\|l}-{key}` | Positional offset (top/right/bottom/left) |
111
-
112
- ### Sizing
113
-
114
- | Class | Description |
115
- |-------|-------------|
116
- | `.sw-{key}` | `width: var(--gap-{key})` |
117
- | `.sh-{key}` | `height: var(--gap-{key})` |
118
- | `.sh-topbar` | `height: var(--topbar-height)` |
119
- | `.sw-sidebar` | `width: var(--sidebar-width)` |
120
-
121
- ### Alignment
122
-
123
- | Class | Description |
124
- |-------|-------------|
125
- | `.main-align-{start\|end\|center}` | `justify-content` |
126
- | `.cross-align-{start\|end\|center}` | `align-items` |
127
- | `.gap-{key}` | `gap: var(--gap-{key})` |
128
-
129
- ### Form & Table
130
-
131
- | Class | Description |
132
- |-------|-------------|
133
- | `.form-control` | Base form input styling (padding, border, font) |
134
- | `.form-box` | Vertical flex form layout with labeled children |
135
- | `.form-box-inline` | Inline-flex row wrap form layout |
136
- | `.form-box-item` | Child item class for `.form-box` |
137
- | `.form-table` | CSS table-display layout for labeled form fields |
138
- | `.form-table-header` | Section heading inside `.form-table > th` |
139
- | `.table` | Standard bordered table |
140
- | `.table-inset` | Table variant without outer border |
141
- | `.table-inline` | Table variant with `width: auto` |
142
- | `.table-bd-v` | Vertical borders only |
143
- | `.table-bd-h` | Horizontal borders only |
144
-
145
- ### Misc Utilities
146
-
147
- | Class | Description |
148
- |-------|-------------|
149
- | `.fill` | `width: 100%; height: 100%; overflow: auto` |
150
- | `.help` | Dotted underline + `cursor: help` |
151
- | `.control-header` | Small gray label above a control |
152
- | `.page-header` | Small gray section heading with bottom margin |
153
- | `.sticky-top` | `position: sticky; top: 0; z-index: 1` |
154
- | `.overflow-auto` | `overflow: auto` |
155
- | `.position-relative` | `position: relative` |
156
- | `.nowrap` | `white-space: nowrap` |
157
-
158
- ## CSS Custom Properties
159
-
160
- ### Color Palette
161
-
162
- `--color-{name}` — Named colors from the palette: `red`, `orange`, `amber`, `yellow`, `lime`, `green`, `emerald`, `teal`, `cyan`, `sky`, `blue`, `indigo`, `violet`, `purple`, `fuchsia`, `pink`, `rose`, `slate`, `gray`, `zinc`, `neutral`, `stone`.
163
-
164
- ### Theme Colors
165
-
166
- `--theme-{group}-{shade}` — Groups: `gray`, `blue-gray`, `primary`, `secondary`, `info`, `success`, `warning`, `danger`. Shades: `lightest`, `lighter`, `light`, `default`, `dark`, `darker`, `darkest`.
167
-
168
- ### Transparency
169
-
170
- | Property | Light Mode | Dark Mode |
171
- |----------|-----------|-----------|
172
- | `--trans-darkest` | `rgba(0,0,0,0.5)` | `rgba(255,255,255,0.5)` |
173
- | `--trans-darker` | `rgba(0,0,0,0.4)` | `rgba(255,255,255,0.4)` |
174
- | `--trans-dark` | `rgba(0,0,0,0.3)` | `rgba(255,255,255,0.3)` |
175
- | `--trans-default` | `rgba(0,0,0,0.2)` | `rgba(255,255,255,0.2)` |
176
- | `--trans-light` | `rgba(0,0,0,0.1)` | `rgba(255,255,255,0.1)` |
177
- | `--trans-lighter` | `rgba(0,0,0,0.05)` | `rgba(255,255,255,0.03)` |
178
- | `--trans-lightest` | `rgba(0,0,0,0.03)` | `rgba(255,255,255,0.05)` |
179
- | `--trans-rev-default` | `rgba(255,255,255,0.1)` | `rgba(0,0,0,0.1)` |
180
- | `--trans-rev-light` | `rgba(255,255,255,0.2)` | `rgba(0,0,0,0.2)` |
181
- | `--trans-rev-lighter` | `rgba(255,255,255,0.3)` | `rgba(0,0,0,0.3)` |
182
- | `--trans-rev-lightest` | `rgba(255,255,255,0.4)` | `rgba(0,0,0,0.4)` |
183
-
184
- ### Text Transparency
185
-
186
- | Property | Light Mode | Dark Mode |
187
- |----------|-----------|-----------|
188
- | `--text-trans-dark` | `black` | `white` |
189
- | `--text-trans-default` | `rgba(0,0,0,0.87)` | `rgba(255,255,255,0.87)` |
190
- | `--text-trans-light` | `rgba(0,0,0,0.6)` | `rgba(255,255,255,0.6)` |
191
- | `--text-trans-lighter` | `rgba(0,0,0,0.38)` | `rgba(255,255,255,0.38)` |
192
- | `--text-trans-lightest` | `rgba(0,0,0,0.2)` | `rgba(255,255,255,0.2)` |
193
- | `--text-trans-rev-default` | `white` | `black` |
194
- | `--text-trans-rev-dark` | `rgba(255,255,255,0.7)` | `rgba(0,0,0,0.7)` |
195
- | `--text-trans-rev-darker` | `rgba(255,255,255,0.5)` | `rgba(0,0,0,0.5)` |
196
-
197
- ### Font Sizes
198
-
199
- | Property | Value |
200
- |----------|-------|
201
- | `--font-size-lg` | `1.1667rem` |
202
- | `--font-size-default` | `1rem` |
203
- | `--font-size-sm` | `0.9167rem` |
204
- | `--font-size-h1` | `2rem` |
205
- | `--font-size-h2` | `1.5rem` |
206
- | `--font-size-h3` | `1.3333rem` |
207
- | `--font-size-h4` | `1.1667rem` |
208
- | `--font-size-h5` | `1rem` |
209
- | `--font-size-h6` | `0.9167rem` |
210
-
211
- ### Gaps (Spacing Scale)
212
-
213
- | Property | Value |
214
- |----------|-------|
215
- | `--gap-xxs` | `0.0833rem` |
216
- | `--gap-xs` | `0.1667rem` |
217
- | `--gap-sm` | `0.3333rem` |
218
- | `--gap-default` | `0.5rem` |
219
- | `--gap-lg` | `0.6667rem` |
220
- | `--gap-xl` | `1rem` |
221
- | `--gap-xxl` | `1.5rem` |
222
-
223
- ### Border Colors
224
-
225
- | Property | Value |
226
- |----------|-------|
227
- | `--border-color-lighter` | `var(--theme-gray-lightest)` |
228
- | `--border-color-light` | `var(--theme-gray-lighter)` |
229
- | `--border-color-default` | `var(--theme-gray-light)` |
230
- | `--border-color-dark` | `var(--theme-gray-default)` |
231
- | `--border-color-darker` | `var(--theme-gray-dark)` |
232
-
233
- ### Border Radii
234
-
235
- | Property | Value |
236
- |----------|-------|
237
- | `--border-radius-xs` | `0.0833rem` |
238
- | `--border-radius-sm` | `0.1667rem` |
239
- | `--border-radius-default` | `0.3333rem` |
240
- | `--border-radius-lg` | `0.5rem` |
241
- | `--border-radius-xl` | `0.6667rem` |
242
- | `--border-radius-xxl` | `1rem` |
243
-
244
- ### Z-Index
245
-
246
- | Property | Value |
247
- |----------|-------|
248
- | `--z-index-toast` | `9999` |
249
- | `--z-index-busy` | `9998` |
250
- | `--z-index-dropdown` | `5000` |
251
- | `--z-index-modal` | `4000` |
252
- | `--z-index-sidebar` | `3000` |
253
-
254
- ### Miscellaneous
255
-
256
- | Property | Light Mode | Dark Mode |
257
- |----------|-----------|-----------|
258
- | `--line-height` | `1.5em` | — |
259
- | `--font-family` | `sans-serif` | — |
260
- | `--font-family-monospace` | `monospace` | — |
261
- | `--background-color` | `white` | `#000` |
262
- | `--background-rev-color` | `black` | `#fff` |
263
- | `--control-color` | `white` | `#000` |
264
- | `--busy-overlay-bg` | `rgba(255,255,255,0.6)` | `rgba(0,0,0,0.6)` |
265
- | `--animation-duration` | `0.2s` | — |
266
- | `--elevation-size` | `0.0833rem` | — |
267
- | `--sidebar-width` | `15em` | — |
268
- | `--topbar-height` | `3em` | — |
269
- | `--sheet-pv` | `var(--gap-xs)` | — |
270
- | `--sheet-ph` | `var(--gap-sm)` | — |
271
- | `--sheet-bg` | `var(--theme-gray-lightest)` | — |
272
-
273
- ## Themes
274
-
275
- ### `.sd-theme-dark`
276
-
277
- Overrides CSS custom properties for dark mode. Inverts `--trans-*`, `--text-trans-*`, `--theme-*` color maps, and sets `--background-color: #000`, `--control-color: #000`.
278
-
279
- Images are automatically inverted via `filter: invert(1) hue-rotate(180deg)`. Add `.no-invert` class to opt out.
280
-
281
- ## Mixins / Functions
282
-
283
- ### `writeVars($value, $prevKey)`
284
-
285
- Recursively walks a nested SASS map and emits each leaf as a CSS custom property `--{key}: {value}`.
286
-
287
- ### `elevation($value)`
288
-
289
- Generates a `box-shadow` declaration for material-style elevation. Negative values produce inset shadows.
290
-
291
- ### `form-control-base()`
292
-
293
- Emits base styles for form input controls (padding, border, font).
294
-
295
- ### `help()`
296
-
297
- Applies dotted underline and `cursor: help`.
298
-
299
- ### `flex-direction($direction, $defaultGap: null)`
300
-
301
- Sets `flex-direction` and optional `gap`. Includes fallback for browsers without flex gap support (Chrome 61+).
302
-
303
- ### `color-map($base, $offset: 0%)`
304
-
305
- Returns a 7-shade map (`lightest`–`darkest`) by scaling the lightness of a base color.
306
-
307
- ### `to-rgb($oklch-color)`
308
-
309
- Converts an OKLCH color value to RGB color space.