@makigamestudio/ui-ionic 0.8.0 → 0.9.0

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/README.md CHANGED
@@ -1,64 +1,707 @@
1
- # UiIonic
1
+ # @makigamestudio/ui-ionic
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.1.0.
3
+ Ionic 8 component implementations for the ui-core library. This package provides ready-to-use Angular 21 standalone components built with Ionic Framework.
4
4
 
5
- ## Code scaffolding
5
+ ## Features
6
6
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
7
+ - **Zoneless Change Detection** No zone.js dependency
8
+ - **Signal-Based Architecture** — Angular Signals for all reactivity
9
+ - **Standalone Components** — No NgModules required
10
+ - **Ionic 8 Integration** — Native Ionic components and styling
11
+ - **TypeScript Strict Mode** — Full type safety
12
+
13
+ ## Installation
8
14
 
9
15
  ```bash
10
- ng generate component component-name
16
+ npm install @makigamestudio/ui-ionic @makigamestudio/ui-core
11
17
  ```
12
18
 
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
19
+ ### Peer Dependencies
14
20
 
15
- ```bash
16
- ng generate --help
21
+ ```json
22
+ {
23
+ "@angular/core": "^21.0.0",
24
+ "@ionic/angular": "^8.0.0",
25
+ "@makigamestudio/ui-core": "^0.5.0"
26
+ }
17
27
  ```
18
28
 
19
- ## Building
29
+ ## Theming
20
30
 
21
- To build the library, run:
31
+ ### Quick Start
22
32
 
23
- ```bash
24
- ng build ui-ionic
33
+ Import the theme file in your global styles to get both CSS variables and component styles:
34
+
35
+ ```scss
36
+ // src/global.scss or src/styles.scss
37
+ @use '@makigamestudio/ui-ionic/theme.scss';
38
+
39
+ // Your custom overrides AFTER the import
40
+ :root {
41
+ --maki-spacing-md: 16px; // Override default spacing
42
+ }
43
+ ```
44
+
45
+ **Note:** Importing `theme.scss` automatically includes `global-styles.scss`, so you only need one import.
46
+
47
+ ### Theming Strategy
48
+
49
+ This library follows a **hybrid approach** for maximum flexibility:
50
+
51
+ 1. **Uses Ionic's color system** — All components use `--ion-color-*` variables (primary, secondary, success, etc.) so they automatically match your app's Ionic theme.
52
+
53
+ 2. **Defines custom design tokens** — Only for properties that Ionic doesn't provide: spacing, border radius, shadows, and typography.
54
+
55
+ This means when you change your Ionic theme colors, all ui-ionic components automatically adapt. No duplicate configuration needed!
56
+
57
+ ### Import Order
58
+
59
+ Always import the theme **before** your custom overrides:
60
+
61
+ ```scss
62
+ // ✅ CORRECT ORDER
63
+ @use '@makigamestudio/ui-ionic/theme.scss';
64
+
65
+ :root {
66
+ --maki-spacing-lg: 20px;
67
+ }
68
+
69
+ // ❌ WRONG ORDER (overrides won't work)
70
+ :root {
71
+ --maki-spacing-lg: 20px;
72
+ }
73
+ @use '@makigamestudio/ui-ionic/theme.scss'; // This resets your overrides!
74
+ ```
75
+
76
+ ### Available CSS Variables
77
+
78
+ All variables include fallback values for robustness.
79
+
80
+ #### Spacing Scale
81
+
82
+ ```css
83
+ --maki-spacing-xs: 4px;
84
+ --maki-spacing-sm: 8px;
85
+ --maki-spacing-md: 12px;
86
+ --maki-spacing-lg: 16px;
87
+ --maki-spacing-xl: 24px;
88
+ --maki-spacing-xxl: 32px;
89
+ ```
90
+
91
+ #### Border Radius Scale
92
+
93
+ ```css
94
+ --maki-radius-xs: 4px;
95
+ --maki-radius-sm: 8px;
96
+ --maki-radius-md: 12px;
97
+ --maki-radius-lg: 16px;
98
+ --maki-radius-xl: 24px;
99
+ --maki-radius-full: 9999px;
100
+ ```
101
+
102
+ #### Shadows
103
+
104
+ ```css
105
+ --maki-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
106
+ /* Dark mode: 0 2px 8px rgba(0, 0, 0, 0.3) */
107
+ ```
108
+
109
+ #### Typography - Font Sizes
110
+
111
+ ```css
112
+ --maki-font-size-xs: 0.75rem;
113
+ --maki-font-size-sm: 0.875rem;
114
+ --maki-font-size-md: 1rem;
115
+ --maki-font-size-lg: 1.125rem;
116
+ --maki-font-size-xl: 1.25rem;
117
+ --maki-font-size-xxl: 1.5rem;
118
+ --maki-font-size-xxxl: 2rem;
119
+ ```
120
+
121
+ #### Typography - Line Heights
122
+
123
+ ```css
124
+ --maki-line-height-tight: 1.25;
125
+ --maki-line-height-normal: 1.5;
126
+ --maki-line-height-relaxed: 1.75;
127
+ ```
128
+
129
+ #### Typography - Letter Spacing
130
+
131
+ ```css
132
+ --maki-letter-spacing-normal: 0;
133
+ --maki-letter-spacing-wide: 0.02em;
134
+ ```
135
+
136
+ ````
137
+
138
+ **Note:** Tooltip show/hide delays (250ms/200ms) are intentionally hardcoded in the service to maintain consistent UX and prevent consumers from setting extreme values that would break expected behavior.
139
+
140
+
141
+ **Z-Index Hierarchy:**
142
+
143
+ ```
144
+ Modal (10000) ← Highest layer (blocks everything)
145
+ ├─ Tooltip (9999) ← Above popovers, below modals
146
+ ├─ Popover (9000) ← Dropdowns and context menus
147
+ ├─ Sticky (1020) ← Sticky headers
148
+ └─ Dropdown (1000) ← Basic dropdowns
149
+ ```
150
+
151
+ This hierarchy ensures tooltips appear above popovers/dropdowns but below modal backdrops.
152
+
153
+ ### Customization Examples
154
+
155
+ #### Override Spacing
156
+
157
+ ```scss
158
+ @use '@makigamestudio/ui-ionic/theme.scss';
159
+
160
+ :root {
161
+ --maki-spacing-md: 16px; // Change medium spacing
162
+ --maki-spacing-lg: 24px; // Change large spacing
163
+ }
164
+ ```
165
+
166
+ #### Change Shadows
167
+
168
+ ```scss
169
+ @use '@makigamestudio/ui-ionic/theme.scss';
170
+
171
+ :root {
172
+ --maki-box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); // Stronger shadow
173
+ }
174
+ ```
175
+
176
+ #### Customize Border Radius
177
+
178
+ ```scss
179
+ @use '@makigamestudio/ui-ionic/theme.scss';
180
+
181
+ :root {
182
+ --maki-radius-sm: 12px; // Rounder tooltips and cards
183
+ }
184
+ ```
185
+
186
+ ### Shadow DOM and RTL Support
187
+
188
+ The library properly handles Ionic's Shadow DOM components and provides RTL (Right-to-Left) language support through CSS custom properties.
189
+
190
+ #### Styling Ionic Shadow DOM Components
191
+
192
+ Ionic components like `ion-button` use Shadow DOM, which prevents regular CSS from penetrating component boundaries. The library uses Ionic's exposed CSS custom properties (e.g., `--padding-start`, `--padding-end`) to style these components:
193
+
194
+ ```typescript
195
+ // button.component.ts
196
+ ion-button {
197
+ --padding-start: var(--maki-spacing-sm, 0.5rem); // Maps to Shadow DOM
198
+ --padding-end: var(--maki-spacing-sm, 0.5rem);
199
+ }
200
+ ```
201
+
202
+ **Why this pattern is correct:**
203
+
204
+ 1. **Shadow DOM Encapsulation**: Regular `padding` CSS won't work on `ion-button` — you must use Ionic's custom properties
205
+ 2. **Consistent Theming**: All spacing uses `--maki-*` tokens, ensuring layout themes affect Ionic components
206
+ 3. **RTL Support**: `--padding-start`/`--padding-end` automatically flip in RTL languages (unlike `padding-left`/`padding-right`)
207
+
208
+ **RTL Behavior:**
209
+
210
+ ```
211
+ LTR (English): --padding-start → left, --padding-end → right
212
+ RTL (Arabic): --padding-start → right, --padding-end → left
213
+ ```
214
+
215
+ ### Theming Architecture
216
+
217
+ The library follows a **hybrid theming approach** that cleanly separates UI-agnostic logic from CSS-specific implementation:
218
+
219
+ #### Separation of Concerns
220
+
221
+ **ui-core (UI-Agnostic):**
222
+
223
+ - ✅ Pure computational logic (position calculations, visibility rules)
224
+ - ✅ State management with signals
225
+ - ✅ Behavioral timing (show/close delays remain hardcoded: 250ms/200ms)
226
+ - ❌ No CSS, no DOM manipulation, no framework-specific code
227
+
228
+ **ui-ionic (Ionic-Specific):**
229
+
230
+ - ✅ CSS variables and theming
231
+ - ✅ DOM manipulation and rendering
232
+ - ✅ Ionic component integration
233
+ - ✅ CSS transitions and animations
234
+
235
+ #### Timing Strategy
236
+
237
+ The library uses a **hybrid timing approach**:
238
+
239
+ **Behavioral Delays (Service-Controlled):**
240
+
241
+ ```typescript
242
+ // ui-core/tooltip.service.ts - Hardcoded for consistent UX
243
+ getShowDelayMs(): number { return 250; } // Wait before showing tooltip
244
+ getCloseDelayMs(): number { return 200; } // Grace period before hiding
245
+ ```
246
+
247
+ These values are intentionally hardcoded to prevent consumers from setting extreme values (e.g., 5000ms) that would break expected tooltip behavior.
248
+
249
+ **CSS Timing (Theme-Controlled):**
250
+
251
+ ```scss
252
+ // ui-ionic/theme.scss - Themable for visual preferences
253
+ ```
254
+
255
+ These values can be customized per layout theme (compact uses faster transitions, comfortable uses slower).
256
+
257
+ **Why This Separation:**
258
+
259
+ - **Behavioral delays** define UX patterns (how long to wait before showing)
260
+ - **CSS timing** defines visual polish (how fast animations feel)
261
+ - Mixing these concerns would make layout themes accidentally break tooltip interaction patterns
262
+
263
+ ### Dark Mode Toggle
264
+
265
+ The library is **theme-agnostic** and works with both light and dark modes. Theme customization and dark mode implementation is the **consumer's responsibility**. The playground app demonstrates a complete dark theme implementation pattern.
266
+
267
+ #### 1. Create a Theme Toggle Service
268
+
269
+ Create a signal-based service to manage theme state:
270
+
271
+ ```typescript
272
+ // services/theme-toggle.service.ts
273
+ import { effect, inject, Injectable, Renderer2, RendererFactory2, signal } from '@angular/core';
274
+ import { DOCUMENT } from '@angular/common';
275
+
276
+ export type ThemeMode = 'light' | 'dark';
277
+
278
+ @Injectable({ providedIn: 'root' })
279
+ export class ThemeToggleService {
280
+ private readonly document = inject(DOCUMENT);
281
+ private readonly renderer: Renderer2;
282
+ private readonly storageKey = 'theme-mode';
283
+
284
+ private readonly _colorThemeMode = signal<ThemeMode>(this.getInitialColorTheme());
285
+ readonly mode = this._colorThemeMode.asReadonly();
286
+
287
+ constructor() {
288
+ const rendererFactory = inject(RendererFactory2);
289
+ this.renderer = rendererFactory.createRenderer(null, null);
290
+
291
+ // Apply initial theme class
292
+ this.applyThemeClass(this._colorThemeMode());
293
+
294
+ // Batch localStorage writes using effect
295
+ effect(() => {
296
+ const currentMode = this._colorThemeMode();
297
+ try {
298
+ localStorage.setItem(this.storageKey, currentMode);
299
+ } catch (error) {
300
+ console.error('Failed to persist theme:', error);
301
+ }
302
+ });
303
+ }
304
+
305
+ toggleColorTheme(): void {
306
+ this.setColorTheme(this._colorThemeMode() === 'light' ? 'dark' : 'light');
307
+ }
308
+
309
+ setColorTheme(mode: ThemeMode): void {
310
+ this._colorThemeMode.set(mode);
311
+ this.applyThemeClass(mode);
312
+ }
313
+
314
+ private getInitialColorTheme(): ThemeMode {
315
+ try {
316
+ const stored = localStorage.getItem(this.storageKey);
317
+ if (stored === 'light' || stored === 'dark') return stored;
318
+ } catch {}
319
+
320
+ // Fallback to prefers-color-scheme
321
+ if (this.document.defaultView?.matchMedia?.('(prefers-color-scheme: dark)').matches) {
322
+ return 'dark';
323
+ }
324
+ return 'light';
325
+ }
326
+
327
+ private applyThemeClass(mode: ThemeMode): void {
328
+ const body = this.document.body;
329
+ if (!body) return;
330
+
331
+ if (mode === 'dark') {
332
+ this.renderer.addClass(body, 'dark');
333
+ } else {
334
+ this.renderer.removeClass(body, 'dark');
335
+ }
336
+ }
337
+ }
338
+ ```
339
+
340
+ #### 2. Define Dark Theme Variables
341
+
342
+ Create a dark theme stylesheet with Ionic's recommended dark palette:
343
+
344
+ ```scss
345
+ // theme-dark.scss
346
+ body.dark {
347
+ // Ionic Core Colors (Dark Mode)
348
+ --ion-background-color: #121212;
349
+ --ion-text-color: #ffffff;
350
+
351
+ // Primary - Lighter for better contrast on dark backgrounds
352
+ --ion-color-primary: #428cff;
353
+ --ion-color-primary-contrast: #ffffff;
354
+
355
+ // Secondary
356
+ --ion-color-secondary: #50c8ff;
357
+ --ion-color-secondary-contrast: #ffffff;
358
+
359
+ // Success
360
+ --ion-color-success: #2fdf75;
361
+ --ion-color-success-contrast: #000000;
362
+
363
+ // Warning
364
+ --ion-color-warning: #ffd534;
365
+ --ion-color-warning-contrast: #000000;
366
+
367
+ // Danger
368
+ --ion-color-danger: #ff4961;
369
+ --ion-color-danger-contrast: #ffffff;
370
+
371
+ // Light - Inverted (becomes darker)
372
+ --ion-color-light: #222428;
373
+ --ion-color-light-contrast: #ffffff;
374
+
375
+ // Medium
376
+ --ion-color-medium: #989aa2;
377
+ --ion-color-medium-contrast: #000000;
378
+
379
+ // Dark - Inverted (becomes lighter)
380
+ --ion-color-dark: #f4f5f8;
381
+ --ion-color-dark-contrast: #000000;
382
+
383
+ // Maki Design Tokens
384
+ --maki-box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
385
+ }
386
+ ```
387
+
388
+ #### 3. Import Dark Theme
389
+
390
+ Add the dark theme import to your global styles:
391
+
392
+ ```scss
393
+ // styles.scss
394
+ @use '@makigamestudio/ui-ionic/theme.scss';
395
+ @use './theme-dark.scss'; // Your dark theme overrides
396
+ ```
397
+
398
+ #### 4. Add Theme Toggle UI
399
+
400
+ Use the theme service in your components:
401
+
402
+ ```typescript
403
+ import { computed, inject } from '@angular/core';
404
+ import { IonToggle } from '@ionic/angular/standalone';
405
+ import { ThemeToggleService } from './services/theme-toggle.service';
406
+
407
+ @Component({
408
+ imports: [IonToggle],
409
+ template: `
410
+ <ion-toggle
411
+ [checked]="isDark()"
412
+ (ionChange)="onThemeToggle($event)"
413
+ aria-label="Toggle dark mode"
414
+ />
415
+ `
416
+ })
417
+ export class MyComponent {
418
+ readonly themeService = inject(ThemeToggleService);
419
+ readonly isDark = computed(() => this.themeService.mode() === 'dark');
420
+
421
+ onThemeToggle(event: CustomEvent): void {
422
+ this.themeService.setColorTheme(event.detail.checked ? 'dark' : 'light');
423
+ }
424
+ }
425
+ ```
426
+
427
+ #### Key Points
428
+
429
+ - **CSS Variables Required**: Always use CSS variables in your components (e.g., `var(--ion-color-primary)`) so they adapt automatically to theme changes
430
+ - **Class-Based Theming**: The service applies/removes the `dark` class on `<body>` to trigger theme overrides
431
+ - **Persistence**: Theme preference is saved to `localStorage` and restored on app load
432
+ - **Fallback Support**: Automatically detects `prefers-color-scheme: dark` if no saved preference exists
433
+ - **Signal-Based**: Fully reactive using Angular signals for zoneless compatibility
434
+
435
+ For a complete working example, see the [playground app](../../projects/playground/src/app/home/home.page.ts) source code.
436
+
437
+ ### Layout Theme Toggle
438
+
439
+ In addition to color themes (light/dark), you can implement layout themes to adjust spacing, typography for different user preferences. The playground demonstrates three layout modes: **compact**, **default**, and **comfortable**.
440
+
441
+ #### Layout Theme Comparison
442
+
443
+ | Property | Compact | Default (Baseline) | Comfortable |
444
+ | ------------------ | ------- | ------------------ | ----------- |
445
+ | **Line Height** | | | |
446
+ | Tight | 1.2 | 1.25 | 1.4 |
447
+ | Normal | 1.3 | 1.5 | 1.75 |
448
+ | Relaxed | 1.5 | 1.75 | 2.0 |
449
+ | **Letter Spacing** | | | |
450
+ | Normal | 0 | 0 | 0 |
451
+ | Wide | 0.02em | 0.02em | 0.04em |
452
+
453
+
454
+ #### Layout Theme Options
455
+
456
+ - **Compact**: Reduced spacing (15-20% smaller), tighter line heights — ideal for information-dense interfaces or large screens
457
+ - **Default**: Standard spacing and typography (library baseline) — balanced for most use cases
458
+ - **Comfortable**: Increased spacing (20-25% larger), relaxed line heights, wider letter spacing — better accessibility and readability
459
+
460
+ #### 1. Create Layout Theme Stylesheets
461
+
462
+ Create separate SCSS files for each layout variant:
463
+
464
+ ```scss
465
+ // theme-layout-compact.scss
466
+ body.layout-compact {
467
+ // Reduced spacing (20% smaller)
468
+ --maki-spacing-xxs: 0.1rem;
469
+ --maki-spacing-xs: 0.2rem;
470
+ --maki-spacing-sm: 0.4rem;
471
+ --maki-spacing-md: 0.6rem;
472
+ --maki-spacing-lg: 0.8rem;
473
+ --maki-spacing-xl: 1.2rem;
474
+ --maki-spacing-xxl: 1.6rem;
475
+
476
+ // Tighter typography
477
+ --maki-font-size-xs: 0.6875rem;
478
+ --maki-font-size-sm: 0.8125rem;
479
+ --maki-font-size-md: 0.9375rem;
480
+ // ... other font sizes
481
+
482
+ // Smaller border radius
483
+ --maki-radius-xs: 0.2rem;
484
+ --maki-radius-sm: 0.375rem;
485
+ // ... other radius values
486
+ }
487
+
488
+ // theme-layout-comfortable.scss
489
+ body.layout-comfortable {
490
+ // Increased spacing (25% larger)
491
+ --maki-spacing-xxs: 0.15625rem;
492
+ --maki-spacing-xs: 0.3125rem;
493
+ --maki-spacing-sm: 0.625rem;
494
+ --maki-spacing-md: 0.9375rem;
495
+ --maki-spacing-lg: 1.25rem;
496
+ --maki-spacing-xl: 1.875rem;
497
+ --maki-spacing-xxl: 2.5rem;
498
+
499
+ // Larger typography for readability
500
+ --maki-font-size-xs: 0.8125rem;
501
+ --maki-font-size-sm: 0.9375rem;
502
+ --maki-font-size-md: 1.0625rem;
503
+ // ... other font sizes
504
+
505
+ // Larger border radius
506
+ --maki-radius-xs: 0.3125rem;
507
+ --maki-radius-sm: 0.625rem;
508
+ // ... other radius values
509
+ }
510
+ ```
511
+
512
+ #### 2. Update Theme Service
513
+
514
+ Extend your `ThemeToggleService` to manage layout modes:
515
+
516
+ ```typescript
517
+ export type LayoutMode = 'compact' | 'default' | 'comfortable';
518
+
519
+ @Injectable({ providedIn: 'root' })
520
+ export class ThemeToggleService {
521
+ private readonly layoutStorageKey = 'layout-mode';
522
+ private readonly _layoutThemeMode = signal<LayoutMode>(this.getInitialLayoutTheme());
523
+ readonly layoutThemeMode = this._layoutThemeMode.asReadonly();
524
+
525
+ constructor() {
526
+ // ... existing color theme setup
527
+
528
+ // Apply initial layout class
529
+ this.applyLayoutClass(this._layoutThemeMode());
530
+
531
+ // Batch layout localStorage writes
532
+ effect(() => {
533
+ const currentLayoutMode = this._layoutThemeMode();
534
+ try {
535
+ localStorage.setItem(this.layoutStorageKey, currentLayoutMode);
536
+ } catch (error) {
537
+ console.error('Failed to persist layout theme:', error);
538
+ }
539
+ });
540
+ }
541
+
542
+ setLayoutTheme(mode: LayoutMode): void {
543
+ this._layoutThemeMode.set(mode);
544
+ this.applyLayoutClass(mode);
545
+ }
546
+
547
+ private getInitialLayoutTheme(): LayoutMode {
548
+ try {
549
+ const stored = localStorage.getItem(this.layoutStorageKey);
550
+ if (stored === 'compact' || stored === 'default' || stored === 'comfortable') {
551
+ return stored;
552
+ }
553
+ } catch {}
554
+ return 'default';
555
+ }
556
+
557
+ private applyLayoutClass(mode: LayoutMode): void {
558
+ const body = this.document.body;
559
+ if (!body) return;
560
+
561
+ // Remove all layout classes
562
+ this.renderer.removeClass(body, 'layout-compact');
563
+ this.renderer.removeClass(body, 'layout-comfortable');
564
+
565
+ // Apply appropriate class (default has no class)
566
+ if (mode === 'compact') {
567
+ this.renderer.addClass(body, 'layout-compact');
568
+ } else if (mode === 'comfortable') {
569
+ this.renderer.addClass(body, 'layout-comfortable');
570
+ }
571
+ }
572
+ }
573
+ ```
574
+
575
+ #### 3. Import Layout Themes
576
+
577
+ Add layout theme imports to your global styles:
578
+
579
+ ```scss
580
+ // styles.scss
581
+ @use '@makigamestudio/ui-ionic/theme.scss';
582
+ @use './theme-dark.scss';
583
+ @use './theme-layout-compact.scss';
584
+ @use './theme-layout-comfortable.scss';
585
+ ```
586
+
587
+ #### 4. Add Layout Switcher UI
588
+
589
+ Use `ion-segment` for layout mode selection:
590
+
591
+ ```typescript
592
+ import { computed, inject } from '@angular/core';
593
+ import { IonSegment, IonSegmentButton, IonLabel } from '@ionic/angular/standalone';
594
+
595
+ @Component({
596
+ imports: [IonSegment, IonSegmentButton, IonLabel],
597
+ template: `
598
+ <ion-segment [value]="layoutThemeMode()" (ionChange)="onLayoutChange($event)">
599
+ <ion-segment-button value="compact">
600
+ <ion-label>Compact</ion-label>
601
+ </ion-segment-button>
602
+ <ion-segment-button value="default">
603
+ <ion-label>Default</ion-label>
604
+ </ion-segment-button>
605
+ <ion-segment-button value="comfortable">
606
+ <ion-label>Comfortable</ion-label>
607
+ </ion-segment-button>
608
+ </ion-segment>
609
+ `
610
+ })
611
+ export class MyComponent {
612
+ readonly themeService = inject(ThemeToggleService);
613
+ readonly layoutThemeMode = computed(() => this.themeService.layoutThemeMode());
614
+
615
+ onLayoutChange(event: CustomEvent): void {
616
+ const layout = event.detail.value as LayoutMode;
617
+ this.themeService.setLayoutTheme(layout);
618
+ }
619
+ }
620
+ ```
621
+
622
+ #### Key Points
623
+
624
+ - **Independent Themes**: Color and layout themes work independently — combine light/dark with any layout mode
625
+ - **Signal-Based**: Use `computed()` to derive component state from service signals for zoneless compatibility
626
+ - **Default Has No Class**: The `default` layout uses the base theme variables (no class applied)
627
+ - **Consistent Variable Names**: Layout themes only override `--maki-*` spacing, typography, and radius variables
628
+ - **Accessibility Friendly**: `comfortable` mode improves readability for users who need larger text
629
+
630
+ For complete examples including both color and layout themes, see the [playground app](../../projects/playground/src/app/home/home.page.ts) source code.
631
+
632
+ ## Components
633
+
634
+ ### ButtonComponent
635
+
636
+ Ionic button with loading state, icon support, and dropdown functionality.
637
+
638
+ ```typescript
639
+ import { ButtonComponent } from '@makigamestudio/ui-ionic';
640
+
641
+ // In your component
642
+ button: IonicActionButton = {
643
+ type: ActionButtonType.Button,
644
+ label: 'Save',
645
+ icon: 'save-outline',
646
+ color: 'primary',
647
+ fill: 'solid'
648
+ };
649
+ ```
650
+
651
+ ```html
652
+ <maki-button [button]="button" />
25
653
  ```
