@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.
@@ -721,7 +721,7 @@ class ActionButtonListComponent {
721
721
  </ion-item>
722
722
  }
723
723
  </ion-list>
724
- `, isInline: true, styles: [":host{display:block}::ng-deep ion-popover::part(content){width:fit-content}ion-list{padding:0}ion-item{--padding-start: var(--maki-action-button-list-padding, 16px);--padding-end: var(--maki-action-button-list-padding, 16px);--min-height: var(--maki-action-button-list-item-height, 44px);cursor:pointer;width:100%}ion-item[disabled]{cursor:not-allowed}ion-label{white-space:nowrap}ion-icon{font-size:var(--maki-action-button-list-icon-size, 20px);margin-inline-end:var(--maki-action-button-list-icon-gap, 12px)}ion-spinner{width:var(--maki-action-button-list-icon-size, 20px);height:var(--maki-action-button-list-icon-size, 20px);margin-inline-end:var(--maki-action-button-list-icon-gap, 12px)}\n"], dependencies: [{ kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "directive", type: MakiTooltipDirective, selector: "[makiTooltip]", inputs: ["makiTooltip", "makiTooltipColor", "makiTooltipPosition", "makiTooltipContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
724
+ `, isInline: true, styles: [":host{display:block}::ng-deep ion-popover::part(content){width:fit-content}ion-list{padding:0}ion-item{--padding-start: var(--maki-spacing-lg, 1rem);--padding-end: var(--maki-spacing-lg, 1rem);cursor:pointer;width:100%}ion-item[disabled]{cursor:not-allowed}ion-label{white-space:nowrap;line-height:var(--maki-line-height-normal, 1.5)}ion-spinner,ion-icon{width:var(--maki-font-size-xl, 1.25rem);height:var(--maki-font-size-xl, 1.25rem);margin-inline-end:var(--maki-spacing-md, .75rem)}\n"], dependencies: [{ kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "directive", type: MakiTooltipDirective, selector: "[makiTooltip]", inputs: ["makiTooltip", "makiTooltipColor", "makiTooltipPosition", "makiTooltipContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
725
725
  }
726
726
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ActionButtonListComponent, decorators: [{
727
727
  type: Component,
@@ -753,7 +753,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
753
753
  </ion-item>
754
754
  }
755
755
  </ion-list>
756
- `, styles: [":host{display:block}::ng-deep ion-popover::part(content){width:fit-content}ion-list{padding:0}ion-item{--padding-start: var(--maki-action-button-list-padding, 16px);--padding-end: var(--maki-action-button-list-padding, 16px);--min-height: var(--maki-action-button-list-item-height, 44px);cursor:pointer;width:100%}ion-item[disabled]{cursor:not-allowed}ion-label{white-space:nowrap}ion-icon{font-size:var(--maki-action-button-list-icon-size, 20px);margin-inline-end:var(--maki-action-button-list-icon-gap, 12px)}ion-spinner{width:var(--maki-action-button-list-icon-size, 20px);height:var(--maki-action-button-list-icon-size, 20px);margin-inline-end:var(--maki-action-button-list-icon-gap, 12px)}\n"] }]
756
+ `, styles: [":host{display:block}::ng-deep ion-popover::part(content){width:fit-content}ion-list{padding:0}ion-item{--padding-start: var(--maki-spacing-lg, 1rem);--padding-end: var(--maki-spacing-lg, 1rem);cursor:pointer;width:100%}ion-item[disabled]{cursor:not-allowed}ion-label{white-space:nowrap;line-height:var(--maki-line-height-normal, 1.5)}ion-spinner,ion-icon{width:var(--maki-font-size-xl, 1.25rem);height:var(--maki-font-size-xl, 1.25rem);margin-inline-end:var(--maki-spacing-md, .75rem)}\n"] }]
757
757
  }], propDecorators: { buttons: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttons", required: false }] }], buttonSelect: [{ type: i0.Output, args: ["buttonSelect"] }] } });
758
758
 
759
759
  /**
@@ -950,12 +950,12 @@ class ButtonComponent {
950
950
  buttonsFromPopover: children,
951
951
  loadingChildIds: this.stateService.loadingChildIds
952
952
  },
953
- event,
954
- translucent: true,
955
- dismissOnSelect: true,
956
- side: 'bottom',
953
+ arrow: false,
957
954
  alignment,
958
- arrow: false
955
+ dismissOnSelect: true,
956
+ event,
957
+ showBackdrop: false,
958
+ side: 'bottom'
959
959
  });
960
960
  await popover.present();
961
961
  const { data, role } = await popover.onDidDismiss();
@@ -998,7 +998,7 @@ class ButtonComponent {
998
998
  <ion-icon name="chevron-down-outline" slot="end" class="dropdown-icon" />
999
999
  }
1000
1000
  </ion-button>
1001
- `, isInline: true, styles: ["ion-button{--padding-start: var(--maki-button-padding-start);--padding-end: var(--maki-button-padding-end);text-transform:none}ion-button.button-has-icon-only::part(native){padding:0}ion-spinner{width:var(--maki-button-spinner-size, 16px);height:var(--maki-button-spinner-size, 16px);margin:0 4px 0 0}.button-icon{font-size:var(--maki-button-icon-size, 16px);margin:0 4px 0 0}.button-icon[slot=icon-only]{margin:0}.dropdown-icon{font-size:var(--maki-button-dropdown-icon-size, 16px);margin-inline-start:var(--maki-button-dropdown-icon-gap, 4px)}\n"], dependencies: [{ kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "directive", type: MakiTooltipDirective, selector: "[makiTooltip]", inputs: ["makiTooltip", "makiTooltipColor", "makiTooltipPosition", "makiTooltipContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1001
+ `, isInline: true, styles: ["ion-button{--padding-start: var(--maki-spacing-sm, .5rem);--padding-end: var(--maki-spacing-sm, .5rem);text-transform:none;line-height:var(--maki-line-height-normal, 1.5)}ion-button.button-has-icon-only::part(native){padding:0}ion-spinner,.button-icon{width:var(--maki-spacing-lg, 1rem);height:var(--maki-spacing-lg, 1rem);margin:0 var(--maki-spacing-xs, .25rem) 0 0}.button-icon[slot=icon-only]{margin:0}.dropdown-icon{font-size:var(--maki-font-size-md, 1rem);margin-inline-start:var(--maki-spacing-xs, .25rem)}\n"], dependencies: [{ kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "directive", type: MakiTooltipDirective, selector: "[makiTooltip]", inputs: ["makiTooltip", "makiTooltipColor", "makiTooltipPosition", "makiTooltipContext"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1002
1002
  }
1003
1003
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: ButtonComponent, decorators: [{
1004
1004
  type: Component,
@@ -1028,7 +1028,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
1028
1028
  <ion-icon name="chevron-down-outline" slot="end" class="dropdown-icon" />
1029
1029
  }
1030
1030
  </ion-button>
1031
- `, styles: ["ion-button{--padding-start: var(--maki-button-padding-start);--padding-end: var(--maki-button-padding-end);text-transform:none}ion-button.button-has-icon-only::part(native){padding:0}ion-spinner{width:var(--maki-button-spinner-size, 16px);height:var(--maki-button-spinner-size, 16px);margin:0 4px 0 0}.button-icon{font-size:var(--maki-button-icon-size, 16px);margin:0 4px 0 0}.button-icon[slot=icon-only]{margin:0}.dropdown-icon{font-size:var(--maki-button-dropdown-icon-size, 16px);margin-inline-start:var(--maki-button-dropdown-icon-gap, 4px)}\n"] }]
1031
+ `, styles: ["ion-button{--padding-start: var(--maki-spacing-sm, .5rem);--padding-end: var(--maki-spacing-sm, .5rem);text-transform:none;line-height:var(--maki-line-height-normal, 1.5)}ion-button.button-has-icon-only::part(native){padding:0}ion-spinner,.button-icon{width:var(--maki-spacing-lg, 1rem);height:var(--maki-spacing-lg, 1rem);margin:0 var(--maki-spacing-xs, .25rem) 0 0}.button-icon[slot=icon-only]{margin:0}.dropdown-icon{font-size:var(--maki-font-size-md, 1rem);margin-inline-start:var(--maki-spacing-xs, .25rem)}\n"] }]
1032
1032
  }], ctorParameters: () => [], propDecorators: { button: [{ type: i0.Input, args: [{ isSignal: true, alias: "button", required: true }] }], buttonClick: [{ type: i0.Output, args: ["buttonClick"] }], childSelect: [{ type: i0.Output, args: ["childSelect"] }] } });
1033
1033
 
1034
1034
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"makigamestudio-ui-ionic.mjs","sources":["../../../projects/ui-ionic/src/lib/directives/maki-tooltip.directive.ts","../../../projects/ui-ionic/src/lib/directives/index.ts","../../../projects/ui-ionic/src/lib/components/action-button-list/action-button-list.component.ts","../../../projects/ui-ionic/src/lib/components/button/button.component.ts","../../../projects/ui-ionic/src/lib/components/index.ts","../../../projects/ui-ionic/src/public-api.ts","../../../projects/ui-ionic/src/makigamestudio-ui-ionic.ts"],"sourcesContent":["/**\n * @file Maki Tooltip Directive\n * @description Ionic implementation of tooltip directive using TooltipService.\n *\n * This directive provides accessible tooltips that adapt to device type and viewport constraints.\n * On desktop, tooltips appear on hover with a delay. On mobile, they appear on click (except for\n * interactive elements like buttons where they're suppressed to avoid interfering with click handlers).\n *\n * All positioning and visibility logic is delegated to TooltipService from ui-core,\n * while this directive handles Ionic-specific DOM manipulation and event handling.\n *\n * @example\n * ```typescript\n * // Simple string tooltip\n * <button makiTooltip=\"Save changes\">Save</button>\n *\n * // With custom color\n * <ion-button makiTooltip=\"Delete item\" makiTooltipColor=\"danger\">\n * <ion-icon name=\"trash\" />\n * </ion-button>\n *\n * // Template tooltip\n * <ng-template #customTooltip>\n * <strong>Custom</strong> content\n * </ng-template>\n * <div [makiTooltip]=\"customTooltip\">Hover me</div>\n * ```\n */\n\nimport {\n ApplicationRef,\n DestroyRef,\n Directive,\n ElementRef,\n EmbeddedViewRef,\n HostListener,\n OnDestroy,\n Renderer2,\n Signal,\n TemplateRef,\n effect,\n inject,\n input,\n isSignal\n} from '@angular/core';\nimport type { TooltipPlacement, TooltipSchedulerHandle } from '@makigamestudio/ui-core';\nimport {\n DeviceDetectionService,\n TooltipSchedulerService,\n TooltipService\n} from '@makigamestudio/ui-core';\nimport type { IonicColor } from '../types/ionic-color.type';\n\n/**\n * Attribute name added to elements with tooltip directive.\n * Useful for testing and debugging.\n */\nexport const TOOLTIP_ATTRIBUTE = 'maki-tooltip';\n\ntype TooltipTemplateContext = Readonly<Record<string, unknown>> & { readonly $implicit?: unknown };\n\n/**\n * Directive for displaying contextual tooltips with device-aware behavior.\n *\n * The directive automatically adapts its behavior based on device type:\n * - **Desktop**: Shows tooltip on hover after 500ms delay, hides on mouse leave\n * - **Mobile**: Shows/hides tooltip on click (suppressed for interactive elements)\n *\n * Tooltips are positioned intelligently to avoid viewport overflow, appearing\n * above or to the left of the element when necessary.\n *\n * @usageNotes\n *\n * ### Basic String Tooltip\n * ```html\n * <button makiTooltip=\"Click to save\">Save</button>\n * ```\n *\n * ### Colored Tooltip\n * ```html\n * <ion-button makiTooltip=\"Permanently delete\" makiTooltipColor=\"danger\">\n * Delete\n * </ion-button>\n * ```\n *\n * ### Template Tooltip\n * ```html\n * <ng-template #richTooltip>\n * <div class=\"custom-tooltip\">\n * <h4>Title</h4>\n * <p>Description</p>\n * </div>\n * </ng-template>\n * <div [makiTooltip]=\"richTooltip\">Hover for details</div>\n * ```\n *\n * ### Live Updates with Signals\n * ```html\n * <span [makiTooltip]=\"statusTooltip()\">Hover</span>\n * ```\n * ```typescript\n * readonly statusTooltip = signal('Status: Ready');\n *\n * // Tooltip updates live while open\n * this.statusTooltip.set('Status: Processing');\n * ```\n *\n * ### Mobile Behavior\n * On mobile devices, tooltips are suppressed for interactive elements\n * (button, ion-button, ion-select, a) to avoid interfering with their\n * primary click handlers.\n */\n@Directive({\n selector: '[makiTooltip]',\n standalone: true\n})\nexport class MakiTooltipDirective implements OnDestroy {\n // ============================================================================\n // Dependencies\n // ============================================================================\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly appRef = inject(ApplicationRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly tooltipService = inject(TooltipService);\n private readonly scheduler = inject(TooltipSchedulerService);\n private readonly deviceDetection = inject(DeviceDetectionService);\n\n // ============================================================================\n // Inputs\n // ============================================================================\n\n /**\n * Tooltip content - can be a string or a template reference.\n *\n * If the input is signal-driven, an open tooltip will update live\n * when the signal value changes.\n *\n * @example\n * ```html\n * <!-- String content -->\n * <button makiTooltip=\"Save changes\">Save</button>\n *\n * <!-- Template content -->\n * <ng-template #tooltip>Rich content</ng-template>\n * <div [makiTooltip]=\"tooltip\">Hover</div>\n * ```\n */\n readonly content = input.required<string | TemplateRef<unknown>>({ alias: 'makiTooltip' });\n\n /**\n * Optional color for the tooltip background.\n * Accepts Ionic color names or null for default styling.\n *\n * @example\n * ```html\n * <button makiTooltip=\"Delete\" makiTooltipColor=\"danger\">Delete</button>\n * ```\n */\n readonly color = input<IonicColor | null>(null, { alias: 'makiTooltipColor' });\n\n /**\n * Preferred tooltip placement. If provided, the directive will attempt to\n * position the tooltip on the specified side before falling back.\n */\n readonly position = input<TooltipPlacement | undefined>(undefined, {\n alias: 'makiTooltipPosition'\n });\n\n /**\n * Optional context object for TemplateRef tooltips.\n * Supports signal inputs so templates can react to changes.\n * Open tooltips update live as the context signal changes.\n *\n * The context is exposed as both named properties and `$implicit`.\n *\n * @example\n * ```html\n * <ng-template #tooltip let-title=\"title\" let-data>\n * <strong>{{ title }}</strong>\n * <span>{{ data?.title }}</span>\n * </ng-template>\n * <span [makiTooltip]=\"tooltip\" [makiTooltipContext]=\"{ title: 'Info' }\">Hover</span>\n * ```\n */\n readonly context = input<unknown>(undefined, { alias: 'makiTooltipContext' });\n\n // ============================================================================\n // Private State\n // ============================================================================\n\n /**\n * Reference to the tooltip DOM element.\n */\n private tooltip: HTMLElement | null = null;\n\n /**\n * Timeout handle for hover delay.\n */\n\n /**\n * Reference to the embedded view when using template content.\n */\n private viewRef: EmbeddedViewRef<unknown> | null = null;\n\n /**\n * Tracks the current template reference to detect swaps.\n */\n private currentTemplateRef: TemplateRef<unknown> | null = null;\n\n /**\n * Cleanup function for document touch listener.\n */\n private touchListenerCleanup: (() => void) | null = null;\n\n /**\n * Animation frame ID for tooltip follow loop.\n */\n private positionAnimationFrame: number | null = null;\n\n /**\n * Timeout handle for fade-out removal.\n */\n private fadeTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Scheduler handle for this directive instance (isolated timers).\n * */\n private readonly schedulerHandle: TooltipSchedulerHandle | null = null;\n\n /**\n * Indicates whether the directive has been destroyed.\n */\n private isDestroyed = false;\n\n /**\n * Latest resolved TemplateRef context.\n */\n private latestTemplateContext: TooltipTemplateContext = { $implicit: undefined };\n\n // ============================================================================\n // Constructor\n // ============================================================================\n\n constructor() {\n // Add custom attribute for identification\n this.el.nativeElement.setAttribute(TOOLTIP_ATTRIBUTE, 'true');\n\n effect(() => {\n this.latestTemplateContext = this.resolveTemplateContext();\n if (this.viewRef) {\n Object.assign(this.viewRef.context as Record<string, unknown>, this.latestTemplateContext);\n this.viewRef.detectChanges();\n this.positionTooltip();\n }\n });\n\n effect(() => {\n const contentValue = this.content();\n if (!this.tooltip) return;\n\n this.updateTooltipContent(contentValue);\n this.positionTooltip();\n });\n\n // Create isolated scheduler handle for this directive instance\n this.schedulerHandle = this.scheduler.createHandle(\n () => this.showTooltip(),\n () => this.hideTooltip()\n );\n\n // Cleanup on destroy\n this.destroyRef.onDestroy(() => {\n this.isDestroyed = true;\n this.schedulerHandle?.destroy();\n this.hideTooltip();\n });\n }\n\n // ============================================================================\n // Event Handlers\n // ============================================================================\n\n /**\n * Shows tooltip on mouse enter (desktop only).\n * Adds a 500ms delay to avoid showing tooltips during quick mouse movements.\n */\n\n @HostListener('mouseenter')\n protected onMouseEnter(): void {\n if (!this.canShowTooltip()) return;\n this.schedulerHandle?.onTriggerEnter();\n }\n\n @HostListener('mouseleave')\n protected onMouseLeave(): void {\n this.schedulerHandle?.onTriggerLeave();\n }\n\n /**\n * Toggles tooltip on click (all devices).\n * On mobile, skips interactive elements. On desktop, acts as a toggle.\n */\n @HostListener('click')\n protected onClick(): void {\n if (!this.canShowTooltip()) {\n this.hideTooltip();\n return;\n }\n // En mobile, activar touch state\n this.schedulerHandle?.onClick(this.deviceDetection.isMobile());\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Checks if tooltip can be shown using TooltipService logic.\n *\n * @returns `true` if tooltip can be shown, `false` otherwise\n */\n private canShowTooltip(): boolean {\n const elementTag = this.el.nativeElement.tagName.toLowerCase();\n const hasContent = !!this.content();\n return this.tooltipService.shouldShowTooltip(\n elementTag,\n this.deviceDetection.isMobile(),\n hasContent\n );\n }\n\n private resolveTemplateContext(): TooltipTemplateContext {\n const rawContext = this.context();\n const resolvedContext = this.unwrapSignal(rawContext);\n\n if (resolvedContext && typeof resolvedContext === 'object') {\n return {\n ...(resolvedContext as Record<string, unknown>),\n $implicit: resolvedContext\n };\n }\n\n return { $implicit: resolvedContext };\n }\n\n private unwrapSignal(value: unknown): unknown {\n if (isSignal(value)) {\n return (value as Signal<unknown>)();\n }\n return value;\n }\n\n /**\n * Clears the hover timeout if it exists.\n */\n\n /**\n * Creates and displays the tooltip element.\n *\n * The tooltip is created as a fixed-position element appended to the document body.\n * Content can be either plain text or a rendered template.\n */\n private showTooltip(): void {\n if (this.tooltip || !this.content()) return;\n\n // Create tooltip element\n this.tooltip = this.renderer.createElement('div');\n this.renderer.addClass(this.tooltip, 'maki-tooltip');\n\n if (!this.tooltip) return;\n\n // Ensure tooltip is not visible or interactive while we measure and position it\n this.tooltip.style.position = 'fixed';\n this.tooltip.style.top = '-9999px';\n this.tooltip.style.left = '-9999px';\n this.tooltip.style.visibility = 'hidden';\n this.tooltip.style.pointerEvents = 'none';\n this.tooltip.style.opacity = '0';\n this.tooltip.style.transition = `opacity ${this.tooltipService.getFadeDurationMs()}ms ease`;\n\n // Apply color attribute if specified\n const colorValue = this.color();\n if (colorValue) {\n this.renderer.setAttribute(this.tooltip, 'data-color', colorValue);\n }\n\n // Set content (template or string)\n const contentValue = this.content();\n this.updateTooltipContent(contentValue);\n\n // Append hidden tooltip to body so we can measure it without visual jump\n this.renderer.appendChild(document.body, this.tooltip);\n\n // If there was a pending fade removal, cancel it (we're re-showing)\n this.clearFadeTimeout();\n\n // Immediately position the tooltip while hidden to avoid a visual jump\n this.positionTooltip();\n\n // Reveal and make interactive with fade-in\n // Make visible before starting opacity animation so it's measured properly\n this.tooltip.style.visibility = 'visible';\n // Allow pointer events after showing\n this.tooltip.style.pointerEvents = 'auto';\n // Trigger fade-in\n // Force a reflow to ensure transition runs\n\n this.tooltip.getBoundingClientRect();\n this.tooltip.style.opacity = '1';\n\n // Añadir listeners para interacción (desktop y mobile)\n this.addTooltipInteractionListeners();\n\n // Start animation frame loop to follow trigger\n this.startTooltipFollowLoop();\n\n // Add document listeners on mobile\n if (this.deviceDetection.isMobile()) {\n this.addDocumentTouchListener();\n }\n }\n\n /**\n * Positions the tooltip using TooltipService calculations.\n */\n private positionTooltip(): void {\n if (!this.tooltip) return;\n\n const triggerRect = this.el.nativeElement.getBoundingClientRect();\n\n // Hide tooltip if element is not visible\n if (!this.tooltipService.isElementVisible(triggerRect)) {\n this.hideTooltip();\n return;\n }\n\n const tooltipRect = this.tooltip.getBoundingClientRect();\n\n // Calculate position using service\n const position = this.tooltipService.calculatePosition(\n triggerRect,\n tooltipRect,\n window.innerWidth,\n window.innerHeight,\n this.position()\n );\n\n // Apply position\n this.tooltip.style.position = 'fixed';\n this.tooltip.style.zIndex = '10000';\n this.tooltip.style.top = `${position.top}px`;\n this.tooltip.style.left = `${position.left}px`;\n }\n\n /**\n * Adds a document-level touch listener to hide tooltip on any touch outside.\n * Only used on mobile devices.\n */\n private addDocumentTouchListener(): void {\n this.removeDocumentTouchListener();\n\n this.touchListenerCleanup = this.renderer.listen('document', 'touchstart', (event: Event) => {\n if (!this.tooltip) return;\n\n // Allow touches inside the tooltip or the trigger element to keep it open\n const target = event.target as Node | null;\n if (target && (this.tooltip.contains(target) || this.el.nativeElement.contains(target))) {\n return;\n }\n\n // Any touch outside should hide the tooltip\n this.hideTooltip();\n });\n }\n\n /**\n * Removes the document-level touch listener.\n */\n private removeDocumentTouchListener(): void {\n if (this.touchListenerCleanup) {\n this.touchListenerCleanup();\n this.touchListenerCleanup = null;\n }\n }\n\n /**\n * Removes the tooltip from the DOM and cleans up resources.\n */\n private hideTooltip(): void {\n this.removeDocumentTouchListener();\n this.removeTooltipInteractionListeners();\n this.stopTooltipFollowLoop();\n\n // If there's no tooltip (already removed), nothing to do\n if (!this.tooltip) return;\n\n // Begin fade-out and removal\n this.tooltip.style.opacity = '0';\n this.tooltip.style.pointerEvents = 'none';\n\n // Schedule removal after fade duration.\n this.clearFadeTimeout();\n this.fadeTimeout = setTimeout(() => {\n if (this.tooltip) {\n // Avoid leaving the tooltip empty during the fade animation.\n if (this.viewRef) {\n if (!this.isDestroyed) {\n try {\n this.appRef.detachView(this.viewRef);\n } catch {\n // ignore detach errors\n }\n }\n try {\n this.viewRef.destroy();\n } catch {\n // ignore destroy errors\n }\n this.viewRef = null;\n this.currentTemplateRef = null;\n }\n\n this.renderer.removeChild(document.body, this.tooltip);\n this.tooltip = null;\n }\n this.fadeTimeout = null;\n }, this.tooltipService.getFadeDurationMs());\n }\n\n private clearFadeTimeout(): void {\n if (this.fadeTimeout) {\n clearTimeout(this.fadeTimeout);\n this.fadeTimeout = null;\n }\n }\n\n private updateTooltipContent(contentValue: string | TemplateRef<unknown>): void {\n if (!this.tooltip) return;\n\n if (contentValue instanceof TemplateRef) {\n this.updateTemplateContent(contentValue);\n return;\n }\n\n this.updateStringContent(contentValue);\n }\n\n private updateTemplateContent(template: TemplateRef<unknown>): void {\n if (!this.tooltip) return;\n\n const shouldRecreate = this.currentTemplateRef !== template || !this.viewRef;\n if (shouldRecreate) {\n this.clearTooltipContent();\n this.viewRef = template.createEmbeddedView(this.latestTemplateContext);\n // Avoid calling attachView after destroy; it can log NG0406 warnings.\n if (!this.isDestroyed) {\n this.appRef.attachView(this.viewRef);\n }\n this.viewRef.rootNodes.forEach(node => this.renderer.appendChild(this.tooltip!, node));\n this.currentTemplateRef = template;\n }\n }\n\n private updateStringContent(contentValue: string): void {\n if (!this.tooltip) return;\n\n if (this.viewRef || this.currentTemplateRef) {\n this.clearTooltipContent();\n }\n\n this.tooltip.textContent = contentValue;\n this.currentTemplateRef = null;\n }\n\n private clearTooltipContent(): void {\n if (!this.tooltip) return;\n\n if (this.viewRef) {\n if (!this.isDestroyed) {\n try {\n this.appRef.detachView(this.viewRef);\n } catch {\n // ignore detach errors\n }\n }\n\n try {\n this.viewRef.destroy();\n } catch {\n // ignore destroy errors\n }\n this.viewRef = null;\n }\n\n while (this.tooltip.firstChild) {\n this.renderer.removeChild(this.tooltip, this.tooltip.firstChild);\n }\n }\n\n /**\n * Añade listeners de interacción al tooltip para mantenerlo abierto mientras se interactúa.\n */\n private addTooltipInteractionListeners(): void {\n if (!this.tooltip) return;\n // Siempre elimina antes por si acaso (defensivo)\n this.removeTooltipInteractionListeners();\n // Desktop: mouseenter/mouseleave\n this.tooltip.addEventListener('mouseenter', this.onTooltipMouseEnter);\n this.tooltip.addEventListener('mouseleave', this.onTooltipMouseLeave);\n // Mobile: touchstart/touchend\n this.tooltip.addEventListener('touchstart', this.onTooltipTouchStart, { passive: true });\n this.tooltip.addEventListener('touchend', this.onTooltipTouchEnd, { passive: true });\n }\n\n /**\n * Elimina listeners de interacción del tooltip.\n */\n private removeTooltipInteractionListeners(): void {\n if (!this.tooltip) return;\n this.tooltip.removeEventListener('mouseenter', this.onTooltipMouseEnter);\n this.tooltip.removeEventListener('mouseleave', this.onTooltipMouseLeave);\n this.tooltip.removeEventListener('touchstart', this.onTooltipTouchStart);\n this.tooltip.removeEventListener('touchend', this.onTooltipTouchEnd);\n }\n\n /**\n * Handler: mouse entra en el tooltip (desktop).\n */\n private readonly onTooltipMouseEnter = (): void => {\n this.schedulerHandle?.onTooltipEnter();\n };\n\n /**\n * Handler: mouse sale del tooltip (desktop).\n */\n private readonly onTooltipMouseLeave = (): void => {\n this.schedulerHandle?.onTooltipLeave();\n };\n\n /**\n * Handler: touchstart en el tooltip (mobile).\n */\n private readonly onTooltipTouchStart = (): void => {\n this.schedulerHandle?.onTooltipTouchStart();\n };\n\n /**\n * Handler: touchend en el tooltip (mobile).\n */\n private readonly onTooltipTouchEnd = (): void => {\n this.schedulerHandle?.onTooltipTouchEnd();\n };\n\n /**\n * Starts a high-performance animation frame loop to keep the tooltip positioned with its trigger.\n */\n private startTooltipFollowLoop(): void {\n this.stopTooltipFollowLoop();\n const loop = (): void => {\n if (!this.tooltip) return;\n this.positionTooltip();\n this.positionAnimationFrame = requestAnimationFrame(loop);\n };\n this.positionAnimationFrame = requestAnimationFrame(loop);\n }\n\n /**\n * Stops the animation frame loop for tooltip positioning.\n */\n private stopTooltipFollowLoop(): void {\n if (this.positionAnimationFrame !== null) {\n cancelAnimationFrame(this.positionAnimationFrame);\n this.positionAnimationFrame = null;\n }\n }\n\n /**\n * Cleanup on directive destruction.\n */\n ngOnDestroy(): void {\n this.hideTooltip();\n }\n}\n","/**\n * @file Directives Barrel Export\n * @description Exports all directives from the ui-ionic library.\n */\n\nexport { MakiTooltipDirective } from './maki-tooltip.directive';\n","/**\n * @file Action Button List Component\n * @description Ionic implementation of action button list for popovers/dropdowns.\n *\n * This component is the Ionic-specific implementation that uses the shared\n * ActionButtonListService from @makigamestudio/ui-core for all business logic.\n * The component only handles:\n * - Ionic template rendering (ion-list, ion-item, ion-icon, ion-spinner)\n * - Ionic-specific popover dismissal via PopoverController\n *\n * All list logic, loading state checks, and button resolution is delegated\n * to the injected service, making the logic reusable for other UI libraries.\n */\n\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n input,\n output,\n signal,\n Signal\n} from '@angular/core';\nimport {\n IonIcon,\n IonItem,\n IonLabel,\n IonList,\n IonSpinner,\n PopoverController\n} from '@ionic/angular/standalone';\n\nimport { ActionButtonListService, ActionButtonType } from '@makigamestudio/ui-core';\nimport { MakiTooltipDirective } from '../../directives';\nimport { IonicActionButton } from '../../types/ionic-action-button.types';\n\n/**\n * Component that renders a list of action buttons for use in popovers/dropdowns.\n *\n * This component is designed to be used as the content of an `ion-popover`\n * created via `PopoverController`. When a button is selected, it dismisses\n * the popover and returns the selected button.\n *\n * @example\n * ```typescript\n * // Used internally by maki-button for dropdowns\n * // Can also be used standalone:\n * const popover = await popoverCtrl.create({\n * component: ActionButtonListComponent,\n * componentProps: { buttons: myButtons },\n * event: clickEvent\n * });\n * await popover.present();\n *\n * const { data } = await popover.onDidDismiss();\n * if (data) {\n * data.handler();\n * }\n * ```\n *\n * @usageNotes\n * ### Inputs\n * - `buttons` (required): Array of `IonicActionButton` objects to display\n *\n * ### Outputs\n * - `buttonSelect`: Emits the selected `IonicActionButton` when clicked\n */\n@Component({\n selector: 'maki-action-button-list',\n standalone: true,\n imports: [IonList, IonItem, IonIcon, IonLabel, IonSpinner, MakiTooltipDirective],\n providers: [ActionButtonListService],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <ion-list lines=\"none\">\n @for (button of buttonList(); track button.id) {\n <ion-item\n [button]=\"true\"\n [disabled]=\"!canSelectButton(button)\"\n [attr.aria-label]=\"button.ariaLabel\"\n [makiTooltip]=\"button.tooltip || ''\"\n [makiTooltipColor]=\"button.tooltipColor ?? null\"\n makiTooltipPosition=\"left\"\n [detail]=\"button.type === ActionButtonType.Dropdown\"\n (click)=\"onButtonClick(button)\"\n >\n @if (shouldShowSpinner(button)) {\n <ion-spinner slot=\"start\" name=\"crescent\" />\n } @else if (button.icon) {\n <ion-icon slot=\"start\" [color]=\"button.config?.color\" [name]=\"button.icon\" />\n }\n @if (button.label) {\n <ion-label [color]=\"button.config?.color\">{{ button.label }}</ion-label>\n }\n </ion-item>\n } @empty {\n <ion-item>\n <ion-label color=\"medium\">No actions available</ion-label>\n </ion-item>\n }\n </ion-list>\n `,\n styles: [\n `\n :host {\n display: block;\n }\n\n ::ng-deep ion-popover::part(content) {\n width: fit-content;\n }\n\n ion-list {\n padding: 0;\n }\n\n ion-item {\n --padding-start: var(--maki-action-button-list-padding, 16px);\n --padding-end: var(--maki-action-button-list-padding, 16px);\n\n --min-height: var(--maki-action-button-list-item-height, 44px);\n\n cursor: pointer;\n\n width: 100%;\n }\n\n ion-item[disabled] {\n cursor: not-allowed;\n }\n\n ion-label {\n white-space: nowrap;\n }\n\n ion-icon {\n font-size: var(--maki-action-button-list-icon-size, 20px);\n margin-inline-end: var(--maki-action-button-list-icon-gap, 12px);\n }\n\n ion-spinner {\n width: var(--maki-action-button-list-icon-size, 20px);\n height: var(--maki-action-button-list-icon-size, 20px);\n margin-inline-end: var(--maki-action-button-list-icon-gap, 12px);\n }\n `\n ]\n})\nexport class ActionButtonListComponent {\n /** Reference to ActionButtonType.Dropdown for template comparison. */\n protected readonly ActionButtonType = ActionButtonType;\n\n /** Ionic PopoverController for dismissing the popover when an item is selected. */\n private readonly popoverCtrl = inject(PopoverController, { optional: true });\n\n /** Service for list logic. */\n private readonly listService = inject(ActionButtonListService);\n\n /** Internal signal to store buttons passed via componentProps. */\n private readonly _buttonsFromProps = signal<readonly IonicActionButton[]>([]);\n\n /** Internal signal to store the Set of currently loading child button IDs. */\n private readonly _loadingChildIdsFromProps = signal<Signal<ReadonlySet<string>> | null>(null);\n\n /** The list of action buttons to display (when used via template binding). */\n readonly buttons = input<readonly IonicActionButton[]>([]);\n\n /** Emits when a button is selected from the list. */\n readonly buttonSelect = output<IonicActionButton>();\n\n /** Computed button list that works with both signal input and componentProps. */\n protected readonly buttonList = computed(\n () =>\n this.listService.resolveButtonList(\n this._buttonsFromProps(),\n this.buttons()\n ) as readonly IonicActionButton[]\n );\n\n /**\n * Setter to capture buttons passed via PopoverController.create({ componentProps }).\n * This is called when Ionic sets the property directly on the component instance.\n */\n set buttonsFromPopover(value: readonly IonicActionButton[]) {\n this._buttonsFromProps.set(value);\n }\n\n /**\n * Setter to capture loading child IDs signal passed via PopoverController.create({ componentProps }).\n */\n set loadingChildIds(value: Signal<ReadonlySet<string>>) {\n this._loadingChildIdsFromProps.set(value);\n }\n\n /** Checks if a button can be selected. */\n protected canSelectButton(button: IonicActionButton): boolean {\n const loadingChildIds = this._loadingChildIdsFromProps()?.() ?? new Set<string>();\n return this.listService.canSelectButton(button, loadingChildIds);\n }\n\n /** Checks if a button should show its loading spinner. */\n protected shouldShowSpinner(button: IonicActionButton): boolean {\n const loadingChildIds = this._loadingChildIdsFromProps()?.() ?? new Set<string>();\n return this.listService.shouldShowSpinner(button, loadingChildIds);\n }\n\n /**\n * Handles click on a button item.\n * Emits the selected button and dismisses the popover.\n *\n * @param button - The clicked action button\n */\n protected onButtonClick(button: IonicActionButton): void {\n const loadingChildIds = this._loadingChildIdsFromProps()?.() ?? new Set<string>();\n if (!this.listService.canSelectButton(button, loadingChildIds)) {\n return;\n }\n\n this.buttonSelect.emit(button);\n this.popoverCtrl?.dismiss(button, 'select');\n }\n}\n","/**\n * @file Button Component\n * @description Ionic implementation of a configurable button component.\n *\n * This component is the Ionic-specific implementation that uses the shared\n * button services from @makigamestudio/ui-core for all business logic.\n * The component only handles:\n * - Ionic template rendering (ion-button, ion-icon, ion-spinner)\n * - Ionic-specific popover creation via PopoverController\n *\n * All state management, display logic, and handler execution is delegated\n * to the injected services, making the logic reusable for other UI libraries.\n */\n\nimport { ChangeDetectionStrategy, Component, computed, inject, input, output } from '@angular/core';\nimport { IonButton, IonIcon, IonSpinner, PopoverController } from '@ionic/angular/standalone';\nimport { addIcons } from 'ionicons';\nimport { chevronDownOutline } from 'ionicons/icons';\n\nimport {\n ActionButtonType,\n ButtonDisplayService,\n ButtonHandlerService,\n ButtonStateService\n} from '@makigamestudio/ui-core';\n\nimport { MakiTooltipDirective } from '../../directives/maki-tooltip.directive';\nimport { IonicActionButton, IonicPopoverAlignment } from '../../types/ionic-action-button.types';\nimport { ActionButtonListComponent } from '../action-button-list/action-button-list.component';\n\n/**\n * A configurable button component that renders an `ion-button` based on\n * an `IonicActionButton` configuration object.\n *\n * Features:\n * - Two button types: Default and Dropdown\n * - Flexible display: icon-only, label-only, or icon+label (determined by properties)\n * - Automatic loading state management for async handlers\n * - Dropdown support via PopoverController with child actions\n * - Full Ionic button styling configuration (fill, size, color, shape, expand)\n * - Automatic chevron icon for dropdown buttons\n *\n * @example\n * ```html\n * <!-- Button with label and icon -->\n * <maki-button [button]=\"saveButton\" />\n *\n * <!-- Icon-only button (no label) -->\n * <maki-button [button]=\"iconButton\" />\n *\n * <!-- Label-only button (no icon) -->\n * <maki-button [button]=\"textButton\" />\n *\n * <!-- Dropdown button -->\n * <maki-button [button]=\"menuButton\" />\n *\n * <!-- Button with tooltip -->\n * <maki-button [button]=\"buttonWithTooltip\" />\n * ```\n *\n * @example\n * ```typescript\n * // In your component\n * import { ActionButtonType } from '@makigamestudio/ui-core';\n * import { IonicActionButton } from '@makigamestudio/ui-ionic';\n * import { TemplateRef, ViewChild } from '@angular/core';\n *\n * // Button with string tooltip\n * saveButton: IonicActionButton = {\n * id: 'save',\n * label: 'Save',\n * icon: 'save-outline',\n * type: ActionButtonType.Default,\n * tooltip: 'Save your changes',\n * config: { fill: 'solid', color: 'primary' },\n * handler: async () => {\n * await this.saveData();\n * }\n * };\n *\n * // Button with colored tooltip\n * deleteButton: IonicActionButton = {\n * id: 'delete',\n * icon: 'trash-outline',\n * type: ActionButtonType.Default,\n * tooltip: 'Permanently delete this item',\n * tooltipColor: 'danger',\n * config: { fill: 'clear', color: 'danger' },\n * handler: () => this.deleteItem()\n * };\n *\n * // Button with template tooltip\n * @ViewChild('richTooltip') richTooltipTemplate!: TemplateRef<unknown>;\n *\n * infoButton: IonicActionButton = {\n * id: 'info',\n * icon: 'information-circle-outline',\n * type: ActionButtonType.Default,\n * tooltip: this.richTooltipTemplate,\n * tooltipColor: 'primary',\n * handler: () => {}\n * };\n *\n * // IonicActionButton (strict typing for Ionic-specific config)\n * ionicButton: IonicActionButton = {\n * id: 'ionic',\n * label: 'Ionic Button',\n * type: ActionButtonType.Default,\n * handler: () => {},\n * config: {\n * fill: 'solid', // Type-checked: 'clear' | 'outline' | 'solid' | 'default'\n * size: 'large' // Type-checked: 'small' | 'default' | 'large'\n * }\n * };\n *\n * menuButton: IonicActionButton = {\n * id: 'menu',\n * label: 'Actions',\n * type: ActionButtonType.Dropdown,\n * handler: () => {},\n * children: [\n * { id: 'edit', label: 'Edit', icon: 'create-outline', type: ActionButtonType.Default, handler: () => this.edit() },\n * { id: 'delete', label: 'Delete', icon: 'trash-outline', type: ActionButtonType.Default, handler: () => this.delete() }\n * ]\n * };\n * ```\n *\n * @usageNotes\n * ### Inputs\n * - `button` (required): The `IonicActionButton` configuration object\n *\n * ### Outputs\n * - `buttonClick`: Emits the button configuration when clicked (for non-dropdown buttons)\n * - `childSelect`: Emits the selected child button (for dropdown buttons)\n *\n * ### Loading State\n * The component automatically manages loading state for async handlers.\n * When a handler returns a Promise, the button shows a spinner until it resolves/rejects.\n * You can also manually control loading via the `button.loading` property.\n *\n * ### Dropdown Behavior\n * For `ActionButtonType.Dropdown`, clicking the button opens an `ion-popover`\n * containing an `ActionButtonListComponent` with the child buttons.\n * When a child is selected, its handler is executed and `childSelect` is emitted.\n */\n@Component({\n selector: 'maki-button',\n standalone: true,\n imports: [IonButton, IonIcon, IonSpinner, MakiTooltipDirective],\n providers: [ButtonStateService, ButtonDisplayService, ButtonHandlerService],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <ion-button\n [fill]=\"button().config?.fill\"\n [size]=\"button().config?.size\"\n [color]=\"button().config?.color\"\n [shape]=\"button().config?.shape\"\n [expand]=\"button().config?.expand\"\n [strong]=\"button().config?.strong\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"button().ariaLabel\"\n [makiTooltip]=\"button().tooltip || ''\"\n [makiTooltipColor]=\"button().tooltipColor ?? null\"\n (click)=\"onClick($event)\"\n >\n @if (showLoadingSpinner()) {\n <ion-spinner [slot]=\"iconSlot()\" name=\"crescent\" />\n } @else if (button().icon) {\n <ion-icon [name]=\"button().icon\" [slot]=\"iconSlot()\" class=\"button-icon\" />\n }\n @if (showLabel()) {\n {{ button().label }}\n }\n @if (showDropdownIcon()) {\n <ion-icon name=\"chevron-down-outline\" slot=\"end\" class=\"dropdown-icon\" />\n }\n </ion-button>\n `,\n styles: [\n `\n ion-button {\n --padding-start: var(--maki-button-padding-start);\n --padding-end: var(--maki-button-padding-end);\n text-transform: none;\n }\n\n ion-button.button-has-icon-only::part(native) {\n padding: 0;\n }\n\n ion-spinner {\n width: var(--maki-button-spinner-size, 16px);\n height: var(--maki-button-spinner-size, 16px);\n margin: 0 4px 0 0;\n }\n\n .button-icon {\n font-size: var(--maki-button-icon-size, 16px);\n margin: 0 4px 0 0;\n }\n\n .button-icon[slot='icon-only'] {\n margin: 0;\n }\n\n .dropdown-icon {\n font-size: var(--maki-button-dropdown-icon-size, 16px);\n margin-inline-start: var(--maki-button-dropdown-icon-gap, 4px);\n }\n `\n ]\n})\nexport class ButtonComponent {\n /** Ionic PopoverController for dropdown popovers. */\n private readonly popoverCtrl = inject(PopoverController);\n\n /** Service for button state management. */\n private readonly stateService = inject(ButtonStateService);\n\n /** Service for button display logic. */\n private readonly displayService = inject(ButtonDisplayService);\n\n /** Service for handler execution. */\n private readonly handlerService = inject(ButtonHandlerService);\n\n /** The action button configuration. */\n readonly button = input.required<IonicActionButton>();\n\n /** Emits when the button is clicked (for non-dropdown buttons). */\n readonly buttonClick = output<IonicActionButton>();\n\n /** Emits when a child button is selected from a dropdown. */\n readonly childSelect = output<IonicActionButton>();\n\n /** Whether the button is in a loading state. */\n readonly isLoading = computed(() => this.stateService.isLoading(this.button()));\n\n /** Whether to display the loading spinner. */\n readonly showLoadingSpinner = computed(() => this.stateService.showLoadingSpinner(this.button()));\n\n /** Whether the button is disabled. */\n readonly isDisabled = computed(() => this.stateService.isDisabled(this.button()));\n\n /** The slot for the icon based on label presence (Ionic-specific). */\n readonly iconSlot = computed(() => (this.button().label ? 'start' : 'icon-only'));\n\n /** Whether to show the label text. */\n readonly showLabel = computed(() => this.displayService.shouldShowLabel(this.button()));\n\n /** Whether to show the dropdown chevron icon. */\n readonly showDropdownIcon = computed(() =>\n this.displayService.shouldShowDropdownIcon(this.button())\n );\n\n constructor() {\n addIcons({ chevronDownOutline });\n }\n\n /**\n * Handles button click events.\n * For dropdown buttons, opens a popover with child actions.\n * For other buttons, executes the handler with auto-loading management.\n *\n * @param event - The click event\n */\n protected async onClick(event: Event): Promise<void> {\n event.stopPropagation();\n\n const btn = this.button();\n\n if (this.isDisabled()) {\n return;\n }\n\n if (btn.type === ActionButtonType.Dropdown) {\n await this.openDropdown(event);\n } else {\n await this.handlerService.executeHandler(btn, loading =>\n this.stateService.setLoading(loading)\n );\n this.buttonClick.emit(btn);\n }\n }\n\n /**\n * Opens a dropdown popover with child action buttons.\n *\n * @param event - The triggering click event for popover positioning\n */\n private async openDropdown(event: Event): Promise<void> {\n const btn = this.button();\n const children = btn.children ?? [];\n\n const alignment = (btn.config?.dropdownAlignment ?? 'end') as IonicPopoverAlignment;\n const popover = await this.popoverCtrl.create({\n component: ActionButtonListComponent,\n componentProps: {\n buttonsFromPopover: children,\n loadingChildIds: this.stateService.loadingChildIds\n },\n event,\n translucent: true,\n dismissOnSelect: true,\n side: 'bottom',\n alignment,\n arrow: false\n });\n\n await popover.present();\n\n const { data, role } = await popover.onDidDismiss<IonicActionButton>();\n\n if (role === 'select' && data) {\n await this.handlerService.executeChildHandler(data, (childId, loading) => {\n if (loading) {\n this.stateService.addLoadingChild(childId);\n } else {\n this.stateService.removeLoadingChild(childId);\n }\n });\n this.childSelect.emit(data);\n }\n }\n}\n","/**\n * @file Components Barrel Export\n * @description Exports all Ionic components from ui-ionic.\n */\n\nexport { ActionButtonListComponent } from './action-button-list/action-button-list.component';\nexport { ButtonComponent } from './button/button.component';\n","/*\n * Public API Surface of @makigamestudio/ui-ionic\n *\n * This package provides Ionic-specific implementations of UI components\n * using the interfaces and services from @makigamestudio/ui-core.\n */\n\n// ============================================================================\n// Ionic-Specific Types\n// ============================================================================\n\nexport type {\n IonicActionButton,\n IonicActionButtonConfig,\n IonicButtonExpand,\n IonicButtonFill,\n IonicButtonShape,\n IonicButtonSize,\n IonicColor,\n IonicPopoverAlignment\n} from './lib/types';\n\n// ============================================================================\n// Ionic Components\n// ============================================================================\n\nexport { ActionButtonListComponent, ButtonComponent } from './lib/components';\n\n// ============================================================================\n// Ionic Directives\n// ============================================================================\n\nexport { MakiTooltipDirective } from './lib/directives';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"makigamestudio-ui-ionic.mjs","sources":["../../../projects/ui-ionic/src/lib/directives/maki-tooltip.directive.ts","../../../projects/ui-ionic/src/lib/directives/index.ts","../../../projects/ui-ionic/src/lib/components/action-button-list/action-button-list.component.ts","../../../projects/ui-ionic/src/lib/components/button/button.component.ts","../../../projects/ui-ionic/src/lib/components/index.ts","../../../projects/ui-ionic/src/public-api.ts","../../../projects/ui-ionic/src/makigamestudio-ui-ionic.ts"],"sourcesContent":["/**\n * @file Maki Tooltip Directive\n * @description Ionic implementation of tooltip directive using TooltipService.\n *\n * This directive provides accessible tooltips that adapt to device type and viewport constraints.\n * On desktop, tooltips appear on hover with a delay. On mobile, they appear on click (except for\n * interactive elements like buttons where they're suppressed to avoid interfering with click handlers).\n *\n * All positioning and visibility logic is delegated to TooltipService from ui-core,\n * while this directive handles Ionic-specific DOM manipulation and event handling.\n *\n * @example\n * ```typescript\n * // Simple string tooltip\n * <button makiTooltip=\"Save changes\">Save</button>\n *\n * // With custom color\n * <ion-button makiTooltip=\"Delete item\" makiTooltipColor=\"danger\">\n * <ion-icon name=\"trash\" />\n * </ion-button>\n *\n * // Template tooltip\n * <ng-template #customTooltip>\n * <strong>Custom</strong> content\n * </ng-template>\n * <div [makiTooltip]=\"customTooltip\">Hover me</div>\n * ```\n */\n\nimport {\n ApplicationRef,\n DestroyRef,\n Directive,\n ElementRef,\n EmbeddedViewRef,\n HostListener,\n OnDestroy,\n Renderer2,\n Signal,\n TemplateRef,\n effect,\n inject,\n input,\n isSignal\n} from '@angular/core';\nimport type { TooltipPlacement, TooltipSchedulerHandle } from '@makigamestudio/ui-core';\nimport {\n DeviceDetectionService,\n TooltipSchedulerService,\n TooltipService\n} from '@makigamestudio/ui-core';\nimport type { IonicColor } from '../types/ionic-color.type';\n\n/**\n * Attribute name added to elements with tooltip directive.\n * Useful for testing and debugging.\n */\nexport const TOOLTIP_ATTRIBUTE = 'maki-tooltip';\n\ntype TooltipTemplateContext = Readonly<Record<string, unknown>> & { readonly $implicit?: unknown };\n\n/**\n * Directive for displaying contextual tooltips with device-aware behavior.\n *\n * The directive automatically adapts its behavior based on device type:\n * - **Desktop**: Shows tooltip on hover after 500ms delay, hides on mouse leave\n * - **Mobile**: Shows/hides tooltip on click (suppressed for interactive elements)\n *\n * Tooltips are positioned intelligently to avoid viewport overflow, appearing\n * above or to the left of the element when necessary.\n *\n * @usageNotes\n *\n * ### Basic String Tooltip\n * ```html\n * <button makiTooltip=\"Click to save\">Save</button>\n * ```\n *\n * ### Colored Tooltip\n * ```html\n * <ion-button makiTooltip=\"Permanently delete\" makiTooltipColor=\"danger\">\n * Delete\n * </ion-button>\n * ```\n *\n * ### Template Tooltip\n * ```html\n * <ng-template #richTooltip>\n * <div class=\"custom-tooltip\">\n * <h4>Title</h4>\n * <p>Description</p>\n * </div>\n * </ng-template>\n * <div [makiTooltip]=\"richTooltip\">Hover for details</div>\n * ```\n *\n * ### Live Updates with Signals\n * ```html\n * <span [makiTooltip]=\"statusTooltip()\">Hover</span>\n * ```\n * ```typescript\n * readonly statusTooltip = signal('Status: Ready');\n *\n * // Tooltip updates live while open\n * this.statusTooltip.set('Status: Processing');\n * ```\n *\n * ### Mobile Behavior\n * On mobile devices, tooltips are suppressed for interactive elements\n * (button, ion-button, ion-select, a) to avoid interfering with their\n * primary click handlers.\n */\n@Directive({\n selector: '[makiTooltip]',\n standalone: true\n})\nexport class MakiTooltipDirective implements OnDestroy {\n // ============================================================================\n // Dependencies\n // ============================================================================\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly appRef = inject(ApplicationRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly tooltipService = inject(TooltipService);\n private readonly scheduler = inject(TooltipSchedulerService);\n private readonly deviceDetection = inject(DeviceDetectionService);\n\n // ============================================================================\n // Inputs\n // ============================================================================\n\n /**\n * Tooltip content - can be a string or a template reference.\n *\n * If the input is signal-driven, an open tooltip will update live\n * when the signal value changes.\n *\n * @example\n * ```html\n * <!-- String content -->\n * <button makiTooltip=\"Save changes\">Save</button>\n *\n * <!-- Template content -->\n * <ng-template #tooltip>Rich content</ng-template>\n * <div [makiTooltip]=\"tooltip\">Hover</div>\n * ```\n */\n readonly content = input.required<string | TemplateRef<unknown>>({ alias: 'makiTooltip' });\n\n /**\n * Optional color for the tooltip background.\n * Accepts Ionic color names or null for default styling.\n *\n * @example\n * ```html\n * <button makiTooltip=\"Delete\" makiTooltipColor=\"danger\">Delete</button>\n * ```\n */\n readonly color = input<IonicColor | null>(null, { alias: 'makiTooltipColor' });\n\n /**\n * Preferred tooltip placement. If provided, the directive will attempt to\n * position the tooltip on the specified side before falling back.\n */\n readonly position = input<TooltipPlacement | undefined>(undefined, {\n alias: 'makiTooltipPosition'\n });\n\n /**\n * Optional context object for TemplateRef tooltips.\n * Supports signal inputs so templates can react to changes.\n * Open tooltips update live as the context signal changes.\n *\n * The context is exposed as both named properties and `$implicit`.\n *\n * @example\n * ```html\n * <ng-template #tooltip let-title=\"title\" let-data>\n * <strong>{{ title }}</strong>\n * <span>{{ data?.title }}</span>\n * </ng-template>\n * <span [makiTooltip]=\"tooltip\" [makiTooltipContext]=\"{ title: 'Info' }\">Hover</span>\n * ```\n */\n readonly context = input<unknown>(undefined, { alias: 'makiTooltipContext' });\n\n // ============================================================================\n // Private State\n // ============================================================================\n\n /**\n * Reference to the tooltip DOM element.\n */\n private tooltip: HTMLElement | null = null;\n\n /**\n * Timeout handle for hover delay.\n */\n\n /**\n * Reference to the embedded view when using template content.\n */\n private viewRef: EmbeddedViewRef<unknown> | null = null;\n\n /**\n * Tracks the current template reference to detect swaps.\n */\n private currentTemplateRef: TemplateRef<unknown> | null = null;\n\n /**\n * Cleanup function for document touch listener.\n */\n private touchListenerCleanup: (() => void) | null = null;\n\n /**\n * Animation frame ID for tooltip follow loop.\n */\n private positionAnimationFrame: number | null = null;\n\n /**\n * Timeout handle for fade-out removal.\n */\n private fadeTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Scheduler handle for this directive instance (isolated timers).\n * */\n private readonly schedulerHandle: TooltipSchedulerHandle | null = null;\n\n /**\n * Indicates whether the directive has been destroyed.\n */\n private isDestroyed = false;\n\n /**\n * Latest resolved TemplateRef context.\n */\n private latestTemplateContext: TooltipTemplateContext = { $implicit: undefined };\n\n // ============================================================================\n // Constructor\n // ============================================================================\n\n constructor() {\n // Add custom attribute for identification\n this.el.nativeElement.setAttribute(TOOLTIP_ATTRIBUTE, 'true');\n\n effect(() => {\n this.latestTemplateContext = this.resolveTemplateContext();\n if (this.viewRef) {\n Object.assign(this.viewRef.context as Record<string, unknown>, this.latestTemplateContext);\n this.viewRef.detectChanges();\n this.positionTooltip();\n }\n });\n\n effect(() => {\n const contentValue = this.content();\n if (!this.tooltip) return;\n\n this.updateTooltipContent(contentValue);\n this.positionTooltip();\n });\n\n // Create isolated scheduler handle for this directive instance\n this.schedulerHandle = this.scheduler.createHandle(\n () => this.showTooltip(),\n () => this.hideTooltip()\n );\n\n // Cleanup on destroy\n this.destroyRef.onDestroy(() => {\n this.isDestroyed = true;\n this.schedulerHandle?.destroy();\n this.hideTooltip();\n });\n }\n\n // ============================================================================\n // Event Handlers\n // ============================================================================\n\n /**\n * Shows tooltip on mouse enter (desktop only).\n * Adds a 500ms delay to avoid showing tooltips during quick mouse movements.\n */\n\n @HostListener('mouseenter')\n protected onMouseEnter(): void {\n if (!this.canShowTooltip()) return;\n this.schedulerHandle?.onTriggerEnter();\n }\n\n @HostListener('mouseleave')\n protected onMouseLeave(): void {\n this.schedulerHandle?.onTriggerLeave();\n }\n\n /**\n * Toggles tooltip on click (all devices).\n * On mobile, skips interactive elements. On desktop, acts as a toggle.\n */\n @HostListener('click')\n protected onClick(): void {\n if (!this.canShowTooltip()) {\n this.hideTooltip();\n return;\n }\n // En mobile, activar touch state\n this.schedulerHandle?.onClick(this.deviceDetection.isMobile());\n }\n\n // ============================================================================\n // Private Methods\n // ============================================================================\n\n /**\n * Checks if tooltip can be shown using TooltipService logic.\n *\n * @returns `true` if tooltip can be shown, `false` otherwise\n */\n private canShowTooltip(): boolean {\n const elementTag = this.el.nativeElement.tagName.toLowerCase();\n const hasContent = !!this.content();\n return this.tooltipService.shouldShowTooltip(\n elementTag,\n this.deviceDetection.isMobile(),\n hasContent\n );\n }\n\n private resolveTemplateContext(): TooltipTemplateContext {\n const rawContext = this.context();\n const resolvedContext = this.unwrapSignal(rawContext);\n\n if (resolvedContext && typeof resolvedContext === 'object') {\n return {\n ...(resolvedContext as Record<string, unknown>),\n $implicit: resolvedContext\n };\n }\n\n return { $implicit: resolvedContext };\n }\n\n private unwrapSignal(value: unknown): unknown {\n if (isSignal(value)) {\n return (value as Signal<unknown>)();\n }\n return value;\n }\n\n /**\n * Clears the hover timeout if it exists.\n */\n\n /**\n * Creates and displays the tooltip element.\n *\n * The tooltip is created as a fixed-position element appended to the document body.\n * Content can be either plain text or a rendered template.\n */\n private showTooltip(): void {\n if (this.tooltip || !this.content()) return;\n\n // Create tooltip element\n this.tooltip = this.renderer.createElement('div');\n this.renderer.addClass(this.tooltip, 'maki-tooltip');\n\n if (!this.tooltip) return;\n\n // Ensure tooltip is not visible or interactive while we measure and position it\n this.tooltip.style.position = 'fixed';\n this.tooltip.style.top = '-9999px';\n this.tooltip.style.left = '-9999px';\n this.tooltip.style.visibility = 'hidden';\n this.tooltip.style.pointerEvents = 'none';\n this.tooltip.style.opacity = '0';\n this.tooltip.style.transition = `opacity ${this.tooltipService.getFadeDurationMs()}ms ease`;\n\n // Apply color attribute if specified\n const colorValue = this.color();\n if (colorValue) {\n this.renderer.setAttribute(this.tooltip, 'data-color', colorValue);\n }\n\n // Set content (template or string)\n const contentValue = this.content();\n this.updateTooltipContent(contentValue);\n\n // Append hidden tooltip to body so we can measure it without visual jump\n this.renderer.appendChild(document.body, this.tooltip);\n\n // If there was a pending fade removal, cancel it (we're re-showing)\n this.clearFadeTimeout();\n\n // Immediately position the tooltip while hidden to avoid a visual jump\n this.positionTooltip();\n\n // Reveal and make interactive with fade-in\n // Make visible before starting opacity animation so it's measured properly\n this.tooltip.style.visibility = 'visible';\n // Allow pointer events after showing\n this.tooltip.style.pointerEvents = 'auto';\n // Trigger fade-in\n // Force a reflow to ensure transition runs\n\n this.tooltip.getBoundingClientRect();\n this.tooltip.style.opacity = '1';\n\n // Añadir listeners para interacción (desktop y mobile)\n this.addTooltipInteractionListeners();\n\n // Start animation frame loop to follow trigger\n this.startTooltipFollowLoop();\n\n // Add document listeners on mobile\n if (this.deviceDetection.isMobile()) {\n this.addDocumentTouchListener();\n }\n }\n\n /**\n * Positions the tooltip using TooltipService calculations.\n */\n private positionTooltip(): void {\n if (!this.tooltip) return;\n\n const triggerRect = this.el.nativeElement.getBoundingClientRect();\n\n // Hide tooltip if element is not visible\n if (!this.tooltipService.isElementVisible(triggerRect)) {\n this.hideTooltip();\n return;\n }\n\n const tooltipRect = this.tooltip.getBoundingClientRect();\n\n // Calculate position using service\n const position = this.tooltipService.calculatePosition(\n triggerRect,\n tooltipRect,\n window.innerWidth,\n window.innerHeight,\n this.position()\n );\n\n // Apply position\n this.tooltip.style.position = 'fixed';\n this.tooltip.style.zIndex = '10000';\n this.tooltip.style.top = `${position.top}px`;\n this.tooltip.style.left = `${position.left}px`;\n }\n\n /**\n * Adds a document-level touch listener to hide tooltip on any touch outside.\n * Only used on mobile devices.\n */\n private addDocumentTouchListener(): void {\n this.removeDocumentTouchListener();\n\n this.touchListenerCleanup = this.renderer.listen('document', 'touchstart', (event: Event) => {\n if (!this.tooltip) return;\n\n // Allow touches inside the tooltip or the trigger element to keep it open\n const target = event.target as Node | null;\n if (target && (this.tooltip.contains(target) || this.el.nativeElement.contains(target))) {\n return;\n }\n\n // Any touch outside should hide the tooltip\n this.hideTooltip();\n });\n }\n\n /**\n * Removes the document-level touch listener.\n */\n private removeDocumentTouchListener(): void {\n if (this.touchListenerCleanup) {\n this.touchListenerCleanup();\n this.touchListenerCleanup = null;\n }\n }\n\n /**\n * Removes the tooltip from the DOM and cleans up resources.\n */\n private hideTooltip(): void {\n this.removeDocumentTouchListener();\n this.removeTooltipInteractionListeners();\n this.stopTooltipFollowLoop();\n\n // If there's no tooltip (already removed), nothing to do\n if (!this.tooltip) return;\n\n // Begin fade-out and removal\n this.tooltip.style.opacity = '0';\n this.tooltip.style.pointerEvents = 'none';\n\n // Schedule removal after fade duration.\n this.clearFadeTimeout();\n this.fadeTimeout = setTimeout(() => {\n if (this.tooltip) {\n // Avoid leaving the tooltip empty during the fade animation.\n if (this.viewRef) {\n if (!this.isDestroyed) {\n try {\n this.appRef.detachView(this.viewRef);\n } catch {\n // ignore detach errors\n }\n }\n try {\n this.viewRef.destroy();\n } catch {\n // ignore destroy errors\n }\n this.viewRef = null;\n this.currentTemplateRef = null;\n }\n\n this.renderer.removeChild(document.body, this.tooltip);\n this.tooltip = null;\n }\n this.fadeTimeout = null;\n }, this.tooltipService.getFadeDurationMs());\n }\n\n private clearFadeTimeout(): void {\n if (this.fadeTimeout) {\n clearTimeout(this.fadeTimeout);\n this.fadeTimeout = null;\n }\n }\n\n private updateTooltipContent(contentValue: string | TemplateRef<unknown>): void {\n if (!this.tooltip) return;\n\n if (contentValue instanceof TemplateRef) {\n this.updateTemplateContent(contentValue);\n return;\n }\n\n this.updateStringContent(contentValue);\n }\n\n private updateTemplateContent(template: TemplateRef<unknown>): void {\n if (!this.tooltip) return;\n\n const shouldRecreate = this.currentTemplateRef !== template || !this.viewRef;\n if (shouldRecreate) {\n this.clearTooltipContent();\n this.viewRef = template.createEmbeddedView(this.latestTemplateContext);\n // Avoid calling attachView after destroy; it can log NG0406 warnings.\n if (!this.isDestroyed) {\n this.appRef.attachView(this.viewRef);\n }\n this.viewRef.rootNodes.forEach(node => this.renderer.appendChild(this.tooltip!, node));\n this.currentTemplateRef = template;\n }\n }\n\n private updateStringContent(contentValue: string): void {\n if (!this.tooltip) return;\n\n if (this.viewRef || this.currentTemplateRef) {\n this.clearTooltipContent();\n }\n\n this.tooltip.textContent = contentValue;\n this.currentTemplateRef = null;\n }\n\n private clearTooltipContent(): void {\n if (!this.tooltip) return;\n\n if (this.viewRef) {\n if (!this.isDestroyed) {\n try {\n this.appRef.detachView(this.viewRef);\n } catch {\n // ignore detach errors\n }\n }\n\n try {\n this.viewRef.destroy();\n } catch {\n // ignore destroy errors\n }\n this.viewRef = null;\n }\n\n while (this.tooltip.firstChild) {\n this.renderer.removeChild(this.tooltip, this.tooltip.firstChild);\n }\n }\n\n /**\n * Añade listeners de interacción al tooltip para mantenerlo abierto mientras se interactúa.\n */\n private addTooltipInteractionListeners(): void {\n if (!this.tooltip) return;\n // Siempre elimina antes por si acaso (defensivo)\n this.removeTooltipInteractionListeners();\n // Desktop: mouseenter/mouseleave\n this.tooltip.addEventListener('mouseenter', this.onTooltipMouseEnter);\n this.tooltip.addEventListener('mouseleave', this.onTooltipMouseLeave);\n // Mobile: touchstart/touchend\n this.tooltip.addEventListener('touchstart', this.onTooltipTouchStart, { passive: true });\n this.tooltip.addEventListener('touchend', this.onTooltipTouchEnd, { passive: true });\n }\n\n /**\n * Elimina listeners de interacción del tooltip.\n */\n private removeTooltipInteractionListeners(): void {\n if (!this.tooltip) return;\n this.tooltip.removeEventListener('mouseenter', this.onTooltipMouseEnter);\n this.tooltip.removeEventListener('mouseleave', this.onTooltipMouseLeave);\n this.tooltip.removeEventListener('touchstart', this.onTooltipTouchStart);\n this.tooltip.removeEventListener('touchend', this.onTooltipTouchEnd);\n }\n\n /**\n * Handler: mouse entra en el tooltip (desktop).\n */\n private readonly onTooltipMouseEnter = (): void => {\n this.schedulerHandle?.onTooltipEnter();\n };\n\n /**\n * Handler: mouse sale del tooltip (desktop).\n */\n private readonly onTooltipMouseLeave = (): void => {\n this.schedulerHandle?.onTooltipLeave();\n };\n\n /**\n * Handler: touchstart en el tooltip (mobile).\n */\n private readonly onTooltipTouchStart = (): void => {\n this.schedulerHandle?.onTooltipTouchStart();\n };\n\n /**\n * Handler: touchend en el tooltip (mobile).\n */\n private readonly onTooltipTouchEnd = (): void => {\n this.schedulerHandle?.onTooltipTouchEnd();\n };\n\n /**\n * Starts a high-performance animation frame loop to keep the tooltip positioned with its trigger.\n */\n private startTooltipFollowLoop(): void {\n this.stopTooltipFollowLoop();\n const loop = (): void => {\n if (!this.tooltip) return;\n this.positionTooltip();\n this.positionAnimationFrame = requestAnimationFrame(loop);\n };\n this.positionAnimationFrame = requestAnimationFrame(loop);\n }\n\n /**\n * Stops the animation frame loop for tooltip positioning.\n */\n private stopTooltipFollowLoop(): void {\n if (this.positionAnimationFrame !== null) {\n cancelAnimationFrame(this.positionAnimationFrame);\n this.positionAnimationFrame = null;\n }\n }\n\n /**\n * Cleanup on directive destruction.\n */\n ngOnDestroy(): void {\n this.hideTooltip();\n }\n}\n","/**\n * @file Directives Barrel Export\n * @description Exports all directives from the ui-ionic library.\n */\n\nexport { MakiTooltipDirective } from './maki-tooltip.directive';\n","/**\n * @file Action Button List Component\n * @description Ionic implementation of action button list for popovers/dropdowns.\n *\n * This component is the Ionic-specific implementation that uses the shared\n * ActionButtonListService from @makigamestudio/ui-core for all business logic.\n * The component only handles:\n * - Ionic template rendering (ion-list, ion-item, ion-icon, ion-spinner)\n * - Ionic-specific popover dismissal via PopoverController\n *\n * All list logic, loading state checks, and button resolution is delegated\n * to the injected service, making the logic reusable for other UI libraries.\n */\n\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n inject,\n input,\n output,\n signal,\n Signal\n} from '@angular/core';\nimport {\n IonIcon,\n IonItem,\n IonLabel,\n IonList,\n IonSpinner,\n PopoverController\n} from '@ionic/angular/standalone';\n\nimport { ActionButtonListService, ActionButtonType } from '@makigamestudio/ui-core';\nimport { MakiTooltipDirective } from '../../directives';\nimport { IonicActionButton } from '../../types/ionic-action-button.types';\n\n/**\n * Component that renders a list of action buttons for use in popovers/dropdowns.\n *\n * This component is designed to be used as the content of an `ion-popover`\n * created via `PopoverController`. When a button is selected, it dismisses\n * the popover and returns the selected button.\n *\n * @example\n * ```typescript\n * // Used internally by maki-button for dropdowns\n * // Can also be used standalone:\n * const popover = await popoverCtrl.create({\n * component: ActionButtonListComponent,\n * componentProps: { buttons: myButtons },\n * event: clickEvent\n * });\n * await popover.present();\n *\n * const { data } = await popover.onDidDismiss();\n * if (data) {\n * data.handler();\n * }\n * ```\n *\n * @usageNotes\n * ### Inputs\n * - `buttons` (required): Array of `IonicActionButton` objects to display\n *\n * ### Outputs\n * - `buttonSelect`: Emits the selected `IonicActionButton` when clicked\n */\n@Component({\n selector: 'maki-action-button-list',\n standalone: true,\n imports: [IonList, IonItem, IonIcon, IonLabel, IonSpinner, MakiTooltipDirective],\n providers: [ActionButtonListService],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <ion-list lines=\"none\">\n @for (button of buttonList(); track button.id) {\n <ion-item\n [button]=\"true\"\n [disabled]=\"!canSelectButton(button)\"\n [attr.aria-label]=\"button.ariaLabel\"\n [makiTooltip]=\"button.tooltip || ''\"\n [makiTooltipColor]=\"button.tooltipColor ?? null\"\n makiTooltipPosition=\"left\"\n [detail]=\"button.type === ActionButtonType.Dropdown\"\n (click)=\"onButtonClick(button)\"\n >\n @if (shouldShowSpinner(button)) {\n <ion-spinner slot=\"start\" name=\"crescent\" />\n } @else if (button.icon) {\n <ion-icon slot=\"start\" [color]=\"button.config?.color\" [name]=\"button.icon\" />\n }\n @if (button.label) {\n <ion-label [color]=\"button.config?.color\">{{ button.label }}</ion-label>\n }\n </ion-item>\n } @empty {\n <ion-item>\n <ion-label color=\"medium\">No actions available</ion-label>\n </ion-item>\n }\n </ion-list>\n `,\n styles: [\n `\n :host {\n display: block;\n }\n\n ::ng-deep ion-popover::part(content) {\n width: fit-content;\n }\n\n ion-list {\n padding: 0;\n }\n\n ion-item {\n --padding-start: var(--maki-spacing-lg, 1rem);\n --padding-end: var(--maki-spacing-lg, 1rem);\n\n cursor: pointer;\n\n width: 100%;\n }\n\n ion-item[disabled] {\n cursor: not-allowed;\n }\n\n ion-label {\n white-space: nowrap;\n line-height: var(--maki-line-height-normal, 1.5);\n }\n\n ion-spinner,\n ion-icon {\n width: var(--maki-font-size-xl, 1.25rem);\n height: var(--maki-font-size-xl, 1.25rem);\n margin-inline-end: var(--maki-spacing-md, 0.75rem);\n }\n `\n ]\n})\nexport class ActionButtonListComponent {\n /** Reference to ActionButtonType.Dropdown for template comparison. */\n protected readonly ActionButtonType = ActionButtonType;\n\n /** Ionic PopoverController for dismissing the popover when an item is selected. */\n private readonly popoverCtrl = inject(PopoverController, { optional: true });\n\n /** Service for list logic. */\n private readonly listService = inject(ActionButtonListService);\n\n /** Internal signal to store buttons passed via componentProps. */\n private readonly _buttonsFromProps = signal<readonly IonicActionButton[]>([]);\n\n /** Internal signal to store the Set of currently loading child button IDs. */\n private readonly _loadingChildIdsFromProps = signal<Signal<ReadonlySet<string>> | null>(null);\n\n /** The list of action buttons to display (when used via template binding). */\n readonly buttons = input<readonly IonicActionButton[]>([]);\n\n /** Emits when a button is selected from the list. */\n readonly buttonSelect = output<IonicActionButton>();\n\n /** Computed button list that works with both signal input and componentProps. */\n protected readonly buttonList = computed(\n () =>\n this.listService.resolveButtonList(\n this._buttonsFromProps(),\n this.buttons()\n ) as readonly IonicActionButton[]\n );\n\n /**\n * Setter to capture buttons passed via PopoverController.create({ componentProps }).\n * This is called when Ionic sets the property directly on the component instance.\n */\n set buttonsFromPopover(value: readonly IonicActionButton[]) {\n this._buttonsFromProps.set(value);\n }\n\n /**\n * Setter to capture loading child IDs signal passed via PopoverController.create({ componentProps }).\n */\n set loadingChildIds(value: Signal<ReadonlySet<string>>) {\n this._loadingChildIdsFromProps.set(value);\n }\n\n /** Checks if a button can be selected. */\n protected canSelectButton(button: IonicActionButton): boolean {\n const loadingChildIds = this._loadingChildIdsFromProps()?.() ?? new Set<string>();\n return this.listService.canSelectButton(button, loadingChildIds);\n }\n\n /** Checks if a button should show its loading spinner. */\n protected shouldShowSpinner(button: IonicActionButton): boolean {\n const loadingChildIds = this._loadingChildIdsFromProps()?.() ?? new Set<string>();\n return this.listService.shouldShowSpinner(button, loadingChildIds);\n }\n\n /**\n * Handles click on a button item.\n * Emits the selected button and dismisses the popover.\n *\n * @param button - The clicked action button\n */\n protected onButtonClick(button: IonicActionButton): void {\n const loadingChildIds = this._loadingChildIdsFromProps()?.() ?? new Set<string>();\n if (!this.listService.canSelectButton(button, loadingChildIds)) {\n return;\n }\n\n this.buttonSelect.emit(button);\n this.popoverCtrl?.dismiss(button, 'select');\n }\n}\n","/**\n * @file Button Component\n * @description Ionic implementation of a configurable button component.\n *\n * This component is the Ionic-specific implementation that uses the shared\n * button services from @makigamestudio/ui-core for all business logic.\n * The component only handles:\n * - Ionic template rendering (ion-button, ion-icon, ion-spinner)\n * - Ionic-specific popover creation via PopoverController\n *\n * All state management, display logic, and handler execution is delegated\n * to the injected services, making the logic reusable for other UI libraries.\n */\n\nimport { ChangeDetectionStrategy, Component, computed, inject, input, output } from '@angular/core';\nimport { IonButton, IonIcon, IonSpinner, PopoverController } from '@ionic/angular/standalone';\nimport { addIcons } from 'ionicons';\nimport { chevronDownOutline } from 'ionicons/icons';\n\nimport {\n ActionButtonType,\n ButtonDisplayService,\n ButtonHandlerService,\n ButtonStateService\n} from '@makigamestudio/ui-core';\n\nimport { MakiTooltipDirective } from '../../directives/maki-tooltip.directive';\nimport { IonicActionButton, IonicPopoverAlignment } from '../../types/ionic-action-button.types';\nimport { ActionButtonListComponent } from '../action-button-list/action-button-list.component';\n\n/**\n * A configurable button component that renders an `ion-button` based on\n * an `IonicActionButton` configuration object.\n *\n * Features:\n * - Two button types: Default and Dropdown\n * - Flexible display: icon-only, label-only, or icon+label (determined by properties)\n * - Automatic loading state management for async handlers\n * - Dropdown support via PopoverController with child actions\n * - Full Ionic button styling configuration (fill, size, color, shape, expand)\n * - Automatic chevron icon for dropdown buttons\n *\n * @example\n * ```html\n * <!-- Button with label and icon -->\n * <maki-button [button]=\"saveButton\" />\n *\n * <!-- Icon-only button (no label) -->\n * <maki-button [button]=\"iconButton\" />\n *\n * <!-- Label-only button (no icon) -->\n * <maki-button [button]=\"textButton\" />\n *\n * <!-- Dropdown button -->\n * <maki-button [button]=\"menuButton\" />\n *\n * <!-- Button with tooltip -->\n * <maki-button [button]=\"buttonWithTooltip\" />\n * ```\n *\n * @example\n * ```typescript\n * // In your component\n * import { ActionButtonType } from '@makigamestudio/ui-core';\n * import { IonicActionButton } from '@makigamestudio/ui-ionic';\n * import { TemplateRef, ViewChild } from '@angular/core';\n *\n * // Button with string tooltip\n * saveButton: IonicActionButton = {\n * id: 'save',\n * label: 'Save',\n * icon: 'save-outline',\n * type: ActionButtonType.Default,\n * tooltip: 'Save your changes',\n * config: { fill: 'solid', color: 'primary' },\n * handler: async () => {\n * await this.saveData();\n * }\n * };\n *\n * // Button with colored tooltip\n * deleteButton: IonicActionButton = {\n * id: 'delete',\n * icon: 'trash-outline',\n * type: ActionButtonType.Default,\n * tooltip: 'Permanently delete this item',\n * tooltipColor: 'danger',\n * config: { fill: 'clear', color: 'danger' },\n * handler: () => this.deleteItem()\n * };\n *\n * // Button with template tooltip\n * @ViewChild('richTooltip') richTooltipTemplate!: TemplateRef<unknown>;\n *\n * infoButton: IonicActionButton = {\n * id: 'info',\n * icon: 'information-circle-outline',\n * type: ActionButtonType.Default,\n * tooltip: this.richTooltipTemplate,\n * tooltipColor: 'primary',\n * handler: () => {}\n * };\n *\n * // IonicActionButton (strict typing for Ionic-specific config)\n * ionicButton: IonicActionButton = {\n * id: 'ionic',\n * label: 'Ionic Button',\n * type: ActionButtonType.Default,\n * handler: () => {},\n * config: {\n * fill: 'solid', // Type-checked: 'clear' | 'outline' | 'solid' | 'default'\n * size: 'large' // Type-checked: 'small' | 'default' | 'large'\n * }\n * };\n *\n * menuButton: IonicActionButton = {\n * id: 'menu',\n * label: 'Actions',\n * type: ActionButtonType.Dropdown,\n * handler: () => {},\n * children: [\n * { id: 'edit', label: 'Edit', icon: 'create-outline', type: ActionButtonType.Default, handler: () => this.edit() },\n * { id: 'delete', label: 'Delete', icon: 'trash-outline', type: ActionButtonType.Default, handler: () => this.delete() }\n * ]\n * };\n * ```\n *\n * @usageNotes\n * ### Inputs\n * - `button` (required): The `IonicActionButton` configuration object\n *\n * ### Outputs\n * - `buttonClick`: Emits the button configuration when clicked (for non-dropdown buttons)\n * - `childSelect`: Emits the selected child button (for dropdown buttons)\n *\n * ### Loading State\n * The component automatically manages loading state for async handlers.\n * When a handler returns a Promise, the button shows a spinner until it resolves/rejects.\n * You can also manually control loading via the `button.loading` property.\n *\n * ### Dropdown Behavior\n * For `ActionButtonType.Dropdown`, clicking the button opens an `ion-popover`\n * containing an `ActionButtonListComponent` with the child buttons.\n * When a child is selected, its handler is executed and `childSelect` is emitted.\n */\n@Component({\n selector: 'maki-button',\n standalone: true,\n imports: [IonButton, IonIcon, IonSpinner, MakiTooltipDirective],\n providers: [ButtonStateService, ButtonDisplayService, ButtonHandlerService],\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <ion-button\n [fill]=\"button().config?.fill\"\n [size]=\"button().config?.size\"\n [color]=\"button().config?.color\"\n [shape]=\"button().config?.shape\"\n [expand]=\"button().config?.expand\"\n [strong]=\"button().config?.strong\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"button().ariaLabel\"\n [makiTooltip]=\"button().tooltip || ''\"\n [makiTooltipColor]=\"button().tooltipColor ?? null\"\n (click)=\"onClick($event)\"\n >\n @if (showLoadingSpinner()) {\n <ion-spinner [slot]=\"iconSlot()\" name=\"crescent\" />\n } @else if (button().icon) {\n <ion-icon [name]=\"button().icon\" [slot]=\"iconSlot()\" class=\"button-icon\" />\n }\n @if (showLabel()) {\n {{ button().label }}\n }\n @if (showDropdownIcon()) {\n <ion-icon name=\"chevron-down-outline\" slot=\"end\" class=\"dropdown-icon\" />\n }\n </ion-button>\n `,\n styles: [\n `\n ion-button {\n --padding-start: var(--maki-spacing-sm, 0.5rem);\n --padding-end: var(--maki-spacing-sm, 0.5rem);\n text-transform: none;\n line-height: var(--maki-line-height-normal, 1.5);\n }\n\n ion-button.button-has-icon-only::part(native) {\n padding: 0;\n }\n\n ion-spinner,\n .button-icon {\n width: var(--maki-spacing-lg, 1rem);\n height: var(--maki-spacing-lg, 1rem);\n margin: 0 var(--maki-spacing-xs, 0.25rem) 0 0;\n }\n\n .button-icon[slot='icon-only'] {\n margin: 0;\n }\n\n .dropdown-icon {\n font-size: var(--maki-font-size-md, 1rem);\n margin-inline-start: var(--maki-spacing-xs, 0.25rem);\n }\n `\n ]\n})\nexport class ButtonComponent {\n /** Ionic PopoverController for dropdown popovers. */\n private readonly popoverCtrl = inject(PopoverController);\n\n /** Service for button state management. */\n private readonly stateService = inject(ButtonStateService);\n\n /** Service for button display logic. */\n private readonly displayService = inject(ButtonDisplayService);\n\n /** Service for handler execution. */\n private readonly handlerService = inject(ButtonHandlerService);\n\n /** The action button configuration. */\n readonly button = input.required<IonicActionButton>();\n\n /** Emits when the button is clicked (for non-dropdown buttons). */\n readonly buttonClick = output<IonicActionButton>();\n\n /** Emits when a child button is selected from a dropdown. */\n readonly childSelect = output<IonicActionButton>();\n\n /** Whether the button is in a loading state. */\n readonly isLoading = computed(() => this.stateService.isLoading(this.button()));\n\n /** Whether to display the loading spinner. */\n readonly showLoadingSpinner = computed(() => this.stateService.showLoadingSpinner(this.button()));\n\n /** Whether the button is disabled. */\n readonly isDisabled = computed(() => this.stateService.isDisabled(this.button()));\n\n /** The slot for the icon based on label presence (Ionic-specific). */\n readonly iconSlot = computed(() => (this.button().label ? 'start' : 'icon-only'));\n\n /** Whether to show the label text. */\n readonly showLabel = computed(() => this.displayService.shouldShowLabel(this.button()));\n\n /** Whether to show the dropdown chevron icon. */\n readonly showDropdownIcon = computed(() =>\n this.displayService.shouldShowDropdownIcon(this.button())\n );\n\n constructor() {\n addIcons({ chevronDownOutline });\n }\n\n /**\n * Handles button click events.\n * For dropdown buttons, opens a popover with child actions.\n * For other buttons, executes the handler with auto-loading management.\n *\n * @param event - The click event\n */\n protected async onClick(event: Event): Promise<void> {\n event.stopPropagation();\n\n const btn = this.button();\n\n if (this.isDisabled()) {\n return;\n }\n\n if (btn.type === ActionButtonType.Dropdown) {\n await this.openDropdown(event);\n } else {\n await this.handlerService.executeHandler(btn, loading =>\n this.stateService.setLoading(loading)\n );\n this.buttonClick.emit(btn);\n }\n }\n\n /**\n * Opens a dropdown popover with child action buttons.\n *\n * @param event - The triggering click event for popover positioning\n */\n private async openDropdown(event: Event): Promise<void> {\n const btn = this.button();\n const children = btn.children ?? [];\n\n const alignment = (btn.config?.dropdownAlignment ?? 'end') as IonicPopoverAlignment;\n const popover = await this.popoverCtrl.create({\n component: ActionButtonListComponent,\n componentProps: {\n buttonsFromPopover: children,\n loadingChildIds: this.stateService.loadingChildIds\n },\n arrow: false,\n alignment,\n dismissOnSelect: true,\n event,\n showBackdrop: false,\n side: 'bottom'\n });\n\n await popover.present();\n\n const { data, role } = await popover.onDidDismiss<IonicActionButton>();\n\n if (role === 'select' && data) {\n await this.handlerService.executeChildHandler(data, (childId, loading) => {\n if (loading) {\n this.stateService.addLoadingChild(childId);\n } else {\n this.stateService.removeLoadingChild(childId);\n }\n });\n this.childSelect.emit(data);\n }\n }\n}\n","/**\n * @file Components Barrel Export\n * @description Exports all Ionic components from ui-ionic.\n */\n\nexport { ActionButtonListComponent } from './action-button-list/action-button-list.component';\nexport { ButtonComponent } from './button/button.component';\n","/*\n * Public API Surface of @makigamestudio/ui-ionic\n *\n * This package provides Ionic-specific implementations of UI components\n * using the interfaces and services from @makigamestudio/ui-core.\n */\n\n// ============================================================================\n// Ionic-Specific Types\n// ============================================================================\n\nexport type {\n IonicActionButton,\n IonicActionButtonConfig,\n IonicButtonExpand,\n IonicButtonFill,\n IonicButtonShape,\n IonicButtonSize,\n IonicColor,\n IonicPopoverAlignment\n} from './lib/types';\n\n// ============================================================================\n// Ionic Components\n// ============================================================================\n\nexport { ActionButtonListComponent, ButtonComponent } from './lib/components';\n\n// ============================================================================\n// Ionic Directives\n// ============================================================================\n\nexport { MakiTooltipDirective } from './lib/directives';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @makigamestudio/ui-ionic Global Component Styles
3
+ *
4
+ * This file contains global styles for library components that need to be
5
+ * applied at the document level (e.g., tooltips rendered in document.body).
6
+ *
7
+ * This file is automatically imported by theme.scss, so consumers only need
8
+ * to import theme.scss to get both CSS variables and component styles.
9
+ */
10
+ ion-popover::part(content) {
11
+ margin: var(--maki-spacing-xs, 0.25rem) 0;
12
+ }
13
+
14
+ .maki-tooltip {
15
+ background: var(--ion-color-dark, #222428);
16
+ color: var(--ion-color-dark-contrast, #fff);
17
+ padding: var(--maki-spacing-sm, 0.5rem) var(--maki-spacing-md, 0.75rem);
18
+ border-radius: var(--maki-radius-xs, 0.25rem);
19
+ font-size: var(--maki-font-size-sm, 0.875rem);
20
+ font-family: var(--ion-font-family, sans-serif);
21
+ line-height: var(--maki-line-height-normal, 1.5);
22
+ letter-spacing: var(--maki-letter-spacing-normal, 0);
23
+ max-width: min(100vw, 450px) !important;
24
+ width: fit-content;
25
+ overflow: scroll;
26
+ word-wrap: break-word;
27
+ box-shadow: var(--maki-box-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));
28
+ z-index: 10000;
29
+ pointer-events: none;
30
+ margin: var(--maki-spacing-xs, 0.25rem) var(--maki-spacing-xs, 0.25rem) var(--maki-spacing-xs, 0.25rem) 0;
31
+ transition: opacity 150ms ease;
32
+ }
33
+ .maki-tooltip[data-color=primary] {
34
+ background: var(--ion-color-primary);
35
+ color: var(--ion-color-primary-contrast);
36
+ }
37
+ .maki-tooltip[data-color=secondary] {
38
+ background: var(--ion-color-secondary);
39
+ color: var(--ion-color-secondary-contrast);
40
+ }
41
+ .maki-tooltip[data-color=tertiary] {
42
+ background: var(--ion-color-tertiary);
43
+ color: var(--ion-color-tertiary-contrast);
44
+ }
45
+ .maki-tooltip[data-color=success] {
46
+ background: var(--ion-color-success);
47
+ color: var(--ion-color-success-contrast);
48
+ }
49
+ .maki-tooltip[data-color=warning] {
50
+ background: var(--ion-color-warning);
51
+ color: var(--ion-color-warning-contrast);
52
+ }
53
+ .maki-tooltip[data-color=danger] {
54
+ background: var(--ion-color-danger);
55
+ color: var(--ion-color-danger-contrast);
56
+ }
57
+ .maki-tooltip[data-color=light] {
58
+ background: var(--ion-color-light);
59
+ color: var(--ion-color-light-contrast);
60
+ }
61
+ .maki-tooltip[data-color=medium] {
62
+ background: var(--ion-color-medium);
63
+ color: var(--ion-color-medium-contrast);
64
+ }
65
+ .maki-tooltip[data-color=dark] {
66
+ background: var(--ion-color-dark);
67
+ color: var(--ion-color-dark-contrast);
68
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @makigamestudio/ui-ionic Global Component Styles
3
+ *
4
+ * This file contains global styles for library components that need to be
5
+ * applied at the document level (e.g., tooltips rendered in document.body).
6
+ *
7
+ * This file is automatically imported by theme.scss, so consumers only need
8
+ * to import theme.scss to get both CSS variables and component styles.
9
+ */
10
+
11
+ // ==============================================
12
+ // Dropdown Popover (maki-button)
13
+ // ==============================================
14
+ ion-popover::part(content) {
15
+ margin: var(--maki-spacing-xs, 0.25rem) 0;
16
+ }
17
+
18
+ // ==============================================
19
+ // Tooltip Component (maki-tooltip)
20
+ // ==============================================
21
+ .maki-tooltip {
22
+ // Base styles with fallbacks for robustness
23
+ background: var(--ion-color-dark, #222428);
24
+ color: var(--ion-color-dark-contrast, #fff);
25
+ padding: var(--maki-spacing-sm, 0.5rem) var(--maki-spacing-md, 0.75rem);
26
+ border-radius: var(--maki-radius-xs, 0.25rem);
27
+ font-size: var(--maki-font-size-sm, 0.875rem);
28
+ font-family: var(--ion-font-family, sans-serif);
29
+ line-height: var(--maki-line-height-normal, 1.5);
30
+ letter-spacing: var(--maki-letter-spacing-normal, 0);
31
+ max-width: min(100vw, 450px) !important;
32
+ width: fit-content;
33
+ overflow: scroll;
34
+ word-wrap: break-word;
35
+ box-shadow: var(--maki-box-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));
36
+ z-index: 10000;
37
+ pointer-events: none;
38
+ margin: var(--maki-spacing-xs, 0.25rem) var(--maki-spacing-xs, 0.25rem)
39
+ var(--maki-spacing-xs, 0.25rem) 0;
40
+ transition: opacity 150ms ease;
41
+
42
+ // Color variants using Ionic color system
43
+ &[data-color='primary'] {
44
+ background: var(--ion-color-primary);
45
+ color: var(--ion-color-primary-contrast);
46
+ }
47
+
48
+ &[data-color='secondary'] {
49
+ background: var(--ion-color-secondary);
50
+ color: var(--ion-color-secondary-contrast);
51
+ }
52
+
53
+ &[data-color='tertiary'] {
54
+ background: var(--ion-color-tertiary);
55
+ color: var(--ion-color-tertiary-contrast);
56
+ }
57
+
58
+ &[data-color='success'] {
59
+ background: var(--ion-color-success);
60
+ color: var(--ion-color-success-contrast);
61
+ }
62
+
63
+ &[data-color='warning'] {
64
+ background: var(--ion-color-warning);
65
+ color: var(--ion-color-warning-contrast);
66
+ }
67
+
68
+ &[data-color='danger'] {
69
+ background: var(--ion-color-danger);
70
+ color: var(--ion-color-danger-contrast);
71
+ }
72
+
73
+ &[data-color='light'] {
74
+ background: var(--ion-color-light);
75
+ color: var(--ion-color-light-contrast);
76
+ }
77
+
78
+ &[data-color='medium'] {
79
+ background: var(--ion-color-medium);
80
+ color: var(--ion-color-medium-contrast);
81
+ }
82
+
83
+ &[data-color='dark'] {
84
+ background: var(--ion-color-dark);
85
+ color: var(--ion-color-dark-contrast);
86
+ }
87
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makigamestudio/ui-ionic",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Ionic implementation of @makigamestudio/ui-core. Provides Ionic-specific button components with signal-based state management.",
5
5
  "keywords": [
6
6
  "angular",
@@ -21,7 +21,7 @@
21
21
  "@angular/common": "^21.0.0",
22
22
  "@angular/core": "^21.0.0",
23
23
  "@ionic/angular": "^8.0.0",
24
- "@makigamestudio/ui-core": "^0.8.0",
24
+ "@makigamestudio/ui-core": "^0.9.0",
25
25
  "ionicons": "^8.0.0"
26
26
  },
27
27
  "dependencies": {