26
654
 
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
655
+ ### ActionButtonListComponent
28
656
 
29
- ### Publishing the Library
657
+ Popover list of action buttons.
658
+
659
+ ```typescript
660
+ import { ActionButtonListComponent } from '@makigamestudio/ui-ionic';
661
+
662
+ buttons: IonicActionButton[] = [
663
+ { type: ActionButtonType.Button, label: 'Edit', icon: 'create-outline' },
664
+ { type: ActionButtonType.Button, label: 'Delete', icon: 'trash-outline', color: 'danger' }
665
+ ];
666
+ ```
30
667
 
31
- Once the project is built, you can publish your library by following these steps:
668
+ ```html
669
+ <maki-action-button-list [buttons]="buttons" />
670
+ ```
32
671
 
33
- 1. Navigate to the `dist` directory:
672
+ ### MakiTooltipDirective
34
673
 
35
- ```bash
36
- cd dist/ui-ionic
37
- ```
674
+ Device-aware tooltips with Ionic color support.
38
675
 
39
- 2. Run the `npm publish` command to publish your library to the npm registry:
40
- ```bash
41
- npm publish
42
- ```
676
+ ```html
677
+ <button makiTooltip="Click to save" makiTooltipColor="primary">Save</button>
678
+ ```
43
679
 
44
- ## Running unit tests
680
+ ## Development
45
681
 
46
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
682
+ ### Building the Library
47
683
 
48
684
  ```bash
49
- ng test
685
+ npm run build:ionic
50
686
  ```
51
687
 
52
- ## Running end-to-end tests
688
+ ### Testing
689
+
690
+ ```bash
691
+ npm run test:ionic
692
+ ```
53
693
 
54
- For end-to-end (e2e) testing, run:
694
+ ### Watch Mode
55
695
 
56
696
  ```bash
57
- ng e2e
697
+ npm run watch:ionic
58
698
  ```
59
699
 
60
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
700
+ ## License
701
+
702
+ MIT
61
703
 
62
- ## Additional Resources
704
+ ## More Information
63
705
 
64
- For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
706
+ For detailed API documentation, examples, and architectural guidelines, see the [GitHub repository](https://github.com/gdor/ui-core).
707
+ ````