ngx-com 0.0.1 → 0.0.4

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.
Files changed (82) hide show
  1. package/fesm2022/ngx-com-components-avatar.mjs +772 -0
  2. package/fesm2022/ngx-com-components-avatar.mjs.map +1 -0
  3. package/fesm2022/ngx-com-components-badge.mjs +138 -0
  4. package/fesm2022/ngx-com-components-badge.mjs.map +1 -0
  5. package/fesm2022/ngx-com-components-button.mjs +146 -0
  6. package/fesm2022/ngx-com-components-button.mjs.map +1 -0
  7. package/fesm2022/ngx-com-components-calendar.mjs +5046 -0
  8. package/fesm2022/ngx-com-components-calendar.mjs.map +1 -0
  9. package/fesm2022/ngx-com-components-card.mjs +590 -0
  10. package/fesm2022/ngx-com-components-card.mjs.map +1 -0
  11. package/fesm2022/ngx-com-components-checkbox.mjs +344 -0
  12. package/fesm2022/ngx-com-components-checkbox.mjs.map +1 -0
  13. package/fesm2022/ngx-com-components-collapsible.mjs +612 -0
  14. package/fesm2022/ngx-com-components-collapsible.mjs.map +1 -0
  15. package/fesm2022/ngx-com-components-confirm.mjs +562 -0
  16. package/fesm2022/ngx-com-components-confirm.mjs.map +1 -0
  17. package/fesm2022/ngx-com-components-dropdown-testing.mjs +255 -0
  18. package/fesm2022/ngx-com-components-dropdown-testing.mjs.map +1 -0
  19. package/fesm2022/ngx-com-components-dropdown.mjs +2692 -0
  20. package/fesm2022/ngx-com-components-dropdown.mjs.map +1 -0
  21. package/fesm2022/ngx-com-components-empty-state.mjs +382 -0
  22. package/fesm2022/ngx-com-components-empty-state.mjs.map +1 -0
  23. package/fesm2022/ngx-com-components-form-field.mjs +924 -0
  24. package/fesm2022/ngx-com-components-form-field.mjs.map +1 -0
  25. package/fesm2022/ngx-com-components-icon.mjs +183 -0
  26. package/fesm2022/ngx-com-components-icon.mjs.map +1 -0
  27. package/fesm2022/ngx-com-components-item.mjs +578 -0
  28. package/fesm2022/ngx-com-components-item.mjs.map +1 -0
  29. package/fesm2022/ngx-com-components-menu.mjs +1200 -0
  30. package/fesm2022/ngx-com-components-menu.mjs.map +1 -0
  31. package/fesm2022/ngx-com-components-paginator.mjs +823 -0
  32. package/fesm2022/ngx-com-components-paginator.mjs.map +1 -0
  33. package/fesm2022/ngx-com-components-popover.mjs +901 -0
  34. package/fesm2022/ngx-com-components-popover.mjs.map +1 -0
  35. package/fesm2022/ngx-com-components-radio.mjs +621 -0
  36. package/fesm2022/ngx-com-components-radio.mjs.map +1 -0
  37. package/fesm2022/ngx-com-components-segmented-control.mjs +538 -0
  38. package/fesm2022/ngx-com-components-segmented-control.mjs.map +1 -0
  39. package/fesm2022/ngx-com-components-sort.mjs +368 -0
  40. package/fesm2022/ngx-com-components-sort.mjs.map +1 -0
  41. package/fesm2022/ngx-com-components-spinner.mjs +189 -0
  42. package/fesm2022/ngx-com-components-spinner.mjs.map +1 -0
  43. package/fesm2022/ngx-com-components-tabs.mjs +1522 -0
  44. package/fesm2022/ngx-com-components-tabs.mjs.map +1 -0
  45. package/fesm2022/ngx-com-components-tooltip.mjs +625 -0
  46. package/fesm2022/ngx-com-components-tooltip.mjs.map +1 -0
  47. package/fesm2022/ngx-com-components.mjs +17 -0
  48. package/fesm2022/ngx-com-components.mjs.map +1 -0
  49. package/fesm2022/ngx-com-tokens.mjs +12 -0
  50. package/fesm2022/ngx-com-tokens.mjs.map +1 -0
  51. package/fesm2022/ngx-com-utils.mjs +601 -0
  52. package/fesm2022/ngx-com-utils.mjs.map +1 -0
  53. package/fesm2022/ngx-com.mjs +9 -23
  54. package/fesm2022/ngx-com.mjs.map +1 -1
  55. package/package.json +105 -1
  56. package/types/ngx-com-components-avatar.d.ts +409 -0
  57. package/types/ngx-com-components-badge.d.ts +97 -0
  58. package/types/ngx-com-components-button.d.ts +69 -0
  59. package/types/ngx-com-components-calendar.d.ts +1665 -0
  60. package/types/ngx-com-components-card.d.ts +373 -0
  61. package/types/ngx-com-components-checkbox.d.ts +116 -0
  62. package/types/ngx-com-components-collapsible.d.ts +379 -0
  63. package/types/ngx-com-components-confirm.d.ts +160 -0
  64. package/types/ngx-com-components-dropdown-testing.d.ts +116 -0
  65. package/types/ngx-com-components-dropdown.d.ts +938 -0
  66. package/types/ngx-com-components-empty-state.d.ts +269 -0
  67. package/types/ngx-com-components-form-field.d.ts +531 -0
  68. package/types/ngx-com-components-icon.d.ts +94 -0
  69. package/types/ngx-com-components-item.d.ts +336 -0
  70. package/types/ngx-com-components-menu.d.ts +479 -0
  71. package/types/ngx-com-components-paginator.d.ts +265 -0
  72. package/types/ngx-com-components-popover.d.ts +309 -0
  73. package/types/ngx-com-components-radio.d.ts +258 -0
  74. package/types/ngx-com-components-segmented-control.d.ts +274 -0
  75. package/types/ngx-com-components-sort.d.ts +133 -0
  76. package/types/ngx-com-components-spinner.d.ts +120 -0
  77. package/types/ngx-com-components-tabs.d.ts +396 -0
  78. package/types/ngx-com-components-tooltip.d.ts +200 -0
  79. package/types/ngx-com-components.d.ts +12 -0
  80. package/types/ngx-com-tokens.d.ts +7 -0
  81. package/types/ngx-com-utils.d.ts +424 -0
  82. package/types/ngx-com.d.ts +10 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-com-components-segmented-control.mjs","sources":["../../../projects/com/components/segmented-control/segment-def.directive.ts","../../../projects/com/components/segmented-control/segmented-control.variants.ts","../../../projects/com/components/segmented-control/segmented-control.component.ts","../../../projects/com/components/segmented-control/index.ts","../../../projects/com/components/segmented-control/ngx-com-components-segmented-control.ts"],"sourcesContent":["import { Directive, TemplateRef, inject } from '@angular/core';\nimport type { SegmentOption } from './segmented-control.component';\n\n/**\n * Template context provided to custom segment templates.\n *\n * @example\n * ```html\n * <ng-template comSegmentDef let-option let-active=\"active\">\n * <com-icon [name]=\"option.value\" />\n * <span>{{ option.label }}</span>\n * </ng-template>\n * ```\n */\nexport interface SegmentTemplateContext<T = unknown> {\n /** The option object (default for `let-option`). */\n $implicit: SegmentOption<T>;\n /** Whether this segment is currently selected. */\n active: boolean;\n /** Whether this segment is disabled. */\n disabled: boolean;\n /** Position in the options list (0-indexed). */\n index: number;\n}\n\n/**\n * Directive to mark a custom template for segment content.\n *\n * The template receives a `SegmentTemplateContext` with the option data,\n * active state, disabled state, and index. Use this to customize the\n * inner content of each segment while the component manages the button,\n * styling, and ARIA attributes.\n *\n * @example Icon + text\n * ```html\n * <com-segmented-control [options]=\"viewOptions\" [(value)]=\"currentView\">\n * <ng-template comSegmentDef let-option let-active=\"active\">\n * <com-icon [name]=\"option.value\" size=\"sm\" />\n * <span>{{ option.label }}</span>\n * </ng-template>\n * </com-segmented-control>\n * ```\n *\n * @example Icon only (label used for accessibility)\n * ```html\n * <com-segmented-control [options]=\"alignmentOptions\" [(value)]=\"alignment\">\n * <ng-template comSegmentDef let-option>\n * <com-icon [name]=\"'align-' + option.value\" size=\"sm\" />\n * </ng-template>\n * </com-segmented-control>\n * ```\n */\n@Directive({\n selector: 'ng-template[comSegmentDef]',\n})\nexport class ComSegmentDef<T = unknown> {\n readonly templateRef: TemplateRef<SegmentTemplateContext<T>> = inject(TemplateRef);\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n// ─── Types ───\n\nexport type SegmentedControlSize = 'sm' | 'md' | 'lg';\nexport type SegmentedControlColor = 'primary' | 'accent' | 'muted';\nexport type SegmentedControlVariant = 'filled' | 'outline';\n\n// ─── Container Variants ───\n\n/**\n * CVA variants for the segmented control container (track).\n * Controls overall sizing, padding, and track background.\n */\nexport const segmentedControlContainerVariants: (props?: {\n size?: SegmentedControlSize;\n fullWidth?: boolean;\n}) => string = cva(\n [\n 'inline-flex items-center',\n 'rounded-pill',\n 'bg-muted',\n 'p-1',\n 'transition-colors duration-150',\n ],\n {\n variants: {\n size: {\n sm: 'gap-0.5',\n md: 'gap-1',\n lg: 'gap-1',\n },\n fullWidth: {\n true: 'w-full',\n false: '',\n },\n },\n defaultVariants: {\n size: 'md',\n fullWidth: false,\n },\n }\n);\n\n// ─── Segment Variants ───\n\n/**\n * CVA variants for individual segment buttons.\n * Controls per-segment sizing, typography, and active/inactive color states.\n */\nexport const segmentedControlSegmentVariants: (props?: {\n size?: SegmentedControlSize;\n color?: SegmentedControlColor;\n variant?: SegmentedControlVariant;\n active?: boolean;\n fullWidth?: boolean;\n}) => string = cva(\n [\n 'inline-flex items-center justify-center',\n 'rounded-pill',\n 'font-medium whitespace-nowrap select-none',\n 'transition-colors duration-150',\n 'cursor-pointer',\n 'gap-1.5',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n ],\n {\n variants: {\n size: {\n sm: 'h-7 px-3 text-sm',\n md: 'h-8 px-4 text-sm',\n lg: 'h-10 px-5 text-base',\n },\n color: {\n primary: '',\n accent: '',\n muted: '',\n },\n variant: {\n filled: '',\n outline: 'bg-transparent',\n },\n active: {\n true: '',\n false: 'text-foreground',\n },\n fullWidth: {\n true: 'flex-1',\n false: '',\n },\n },\n compoundVariants: [\n // ─── Filled + Active ───\n {\n variant: 'filled',\n color: 'primary',\n active: true,\n class: 'bg-primary text-primary-foreground shadow-sm',\n },\n {\n variant: 'filled',\n color: 'accent',\n active: true,\n class: 'bg-accent text-accent-foreground shadow-sm',\n },\n {\n variant: 'filled',\n color: 'muted',\n active: true,\n class: 'bg-background text-foreground shadow-sm',\n },\n\n // ─── Filled + Inactive (hover) ───\n {\n variant: 'filled',\n active: false,\n class: 'hover:bg-muted-hover',\n },\n\n // ─── Outline + Active ───\n {\n variant: 'outline',\n color: 'primary',\n active: true,\n class: 'ring-2 ring-primary text-primary',\n },\n {\n variant: 'outline',\n color: 'accent',\n active: true,\n class: 'ring-2 ring-accent text-accent',\n },\n {\n variant: 'outline',\n color: 'muted',\n active: true,\n class: 'ring-2 ring-border text-foreground',\n },\n\n // ─── Outline + Inactive (hover) ───\n {\n variant: 'outline',\n active: false,\n class: 'hover:bg-muted-hover',\n },\n ],\n defaultVariants: {\n size: 'md',\n color: 'primary',\n variant: 'filled',\n active: false,\n fullWidth: false,\n },\n }\n);\n\n// ─── Disabled Segment Classes ───\n\n/**\n * Classes to apply when a segment is disabled.\n * Separate from CVA to avoid complex variant combinations.\n */\nexport const SEGMENT_DISABLED_CLASSES =\n 'bg-disabled text-disabled-foreground cursor-not-allowed hover:bg-disabled';\n\n// ─── Variant Types ───\n\nexport type SegmentedControlContainerVariants = VariantProps<typeof segmentedControlContainerVariants>;\nexport type SegmentedControlSegmentVariants = VariantProps<typeof segmentedControlSegmentVariants>;\n","import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n ElementRef,\n input,\n model,\n viewChildren,\n ViewEncapsulation,\n} from '@angular/core';\nimport type { InputSignal, InputSignalWithTransform, ModelSignal, Signal } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { mergeClasses } from 'ngx-com/utils';\nimport { ComSegmentDef, type SegmentTemplateContext } from './segment-def.directive';\nimport {\n segmentedControlContainerVariants,\n segmentedControlSegmentVariants,\n SEGMENT_DISABLED_CLASSES,\n} from './segmented-control.variants';\nimport type {\n SegmentedControlSize,\n SegmentedControlColor,\n SegmentedControlVariant,\n} from './segmented-control.variants';\n\n/**\n * Represents a single option in the segmented control.\n */\nexport interface SegmentOption<T = unknown> {\n /** The value associated with this option. */\n value: T;\n /** Display label (also used as aria-label fallback for custom templates). */\n label: string;\n /** Whether this option is disabled. */\n disabled?: boolean | undefined;\n}\n\n/**\n * Segmented control component — a horizontal group of mutually exclusive options\n * where one is always selected. Think of it as a styled radio group in pill form.\n *\n * Supports two rendering modes:\n * - **Simple mode**: Plain text labels from the `label` property\n * - **Custom template mode**: Full control via `ng-template[comSegmentDef]`\n *\n * @tokens `--color-primary`, `--color-primary-foreground`,\n * `--color-accent`, `--color-accent-foreground`,\n * `--color-muted`, `--color-muted-foreground`, `--color-muted-hover`,\n * `--color-background`, `--color-foreground`,\n * `--color-disabled`, `--color-disabled-foreground`,\n * `--color-border`, `--color-ring`\n *\n * @example Basic two-option toggle\n * ```html\n * <com-segmented-control\n * [options]=\"[\n * { value: 'admin', label: 'Admin' },\n * { value: 'user', label: 'User' }\n * ]\"\n * [(value)]=\"selectedRole\"\n * />\n * ```\n *\n * @example Multiple options with variants\n * ```html\n * <com-segmented-control\n * [options]=\"viewOptions\"\n * [(value)]=\"currentView\"\n * color=\"primary\"\n * size=\"sm\"\n * />\n * ```\n *\n * @example Custom template with icons\n * ```html\n * <com-segmented-control [options]=\"viewOptions\" [(value)]=\"currentView\" color=\"primary\">\n * <ng-template comSegmentDef let-option let-active=\"active\">\n * <com-icon [name]=\"option.value === 'grid' ? 'grid' : 'list'\" size=\"sm\" />\n * <span>{{ option.label }}</span>\n * </ng-template>\n * </com-segmented-control>\n * ```\n *\n * @example Custom template with badges\n * ```html\n * <com-segmented-control [options]=\"statusOptions\" [(value)]=\"statusFilter\" color=\"accent\">\n * <ng-template comSegmentDef let-option let-active=\"active\">\n * <span>{{ option.label }}</span>\n * <span\n * class=\"ml-1.5 rounded-pill px-1.5 text-xs\"\n * [class]=\"active ? 'bg-accent-foreground/20 text-accent-foreground' : 'bg-muted text-muted-foreground'\"\n * >\n * {{ option.value === 'open' ? openCount : closedCount }}\n * </span>\n * </ng-template>\n * </com-segmented-control>\n * ```\n *\n * @example Icon only (label used for accessibility)\n * ```html\n * <com-segmented-control\n * [options]=\"[\n * { value: 'left', label: 'Align left' },\n * { value: 'center', label: 'Align center' },\n * { value: 'right', label: 'Align right' }\n * ]\"\n * [(value)]=\"alignment\"\n * size=\"sm\"\n * >\n * <ng-template comSegmentDef let-option>\n * <com-icon [name]=\"'align-' + option.value\" size=\"sm\" />\n * </ng-template>\n * </com-segmented-control>\n * ```\n *\n * @example Full width + outline variant\n * ```html\n * <com-segmented-control\n * [options]=\"plans\"\n * [(value)]=\"selectedPlan\"\n * variant=\"outline\"\n * color=\"primary\"\n * [fullWidth]=\"true\"\n * />\n * ```\n *\n * @example Disabled options\n * ```html\n * <com-segmented-control\n * [options]=\"[\n * { value: 'free', label: 'Free' },\n * { value: 'pro', label: 'Pro' },\n * { value: 'enterprise', label: 'Enterprise', disabled: true }\n * ]\"\n * [(value)]=\"plan\"\n * color=\"primary\"\n * size=\"lg\"\n * />\n * ```\n */\n@Component({\n selector: 'com-segmented-control',\n exportAs: 'comSegmentedControl',\n template: `\n <div\n role=\"radiogroup\"\n [attr.aria-label]=\"ariaLabel()\"\n [class]=\"containerClasses()\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <button\n #segmentButton\n type=\"button\"\n role=\"radio\"\n [attr.aria-checked]=\"isActive(option)\"\n [attr.aria-label]=\"customTemplate() ? option.label : null\"\n [attr.aria-disabled]=\"option.disabled || null\"\n [disabled]=\"option.disabled\"\n [tabindex]=\"tabIndexFor(i)\"\n [class]=\"segmentClasses(option)\"\n (click)=\"select(option)\"\n (keydown)=\"onKeydown($event, i)\"\n >\n @if (customTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl.templateRef\"\n [ngTemplateOutletContext]=\"getTemplateContext(option, i)\"\n />\n } @else {\n {{ option.label }}\n }\n </button>\n }\n </div>\n `,\n styles: `\n com-segmented-control {\n display: inline-block;\n }\n com-segmented-control[fullWidth] {\n display: block;\n }\n `,\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'com-segmented-control',\n '[attr.fullWidth]': 'fullWidth() || null',\n },\n})\nexport class ComSegmentedControl<T = unknown> {\n // ─── View Children ───\n\n /** References to all segment buttons for focus management. */\n private readonly segmentButtons: Signal<readonly ElementRef<HTMLButtonElement>[]> =\n viewChildren<ElementRef<HTMLButtonElement>>('segmentButton');\n\n // ─── Inputs ───\n\n /** The list of options to display. */\n readonly options: InputSignal<SegmentOption<T>[]> = input.required<SegmentOption<T>[]>();\n\n /** Currently selected value. Two-way bindable with `[(value)]`. */\n readonly value: ModelSignal<T | undefined> = model<T | undefined>(undefined);\n\n /** Controls segment height, padding, and font size. */\n readonly size: InputSignal<SegmentedControlSize> = input<SegmentedControlSize>('md');\n\n /** Color scheme for the active segment. */\n readonly color: InputSignal<SegmentedControlColor> = input<SegmentedControlColor>('primary');\n\n /** Visual variant: filled (solid background) or outline (ring border). */\n readonly variant: InputSignal<SegmentedControlVariant> = input<SegmentedControlVariant>('filled');\n\n /** When true, segments stretch equally to fill available width. */\n readonly fullWidth: InputSignalWithTransform<boolean, unknown> = input(false, {\n transform: booleanAttribute,\n });\n\n /** Accessible label for the radiogroup container. */\n readonly ariaLabel: InputSignal<string | null> = input<string | null>(null, {\n alias: 'aria-label',\n });\n\n /** Custom CSS classes to merge with container classes. */\n readonly userClass: InputSignal<string> = input('', { alias: 'class' });\n\n // ─── Content Child ───\n\n /** Optional custom template for segment content. */\n readonly customTemplate: Signal<ComSegmentDef<T> | undefined> = contentChild<ComSegmentDef<T>>(ComSegmentDef);\n\n // ─── Computed ───\n\n /** Classes for the container/track element. */\n protected readonly containerClasses: Signal<string> = computed(() =>\n mergeClasses(\n segmentedControlContainerVariants({\n size: this.size(),\n fullWidth: this.fullWidth(),\n }),\n this.userClass()\n )\n );\n\n // ─── Public Methods ───\n\n /**\n * Checks if the given option is currently selected.\n */\n isActive(option: SegmentOption<T>): boolean {\n return this.value() === option.value;\n }\n\n /**\n * Selects the given option (if not disabled).\n */\n select(option: SegmentOption<T>): void {\n if (option.disabled) {\n return;\n }\n this.value.set(option.value);\n }\n\n /**\n * Returns the tabindex for a segment at the given index.\n * Implements roving tabindex: only the selected (or first focusable) segment has tabindex=\"0\".\n */\n tabIndexFor(index: number): number {\n const opts = this.options();\n const currentValue = this.value();\n\n // If current value matches this option, it gets tabindex=\"0\"\n if (opts[index]?.value === currentValue) {\n return 0;\n }\n\n // If no value is selected, first non-disabled option gets tabindex=\"0\"\n if (currentValue === undefined) {\n const firstFocusableIndex = opts.findIndex((o) => !o.disabled);\n return index === firstFocusableIndex ? 0 : -1;\n }\n\n return -1;\n }\n\n /**\n * Returns computed classes for a segment button.\n */\n segmentClasses(option: SegmentOption<T>): string {\n const active = this.isActive(option);\n const baseClasses = segmentedControlSegmentVariants({\n size: this.size(),\n color: this.color(),\n variant: this.variant(),\n active,\n fullWidth: this.fullWidth(),\n });\n\n if (option.disabled) {\n return mergeClasses(baseClasses, SEGMENT_DISABLED_CLASSES);\n }\n\n return baseClasses;\n }\n\n /**\n * Builds the template context for custom templates.\n */\n getTemplateContext(option: SegmentOption<T>, index: number): SegmentTemplateContext<T> {\n return {\n $implicit: option,\n active: this.isActive(option),\n disabled: !!option.disabled,\n index,\n };\n }\n\n /**\n * Handles keyboard navigation for the segmented control.\n * Implements ARIA radiogroup keyboard patterns.\n */\n onKeydown(event: KeyboardEvent, currentIndex: number): void {\n const opts = this.options();\n let targetIndex: number | null = null;\n\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n targetIndex = this.findNextFocusableIndex(currentIndex, 1);\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n targetIndex = this.findNextFocusableIndex(currentIndex, -1);\n break;\n case 'Home':\n targetIndex = this.findFirstFocusableIndex();\n break;\n case 'End':\n targetIndex = this.findLastFocusableIndex();\n break;\n default:\n return;\n }\n\n if (targetIndex !== null && targetIndex !== currentIndex) {\n event.preventDefault();\n const targetOption = opts[targetIndex];\n if (targetOption) {\n this.select(targetOption);\n this.focusSegmentAt(targetIndex);\n }\n }\n }\n\n // ─── Private Methods ───\n\n /**\n * Finds the next focusable (non-disabled) option index in the given direction.\n * Wraps around to the beginning/end of the list.\n */\n private findNextFocusableIndex(currentIndex: number, direction: 1 | -1): number | null {\n const opts = this.options();\n const length = opts.length;\n\n if (length === 0) {\n return null;\n }\n\n let index = currentIndex;\n for (let i = 0; i < length; i++) {\n index = (index + direction + length) % length;\n if (!opts[index]?.disabled) {\n return index;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the first focusable (non-disabled) option index.\n */\n private findFirstFocusableIndex(): number | null {\n const opts = this.options();\n const index = opts.findIndex((o) => !o.disabled);\n return index >= 0 ? index : null;\n }\n\n /**\n * Finds the last focusable (non-disabled) option index.\n */\n private findLastFocusableIndex(): number | null {\n const opts = this.options();\n for (let i = opts.length - 1; i >= 0; i--) {\n if (!opts[i]?.disabled) {\n return i;\n }\n }\n return null;\n }\n\n /**\n * Focuses the segment button at the given index.\n */\n private focusSegmentAt(index: number): void {\n const button = this.segmentButtons()[index];\n if (button) {\n button.nativeElement.focus();\n }\n }\n}\n","// Public API for the segmented-control component\n\n// Main component\nexport { ComSegmentedControl } from './segmented-control.component';\nexport type { SegmentOption } from './segmented-control.component';\n\n// Directive\nexport { ComSegmentDef } from './segment-def.directive';\nexport type { SegmentTemplateContext } from './segment-def.directive';\n\n// Variants\nexport {\n segmentedControlContainerVariants,\n segmentedControlSegmentVariants,\n SEGMENT_DISABLED_CLASSES,\n} from './segmented-control.variants';\n\nexport type {\n SegmentedControlSize,\n SegmentedControlColor,\n SegmentedControlVariant,\n SegmentedControlContainerVariants,\n SegmentedControlSegmentVariants,\n} from './segmented-control.variants';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,368 @@
1
+ import { cva } from 'class-variance-authority';
2
+ import * as i0 from '@angular/core';
3
+ import { model, input, booleanAttribute, output, Directive, computed, ChangeDetectionStrategy, Component, inject, DestroyRef } from '@angular/core';
4
+
5
+ // ─── Sort Header Variants ───
6
+ /**
7
+ * @tokens `--color-foreground`, `--color-muted-foreground`
8
+ */
9
+ const sortHeaderVariants = cva(['inline-flex items-center gap-1.5', 'select-none', 'transition-colors duration-150'], {
10
+ variants: {
11
+ sortable: {
12
+ true: 'cursor-pointer hover:text-foreground',
13
+ false: 'cursor-default',
14
+ },
15
+ active: {
16
+ true: 'text-foreground',
17
+ false: 'text-muted-foreground',
18
+ },
19
+ disabled: {
20
+ true: 'text-disabled-foreground cursor-not-allowed pointer-events-none',
21
+ false: '',
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ sortable: true,
26
+ active: false,
27
+ disabled: false,
28
+ },
29
+ });
30
+ // ─── Sort Icon Variants ───
31
+ /**
32
+ * @tokens `--color-foreground`, `--color-muted-foreground`
33
+ */
34
+ const sortIconVariants = cva(['inline-flex items-center justify-center', 'shrink-0', 'transition-all duration-200 ease-out'], {
35
+ variants: {
36
+ size: {
37
+ sm: 'size-3',
38
+ md: 'size-3.5',
39
+ lg: 'size-4',
40
+ },
41
+ state: {
42
+ asc: 'opacity-100 rotate-0',
43
+ desc: 'opacity-100 rotate-180',
44
+ unsorted: 'opacity-40 rotate-0',
45
+ hidden: 'opacity-0 scale-75',
46
+ },
47
+ },
48
+ defaultVariants: {
49
+ size: 'md',
50
+ state: 'hidden',
51
+ },
52
+ });
53
+
54
+ const DEFAULT_SORT_CYCLE = ['asc', 'desc', undefined];
55
+ /**
56
+ * Parent directive that manages sort state for a group of sortable headers.
57
+ *
58
+ * Apply to a container element (e.g., `<tr>`, `<div>`) that contains `[uiSortHeader]` children.
59
+ * Children inject this directive via DI and read its signals directly.
60
+ *
61
+ * @tokens `--color-foreground`, `--color-muted-foreground`
62
+ *
63
+ * @example Basic usage
64
+ * ```html
65
+ * <tr comSort (sortChange)="onSort($event)">
66
+ * <th comSortHeader="name">Name</th>
67
+ * <th comSortHeader="age">Age</th>
68
+ * </tr>
69
+ * ```
70
+ *
71
+ * @example Two-way binding
72
+ * ```html
73
+ * <tr comSort [(sortActive)]="column" [(sortDirection)]="direction">
74
+ * <th comSortHeader="name">Name</th>
75
+ * </tr>
76
+ * ```
77
+ */
78
+ class SortDirective {
79
+ // ─── Inputs ───
80
+ /** Currently active sort column id — two-way via model() */
81
+ sortActive = model(undefined, ...(ngDevMode ? [{ debugName: "sortActive" }] : []));
82
+ /** Current sort direction — two-way via model() */
83
+ sortDirection = model(undefined, ...(ngDevMode ? [{ debugName: "sortDirection" }] : []));
84
+ /** Disables all sorting in this container */
85
+ sortDisabled = input(false, { ...(ngDevMode ? { debugName: "sortDisabled" } : {}), transform: booleanAttribute });
86
+ /** Customize the click cycle (e.g., ['asc', 'desc'] to skip unsorted) */
87
+ sortCycle = input(DEFAULT_SORT_CYCLE, ...(ngDevMode ? [{ debugName: "sortCycle" }] : []));
88
+ /** Show a muted arrow on unsorted headers */
89
+ sortShowIndicator = input(false, { ...(ngDevMode ? { debugName: "sortShowIndicator" } : {}), transform: booleanAttribute });
90
+ // ─── Outputs ───
91
+ /** Emitted when active column or direction changes */
92
+ sortChange = output();
93
+ // ─── Registration ───
94
+ headers = new Map();
95
+ /** Register a sort header with this parent */
96
+ register(header) {
97
+ this.headers.set(header.id(), header);
98
+ }
99
+ /** Deregister a sort header */
100
+ deregister(id) {
101
+ this.headers.delete(id);
102
+ }
103
+ // ─── Public API ───
104
+ /** Programmatically sort by a column */
105
+ sort(id) {
106
+ if (this.sortDisabled())
107
+ return;
108
+ const cycle = this.sortCycle();
109
+ if (this.sortActive() !== id) {
110
+ // New column — start at first direction in cycle
111
+ this.sortActive.set(id);
112
+ this.sortDirection.set(cycle[0]);
113
+ }
114
+ else {
115
+ // Same column — advance cycle
116
+ const currentIndex = cycle.indexOf(this.sortDirection());
117
+ const nextIndex = (currentIndex + 1) % cycle.length;
118
+ const nextDir = cycle[nextIndex];
119
+ this.sortDirection.set(nextDir);
120
+ // If direction is undefined, clear active
121
+ if (nextDir === undefined) {
122
+ this.sortActive.set(undefined);
123
+ }
124
+ }
125
+ this.sortChange.emit({
126
+ active: this.sortActive(),
127
+ direction: this.sortDirection(),
128
+ });
129
+ }
130
+ /** Returns the next direction in the cycle for a given column */
131
+ getNextDirection(id) {
132
+ const cycle = this.sortCycle();
133
+ if (this.sortActive() !== id) {
134
+ return cycle[0];
135
+ }
136
+ const currentIndex = cycle.indexOf(this.sortDirection());
137
+ const nextIndex = (currentIndex + 1) % cycle.length;
138
+ return cycle[nextIndex];
139
+ }
140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SortDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
141
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.0", type: SortDirective, isStandalone: true, selector: "[comSort]", inputs: { sortActive: { classPropertyName: "sortActive", publicName: "sortActive", isSignal: true, isRequired: false, transformFunction: null }, sortDirection: { classPropertyName: "sortDirection", publicName: "sortDirection", isSignal: true, isRequired: false, transformFunction: null }, sortDisabled: { classPropertyName: "sortDisabled", publicName: "sortDisabled", isSignal: true, isRequired: false, transformFunction: null }, sortCycle: { classPropertyName: "sortCycle", publicName: "sortCycle", isSignal: true, isRequired: false, transformFunction: null }, sortShowIndicator: { classPropertyName: "sortShowIndicator", publicName: "sortShowIndicator", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortActive: "sortActiveChange", sortDirection: "sortDirectionChange", sortChange: "sortChange" }, host: { classAttribute: "contents" }, exportAs: ["comSort"], ngImport: i0 });
142
+ }
143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SortDirective, decorators: [{
144
+ type: Directive,
145
+ args: [{
146
+ selector: '[comSort]',
147
+ exportAs: 'comSort',
148
+ host: {
149
+ class: 'contents',
150
+ },
151
+ }]
152
+ }], propDecorators: { sortActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortActive", required: false }] }, { type: i0.Output, args: ["sortActiveChange"] }], sortDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDirection", required: false }] }, { type: i0.Output, args: ["sortDirectionChange"] }], sortDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDisabled", required: false }] }], sortCycle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortCycle", required: false }] }], sortShowIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortShowIndicator", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }] } });
153
+
154
+ /**
155
+ * Internal animated SVG arrow indicator for sort headers.
156
+ * Not exported — used only inside SortHeaderComponent.
157
+ *
158
+ * @tokens `--color-foreground`, `--color-muted-foreground`
159
+ */
160
+ class SortIconComponent {
161
+ /** Current sort direction */
162
+ direction = input(undefined, ...(ngDevMode ? [{ debugName: "direction" }] : []));
163
+ /** Whether the column is actively sorted */
164
+ isSorted = input(false, ...(ngDevMode ? [{ debugName: "isSorted" }] : []));
165
+ /** Show a muted indicator when not sorted */
166
+ showWhenUnsorted = input(false, ...(ngDevMode ? [{ debugName: "showWhenUnsorted" }] : []));
167
+ /** Compute the icon state for CVA */
168
+ iconState = computed(() => {
169
+ if (this.isSorted()) {
170
+ return this.direction() === 'asc' ? 'asc' : 'desc';
171
+ }
172
+ if (this.showWhenUnsorted()) {
173
+ return 'unsorted';
174
+ }
175
+ return 'hidden';
176
+ }, ...(ngDevMode ? [{ debugName: "iconState" }] : []));
177
+ /** CVA-generated classes for the icon container */
178
+ iconClasses = computed(() => sortIconVariants({
179
+ size: 'md',
180
+ state: this.iconState(),
181
+ }), ...(ngDevMode ? [{ debugName: "iconClasses" }] : []));
182
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SortIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
183
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.0", type: SortIconComponent, isStandalone: true, selector: "com-sort-icon", inputs: { direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, isSorted: { classPropertyName: "isSorted", publicName: "isSorted", isSignal: true, isRequired: false, transformFunction: null }, showWhenUnsorted: { classPropertyName: "showWhenUnsorted", publicName: "showWhenUnsorted", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
184
+ <span [class]="iconClasses()">
185
+ <svg
186
+ xmlns="http://www.w3.org/2000/svg"
187
+ viewBox="0 0 24 24"
188
+ fill="none"
189
+ stroke="currentColor"
190
+ stroke-width="2.5"
191
+ stroke-linecap="round"
192
+ stroke-linejoin="round"
193
+ class="size-full"
194
+ aria-hidden="true"
195
+ >
196
+ <path d="M12 19V5" />
197
+ <path d="M5 12l7-7 7 7" />
198
+ </svg>
199
+ </span>
200
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
201
+ }
202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SortIconComponent, decorators: [{
203
+ type: Component,
204
+ args: [{
205
+ selector: 'com-sort-icon',
206
+ template: `
207
+ <span [class]="iconClasses()">
208
+ <svg
209
+ xmlns="http://www.w3.org/2000/svg"
210
+ viewBox="0 0 24 24"
211
+ fill="none"
212
+ stroke="currentColor"
213
+ stroke-width="2.5"
214
+ stroke-linecap="round"
215
+ stroke-linejoin="round"
216
+ class="size-full"
217
+ aria-hidden="true"
218
+ >
219
+ <path d="M12 19V5" />
220
+ <path d="M5 12l7-7 7 7" />
221
+ </svg>
222
+ </span>
223
+ `,
224
+ changeDetection: ChangeDetectionStrategy.OnPush,
225
+ }]
226
+ }], propDecorators: { direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], isSorted: [{ type: i0.Input, args: [{ isSignal: true, alias: "isSorted", required: false }] }], showWhenUnsorted: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWhenUnsorted", required: false }] }] } });
227
+
228
+ /**
229
+ * Sortable header component — child of [uiSort] directive.
230
+ *
231
+ * Apply to table headers, div columns, or any clickable element that should trigger sorting.
232
+ *
233
+ * @tokens `--color-foreground`, `--color-muted-foreground`, `--color-disabled-foreground`
234
+ *
235
+ * @example Basic usage
236
+ * ```html
237
+ * <tr comSort (sortChange)="onSort($event)">
238
+ * <th comSortHeader="name">Name</th>
239
+ * <th comSortHeader="age">Age</th>
240
+ * </tr>
241
+ * ```
242
+ *
243
+ * @example Arrow placement
244
+ * ```html
245
+ * <th comSortHeader="name" comSortHeaderArrowPosition="before">Name</th>
246
+ * ```
247
+ */
248
+ class SortHeaderComponent {
249
+ sort = inject(SortDirective, { optional: true });
250
+ destroyRef = inject(DestroyRef);
251
+ // ─── Inputs ───
252
+ /** The column id — aliased from the selector */
253
+ id = input.required({ ...(ngDevMode ? { debugName: "id" } : {}), alias: 'comSortHeader' });
254
+ /** Disable sorting for this specific header */
255
+ sortHeaderDisabled = input(false, { ...(ngDevMode ? { debugName: "sortHeaderDisabled" } : {}), transform: booleanAttribute });
256
+ /** Override parent's sortShowIndicator for this header */
257
+ sortHeaderShowIndicator = input(undefined, ...(ngDevMode ? [{ debugName: "sortHeaderShowIndicator" }] : []));
258
+ /** Arrow placement relative to content */
259
+ sortHeaderArrowPosition = input('after', { ...(ngDevMode ? { debugName: "sortHeaderArrowPosition" } : {}), alias: 'comSortHeaderArrowPosition' });
260
+ // ─── Computed State (from parent signals) ───
261
+ /** Whether this header is the currently active sort column */
262
+ isActive = computed(() => this.sort?.sortActive() === this.id(), ...(ngDevMode ? [{ debugName: "isActive" }] : []));
263
+ /** Current direction if active, undefined otherwise */
264
+ direction = computed(() => this.isActive() ? this.sort?.sortDirection() : undefined, ...(ngDevMode ? [{ debugName: "direction" }] : []));
265
+ /** Whether this header is sorted (active + has direction) */
266
+ isSorted = computed(() => this.isActive() && this.sort?.sortDirection() !== undefined, ...(ngDevMode ? [{ debugName: "isSorted" }] : []));
267
+ /** Whether to show the muted indicator when unsorted */
268
+ showUnsortedIndicator = computed(() => this.sortHeaderShowIndicator() ?? this.sort?.sortShowIndicator() ?? false, ...(ngDevMode ? [{ debugName: "showUnsortedIndicator" }] : []));
269
+ /** Whether sorting is disabled for this header */
270
+ isDisabled = computed(() => this.sortHeaderDisabled() || this.sort?.sortDisabled() || false, ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
271
+ /** aria-sort attribute value */
272
+ ariaSort = computed(() => {
273
+ if (!this.isSorted())
274
+ return 'none';
275
+ return this.direction() === 'asc' ? 'ascending' : 'descending';
276
+ }, ...(ngDevMode ? [{ debugName: "ariaSort" }] : []));
277
+ /** CVA-generated host classes */
278
+ hostClasses = computed(() => sortHeaderVariants({
279
+ sortable: !this.isDisabled(),
280
+ active: this.isSorted(),
281
+ disabled: this.isDisabled(),
282
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
283
+ constructor() {
284
+ if (!this.sort) {
285
+ throw new Error('comSortHeader must be placed inside a [comSort] container.');
286
+ }
287
+ this.destroyRef.onDestroy(() => {
288
+ this.sort?.deregister(this.id());
289
+ });
290
+ }
291
+ ngOnInit() {
292
+ this.sort.register(this);
293
+ }
294
+ // ─── Event Handlers ───
295
+ onClick() {
296
+ if (this.isDisabled())
297
+ return;
298
+ this.sort.sort(this.id());
299
+ }
300
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SortHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
301
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: SortHeaderComponent, isStandalone: true, selector: "[comSortHeader]", inputs: { id: { classPropertyName: "id", publicName: "comSortHeader", isSignal: true, isRequired: true, transformFunction: null }, sortHeaderDisabled: { classPropertyName: "sortHeaderDisabled", publicName: "sortHeaderDisabled", isSignal: true, isRequired: false, transformFunction: null }, sortHeaderShowIndicator: { classPropertyName: "sortHeaderShowIndicator", publicName: "sortHeaderShowIndicator", isSignal: true, isRequired: false, transformFunction: null }, sortHeaderArrowPosition: { classPropertyName: "sortHeaderArrowPosition", publicName: "comSortHeaderArrowPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick()", "keydown.enter": "onClick()", "keydown.space": "$event.preventDefault(); onClick()" }, properties: { "class": "hostClasses()", "attr.aria-sort": "ariaSort()", "attr.role": "\"columnheader\"", "attr.tabindex": "isDisabled() ? -1 : 0", "attr.aria-disabled": "isDisabled() || null" } }, ngImport: i0, template: `
302
+ @if (sortHeaderArrowPosition() === 'before') {
303
+ <com-sort-icon
304
+ [direction]="direction()"
305
+ [isSorted]="isSorted()"
306
+ [showWhenUnsorted]="showUnsortedIndicator()"
307
+ />
308
+ }
309
+
310
+ <ng-content />
311
+
312
+ @if (sortHeaderArrowPosition() === 'after') {
313
+ <com-sort-icon
314
+ [direction]="direction()"
315
+ [isSorted]="isSorted()"
316
+ [showWhenUnsorted]="showUnsortedIndicator()"
317
+ />
318
+ }
319
+ `, isInline: true, dependencies: [{ kind: "component", type: SortIconComponent, selector: "com-sort-icon", inputs: ["direction", "isSorted", "showWhenUnsorted"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
320
+ }
321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SortHeaderComponent, decorators: [{
322
+ type: Component,
323
+ args: [{
324
+ selector: '[comSortHeader]',
325
+ template: `
326
+ @if (sortHeaderArrowPosition() === 'before') {
327
+ <com-sort-icon
328
+ [direction]="direction()"
329
+ [isSorted]="isSorted()"
330
+ [showWhenUnsorted]="showUnsortedIndicator()"
331
+ />
332
+ }
333
+
334
+ <ng-content />
335
+
336
+ @if (sortHeaderArrowPosition() === 'after') {
337
+ <com-sort-icon
338
+ [direction]="direction()"
339
+ [isSorted]="isSorted()"
340
+ [showWhenUnsorted]="showUnsortedIndicator()"
341
+ />
342
+ }
343
+ `,
344
+ imports: [SortIconComponent],
345
+ changeDetection: ChangeDetectionStrategy.OnPush,
346
+ host: {
347
+ '[class]': 'hostClasses()',
348
+ '[attr.aria-sort]': 'ariaSort()',
349
+ '[attr.role]': '"columnheader"',
350
+ '[attr.tabindex]': 'isDisabled() ? -1 : 0',
351
+ '[attr.aria-disabled]': 'isDisabled() || null',
352
+ '(click)': 'onClick()',
353
+ '(keydown.enter)': 'onClick()',
354
+ '(keydown.space)': '$event.preventDefault(); onClick()',
355
+ },
356
+ }]
357
+ }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "comSortHeader", required: true }] }], sortHeaderDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortHeaderDisabled", required: false }] }], sortHeaderShowIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortHeaderShowIndicator", required: false }] }], sortHeaderArrowPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "comSortHeaderArrowPosition", required: false }] }] } });
358
+
359
+ // Public API for the sort component
360
+ // Types & Variants
361
+ // NOT exported: SortIconComponent (internal)
362
+
363
+ /**
364
+ * Generated bundle index. Do not edit.
365
+ */
366
+
367
+ export { SortDirective, SortHeaderComponent, sortHeaderVariants, sortIconVariants };
368
+ //# sourceMappingURL=ngx-com-components-sort.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-com-components-sort.mjs","sources":["../../../projects/com/components/sort/sort.variants.ts","../../../projects/com/components/sort/sort.directive.ts","../../../projects/com/components/sort/sort-icon.component.ts","../../../projects/com/components/sort/sort-header.component.ts","../../../projects/com/components/sort/index.ts","../../../projects/com/components/sort/ngx-com-components-sort.ts"],"sourcesContent":["import { cva } from 'class-variance-authority';\n\n// ─── Type Exports ───\n\n/** Sort direction — three states */\nexport type SortDirection = 'asc' | 'desc' | undefined;\n\n/** Configures the three-state sort cycle */\nexport type SortCycle = SortDirection[];\n\n/** Emitted when sort state changes */\nexport interface SortEvent {\n /** The active column id, or undefined if unsorted */\n active: string | undefined;\n /** The sort direction */\n direction: SortDirection;\n}\n\n// ─── Sort Header Variants ───\n\n/**\n * @tokens `--color-foreground`, `--color-muted-foreground`\n */\nexport const sortHeaderVariants: (props?: {\n sortable?: boolean;\n active?: boolean;\n disabled?: boolean;\n}) => string = cva(\n ['inline-flex items-center gap-1.5', 'select-none', 'transition-colors duration-150'],\n {\n variants: {\n sortable: {\n true: 'cursor-pointer hover:text-foreground',\n false: 'cursor-default',\n },\n active: {\n true: 'text-foreground',\n false: 'text-muted-foreground',\n },\n disabled: {\n true: 'text-disabled-foreground cursor-not-allowed pointer-events-none',\n false: '',\n },\n },\n defaultVariants: {\n sortable: true,\n active: false,\n disabled: false,\n },\n }\n);\n\n// ─── Sort Icon Variants ───\n\n/**\n * @tokens `--color-foreground`, `--color-muted-foreground`\n */\nexport const sortIconVariants: (props?: {\n size?: 'sm' | 'md' | 'lg';\n state?: 'asc' | 'desc' | 'unsorted' | 'hidden';\n}) => string = cva(\n ['inline-flex items-center justify-center', 'shrink-0', 'transition-all duration-200 ease-out'],\n {\n variants: {\n size: {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n },\n state: {\n asc: 'opacity-100 rotate-0',\n desc: 'opacity-100 rotate-180',\n unsorted: 'opacity-40 rotate-0',\n hidden: 'opacity-0 scale-75',\n },\n },\n defaultVariants: {\n size: 'md',\n state: 'hidden',\n },\n }\n);\n","import { booleanAttribute, Directive, input, model, output } from '@angular/core';\nimport type {\n InputSignal,\n InputSignalWithTransform,\n ModelSignal,\n OutputEmitterRef,\n} from '@angular/core';\nimport type { SortDirection, SortCycle, SortEvent } from './sort.variants';\nimport type { SortHeaderComponent } from './sort-header.component';\n\nconst DEFAULT_SORT_CYCLE: SortCycle = ['asc', 'desc', undefined];\n\n/**\n * Parent directive that manages sort state for a group of sortable headers.\n *\n * Apply to a container element (e.g., `<tr>`, `<div>`) that contains `[uiSortHeader]` children.\n * Children inject this directive via DI and read its signals directly.\n *\n * @tokens `--color-foreground`, `--color-muted-foreground`\n *\n * @example Basic usage\n * ```html\n * <tr comSort (sortChange)=\"onSort($event)\">\n * <th comSortHeader=\"name\">Name</th>\n * <th comSortHeader=\"age\">Age</th>\n * </tr>\n * ```\n *\n * @example Two-way binding\n * ```html\n * <tr comSort [(sortActive)]=\"column\" [(sortDirection)]=\"direction\">\n * <th comSortHeader=\"name\">Name</th>\n * </tr>\n * ```\n */\n@Directive({\n selector: '[comSort]',\n exportAs: 'comSort',\n host: {\n class: 'contents',\n },\n})\nexport class SortDirective {\n // ─── Inputs ───\n\n /** Currently active sort column id — two-way via model() */\n readonly sortActive: ModelSignal<string | undefined> = model<string | undefined>(undefined);\n\n /** Current sort direction — two-way via model() */\n readonly sortDirection: ModelSignal<SortDirection> = model<SortDirection>(undefined);\n\n /** Disables all sorting in this container */\n readonly sortDisabled: InputSignalWithTransform<boolean, unknown> = input(false, {\n transform: booleanAttribute,\n });\n\n /** Customize the click cycle (e.g., ['asc', 'desc'] to skip unsorted) */\n readonly sortCycle: InputSignal<SortCycle> = input<SortCycle>(DEFAULT_SORT_CYCLE);\n\n /** Show a muted arrow on unsorted headers */\n readonly sortShowIndicator: InputSignalWithTransform<boolean, unknown> = input(false, {\n transform: booleanAttribute,\n });\n\n // ─── Outputs ───\n\n /** Emitted when active column or direction changes */\n readonly sortChange: OutputEmitterRef<SortEvent> = output<SortEvent>();\n\n // ─── Registration ───\n\n private readonly headers: Map<string, SortHeaderComponent> = new Map<string, SortHeaderComponent>();\n\n /** Register a sort header with this parent */\n register(header: SortHeaderComponent): void {\n this.headers.set(header.id(), header);\n }\n\n /** Deregister a sort header */\n deregister(id: string): void {\n this.headers.delete(id);\n }\n\n // ─── Public API ───\n\n /** Programmatically sort by a column */\n sort(id: string): void {\n if (this.sortDisabled()) return;\n\n const cycle = this.sortCycle();\n\n if (this.sortActive() !== id) {\n // New column — start at first direction in cycle\n this.sortActive.set(id);\n this.sortDirection.set(cycle[0]);\n } else {\n // Same column — advance cycle\n const currentIndex = cycle.indexOf(this.sortDirection());\n const nextIndex = (currentIndex + 1) % cycle.length;\n const nextDir = cycle[nextIndex];\n this.sortDirection.set(nextDir);\n\n // If direction is undefined, clear active\n if (nextDir === undefined) {\n this.sortActive.set(undefined);\n }\n }\n\n this.sortChange.emit({\n active: this.sortActive(),\n direction: this.sortDirection(),\n });\n }\n\n /** Returns the next direction in the cycle for a given column */\n getNextDirection(id: string): SortDirection {\n const cycle = this.sortCycle();\n\n if (this.sortActive() !== id) {\n return cycle[0];\n }\n\n const currentIndex = cycle.indexOf(this.sortDirection());\n const nextIndex = (currentIndex + 1) % cycle.length;\n return cycle[nextIndex];\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport type { InputSignal, Signal } from '@angular/core';\nimport { sortIconVariants } from './sort.variants';\nimport type { SortDirection } from './sort.variants';\n\n/**\n * Internal animated SVG arrow indicator for sort headers.\n * Not exported — used only inside SortHeaderComponent.\n *\n * @tokens `--color-foreground`, `--color-muted-foreground`\n */\n@Component({\n selector: 'com-sort-icon',\n template: `\n <span [class]=\"iconClasses()\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"size-full\"\n aria-hidden=\"true\"\n >\n <path d=\"M12 19V5\" />\n <path d=\"M5 12l7-7 7 7\" />\n </svg>\n </span>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SortIconComponent {\n /** Current sort direction */\n readonly direction: InputSignal<SortDirection> = input<SortDirection>(undefined);\n\n /** Whether the column is actively sorted */\n readonly isSorted: InputSignal<boolean> = input(false);\n\n /** Show a muted indicator when not sorted */\n readonly showWhenUnsorted: InputSignal<boolean> = input(false);\n\n /** Compute the icon state for CVA */\n private readonly iconState: Signal<'asc' | 'desc' | 'unsorted' | 'hidden'> = computed(() => {\n if (this.isSorted()) {\n return this.direction() === 'asc' ? 'asc' : 'desc';\n }\n if (this.showWhenUnsorted()) {\n return 'unsorted';\n }\n return 'hidden';\n });\n\n /** CVA-generated classes for the icon container */\n readonly iconClasses: Signal<string> = computed(() =>\n sortIconVariants({\n size: 'md',\n state: this.iconState(),\n })\n );\n}\n","import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n inject,\n input,\n} from '@angular/core';\nimport type {\n InputSignal,\n InputSignalWithTransform,\n OnInit,\n Signal,\n} from '@angular/core';\nimport { SortDirective } from './sort.directive';\nimport { SortIconComponent } from './sort-icon.component';\nimport { sortHeaderVariants } from './sort.variants';\nimport type { SortDirection } from './sort.variants';\n\n/**\n * Sortable header component — child of [uiSort] directive.\n *\n * Apply to table headers, div columns, or any clickable element that should trigger sorting.\n *\n * @tokens `--color-foreground`, `--color-muted-foreground`, `--color-disabled-foreground`\n *\n * @example Basic usage\n * ```html\n * <tr comSort (sortChange)=\"onSort($event)\">\n * <th comSortHeader=\"name\">Name</th>\n * <th comSortHeader=\"age\">Age</th>\n * </tr>\n * ```\n *\n * @example Arrow placement\n * ```html\n * <th comSortHeader=\"name\" comSortHeaderArrowPosition=\"before\">Name</th>\n * ```\n */\n@Component({\n selector: '[comSortHeader]',\n template: `\n @if (sortHeaderArrowPosition() === 'before') {\n <com-sort-icon\n [direction]=\"direction()\"\n [isSorted]=\"isSorted()\"\n [showWhenUnsorted]=\"showUnsortedIndicator()\"\n />\n }\n\n <ng-content />\n\n @if (sortHeaderArrowPosition() === 'after') {\n <com-sort-icon\n [direction]=\"direction()\"\n [isSorted]=\"isSorted()\"\n [showWhenUnsorted]=\"showUnsortedIndicator()\"\n />\n }\n `,\n imports: [SortIconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n '[attr.aria-sort]': 'ariaSort()',\n '[attr.role]': '\"columnheader\"',\n '[attr.tabindex]': 'isDisabled() ? -1 : 0',\n '[attr.aria-disabled]': 'isDisabled() || null',\n '(click)': 'onClick()',\n '(keydown.enter)': 'onClick()',\n '(keydown.space)': '$event.preventDefault(); onClick()',\n },\n})\nexport class SortHeaderComponent implements OnInit {\n private readonly sort: SortDirective | null = inject(SortDirective, { optional: true });\n private readonly destroyRef: DestroyRef = inject(DestroyRef);\n\n // ─── Inputs ───\n\n /** The column id — aliased from the selector */\n readonly id: InputSignal<string> = input.required<string>({ alias: 'comSortHeader' });\n\n /** Disable sorting for this specific header */\n readonly sortHeaderDisabled: InputSignalWithTransform<boolean, unknown> = input(false, {\n transform: booleanAttribute,\n });\n\n /** Override parent's sortShowIndicator for this header */\n readonly sortHeaderShowIndicator: InputSignal<boolean | undefined> = input<boolean | undefined>(\n undefined\n );\n\n /** Arrow placement relative to content */\n readonly sortHeaderArrowPosition: InputSignal<'before' | 'after'> = input<'before' | 'after'>(\n 'after',\n { alias: 'comSortHeaderArrowPosition' }\n );\n\n // ─── Computed State (from parent signals) ───\n\n /** Whether this header is the currently active sort column */\n readonly isActive: Signal<boolean> = computed(() => this.sort?.sortActive() === this.id());\n\n /** Current direction if active, undefined otherwise */\n readonly direction: Signal<SortDirection> = computed(() =>\n this.isActive() ? this.sort?.sortDirection() : undefined\n );\n\n /** Whether this header is sorted (active + has direction) */\n readonly isSorted: Signal<boolean> = computed(\n () => this.isActive() && this.sort?.sortDirection() !== undefined\n );\n\n /** Whether to show the muted indicator when unsorted */\n readonly showUnsortedIndicator: Signal<boolean> = computed(\n () => this.sortHeaderShowIndicator() ?? this.sort?.sortShowIndicator() ?? false\n );\n\n /** Whether sorting is disabled for this header */\n readonly isDisabled: Signal<boolean> = computed(\n () => this.sortHeaderDisabled() || this.sort?.sortDisabled() || false\n );\n\n /** aria-sort attribute value */\n readonly ariaSort: Signal<'ascending' | 'descending' | 'none'> = computed(() => {\n if (!this.isSorted()) return 'none';\n return this.direction() === 'asc' ? 'ascending' : 'descending';\n });\n\n /** CVA-generated host classes */\n readonly hostClasses: Signal<string> = computed(() =>\n sortHeaderVariants({\n sortable: !this.isDisabled(),\n active: this.isSorted(),\n disabled: this.isDisabled(),\n })\n );\n\n constructor() {\n if (!this.sort) {\n throw new Error('comSortHeader must be placed inside a [comSort] container.');\n }\n\n this.destroyRef.onDestroy(() => {\n this.sort?.deregister(this.id());\n });\n }\n\n ngOnInit(): void {\n this.sort!.register(this);\n }\n\n // ─── Event Handlers ───\n\n protected onClick(): void {\n if (this.isDisabled()) return;\n this.sort!.sort(this.id());\n }\n}\n","// Public API for the sort component\n\n// Types & Variants\nexport {\n sortHeaderVariants,\n sortIconVariants,\n type SortDirection,\n type SortCycle,\n type SortEvent,\n} from './sort.variants';\n\n// Directives & Components\nexport { SortDirective } from './sort.directive';\nexport { SortHeaderComponent } from './sort-header.component';\n\n// NOT exported: SortIconComponent (internal)\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAkBA;AAEA;;AAEG;AACI,MAAM,kBAAkB,GAIhB,GAAG,CAChB,CAAC,kCAAkC,EAAE,aAAa,EAAE,gCAAgC,CAAC,EACrF;AACE,IAAA,QAAQ,EAAE;AACR,QAAA,QAAQ,EAAE;AACR,YAAA,IAAI,EAAE,sCAAsC;AAC5C,YAAA,KAAK,EAAE,gBAAgB;AACxB,SAAA;AACD,QAAA,MAAM,EAAE;AACN,YAAA,IAAI,EAAE,iBAAiB;AACvB,YAAA,KAAK,EAAE,uBAAuB;AAC/B,SAAA;AACD,QAAA,QAAQ,EAAE;AACR,YAAA,IAAI,EAAE,iEAAiE;AACvE,YAAA,KAAK,EAAE,EAAE;AACV,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE;AACf,QAAA,QAAQ,EAAE,IAAI;AACd,QAAA,MAAM,EAAE,KAAK;AACb,QAAA,QAAQ,EAAE,KAAK;AAChB,KAAA;AACF,CAAA;AAGH;AAEA;;AAEG;AACI,MAAM,gBAAgB,GAGd,GAAG,CAChB,CAAC,yCAAyC,EAAE,UAAU,EAAE,sCAAsC,CAAC,EAC/F;AACE,IAAA,QAAQ,EAAE;AACR,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,UAAU;AACd,YAAA,EAAE,EAAE,QAAQ;AACb,SAAA;AACD,QAAA,KAAK,EAAE;AACL,YAAA,GAAG,EAAE,sBAAsB;AAC3B,YAAA,IAAI,EAAE,wBAAwB;AAC9B,YAAA,QAAQ,EAAE,qBAAqB;AAC/B,YAAA,MAAM,EAAE,oBAAoB;AAC7B,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE;AACf,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,KAAK,EAAE,QAAQ;AAChB,KAAA;AACF,CAAA;;ACtEH,MAAM,kBAAkB,GAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;AAsBG;MAQU,aAAa,CAAA;;;AAIf,IAAA,UAAU,GAAoC,KAAK,CAAqB,SAAS,sDAAC;;AAGlF,IAAA,aAAa,GAA+B,KAAK,CAAgB,SAAS,yDAAC;;IAG3E,YAAY,GAA+C,KAAK,CAAC,KAAK,yDAC7E,SAAS,EAAE,gBAAgB,EAAA,CAC3B;;AAGO,IAAA,SAAS,GAA2B,KAAK,CAAY,kBAAkB,qDAAC;;IAGxE,iBAAiB,GAA+C,KAAK,CAAC,KAAK,8DAClF,SAAS,EAAE,gBAAgB,EAAA,CAC3B;;;IAKO,UAAU,GAAgC,MAAM,EAAa;;AAIrD,IAAA,OAAO,GAAqC,IAAI,GAAG,EAA+B;;AAGnG,IAAA,QAAQ,CAAC,MAA2B,EAAA;AAClC,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC;IACvC;;AAGA,IAAA,UAAU,CAAC,EAAU,EAAA;AACnB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACzB;;;AAKA,IAAA,IAAI,CAAC,EAAU,EAAA;QACb,IAAI,IAAI,CAAC,YAAY,EAAE;YAAE;AAEzB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;AAE9B,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;;AAE5B,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC;aAAO;;YAEL,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxD,MAAM,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM;AACnD,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC;AAChC,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC;;AAG/B,YAAA,IAAI,OAAO,KAAK,SAAS,EAAE;AACzB,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC;YAChC;QACF;AAEA,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AACnB,YAAA,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE;AACzB,YAAA,SAAS,EAAE,IAAI,CAAC,aAAa,EAAE;AAChC,SAAA,CAAC;IACJ;;AAGA,IAAA,gBAAgB,CAAC,EAAU,EAAA;AACzB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE;AAE9B,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;AAC5B,YAAA,OAAO,KAAK,CAAC,CAAC,CAAC;QACjB;QAEA,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QACxD,MAAM,SAAS,GAAG,CAAC,YAAY,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM;AACnD,QAAA,OAAO,KAAK,CAAC,SAAS,CAAC;IACzB;uGAnFW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAb,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UAAA,EAAA,kBAAA,EAAA,aAAA,EAAA,qBAAA,EAAA,UAAA,EAAA,YAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,UAAA,EAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAb,aAAa,EAAA,UAAA,EAAA,CAAA;kBAPzB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,WAAW;AACrB,oBAAA,QAAQ,EAAE,SAAS;AACnB,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,UAAU;AAClB,qBAAA;AACF,iBAAA;;;ACpCD;;;;;AAKG;MAuBU,iBAAiB,CAAA;;AAEnB,IAAA,SAAS,GAA+B,KAAK,CAAgB,SAAS,qDAAC;;AAGvE,IAAA,QAAQ,GAAyB,KAAK,CAAC,KAAK,oDAAC;;AAG7C,IAAA,gBAAgB,GAAyB,KAAK,CAAC,KAAK,4DAAC;;AAG7C,IAAA,SAAS,GAAmD,QAAQ,CAAC,MAAK;AACzF,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,KAAK,GAAG,KAAK,GAAG,MAAM;QACpD;AACA,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE,EAAE;AAC3B,YAAA,OAAO,UAAU;QACnB;AACA,QAAA,OAAO,QAAQ;AACjB,IAAA,CAAC,qDAAC;;AAGO,IAAA,WAAW,GAAmB,QAAQ,CAAC,MAC9C,gBAAgB,CAAC;AACf,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE;AACxB,KAAA,CAAC,uDACH;uGA3BU,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAjB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,gBAAA,EAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,UAAA,EAAA,kBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EApBlB;;;;;;;;;;;;;;;;;AAiBT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAGU,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAtB7B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,eAAe;AACzB,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;AAiBT,EAAA,CAAA;oBACD,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAChD,iBAAA;;;ACZD;;;;;;;;;;;;;;;;;;;AAmBG;MAmCU,mBAAmB,CAAA;IACb,IAAI,GAAyB,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACtE,IAAA,UAAU,GAAe,MAAM,CAAC,UAAU,CAAC;;;IAKnD,EAAE,GAAwB,KAAK,CAAC,QAAQ,8CAAW,KAAK,EAAE,eAAe,EAAA,CAAG;;IAG5E,kBAAkB,GAA+C,KAAK,CAAC,KAAK,+DACnF,SAAS,EAAE,gBAAgB,EAAA,CAC3B;;AAGO,IAAA,uBAAuB,GAAqC,KAAK,CACxE,SAAS,mEACV;;IAGQ,uBAAuB,GAAoC,KAAK,CACvE,OAAO,oEACL,KAAK,EAAE,4BAA4B,EAAA,CACtC;;;AAKQ,IAAA,QAAQ,GAAoB,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,EAAE,oDAAC;;IAGjF,SAAS,GAA0B,QAAQ,CAAC,MACnD,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,SAAS,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CACzD;;IAGQ,QAAQ,GAAoB,QAAQ,CAC3C,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,SAAS,oDAClE;;IAGQ,qBAAqB,GAAoB,QAAQ,CACxD,MAAM,IAAI,CAAC,uBAAuB,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,KAAK,iEAChF;;IAGQ,UAAU,GAAoB,QAAQ,CAC7C,MAAM,IAAI,CAAC,kBAAkB,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,KAAK,sDACtE;;AAGQ,IAAA,QAAQ,GAAgD,QAAQ,CAAC,MAAK;AAC7E,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,OAAO,MAAM;AACnC,QAAA,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,KAAK,GAAG,WAAW,GAAG,YAAY;AAChE,IAAA,CAAC,oDAAC;;AAGO,IAAA,WAAW,GAAmB,QAAQ,CAAC,MAC9C,kBAAkB,CAAC;AACjB,QAAA,QAAQ,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;AAC5B,QAAA,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE;AACvB,QAAA,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE;AAC5B,KAAA,CAAC,uDACH;AAED,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;AACd,YAAA,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC;QAC/E;AAEA,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;YAC7B,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;AAClC,QAAA,CAAC,CAAC;IACJ;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC3B;;IAIU,OAAO,GAAA;QACf,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE;QACvB,IAAI,CAAC,IAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;IAC5B;uGApFW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,EAAA,EAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,uBAAA,EAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,UAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,uBAAA,EAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,UAAA,EAAA,4BAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,eAAA,EAAA,WAAA,EAAA,eAAA,EAAA,oCAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,WAAA,EAAA,kBAAA,EAAA,eAAA,EAAA,uBAAA,EAAA,oBAAA,EAAA,sBAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhCpB;;;;;;;;;;;;;;;;;;AAkBT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACS,iBAAiB,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,WAAA,EAAA,UAAA,EAAA,kBAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAahB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAlC/B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,iBAAiB;AAC3B,oBAAA,QAAQ,EAAE;;;;;;;;;;;;;;;;;;AAkBT,EAAA,CAAA;oBACD,OAAO,EAAE,CAAC,iBAAiB,CAAC;oBAC5B,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,eAAe;AAC1B,wBAAA,kBAAkB,EAAE,YAAY;AAChC,wBAAA,aAAa,EAAE,gBAAgB;AAC/B,wBAAA,iBAAiB,EAAE,uBAAuB;AAC1C,wBAAA,sBAAsB,EAAE,sBAAsB;AAC9C,wBAAA,SAAS,EAAE,WAAW;AACtB,wBAAA,iBAAiB,EAAE,WAAW;AAC9B,wBAAA,iBAAiB,EAAE,oCAAoC;AACxD,qBAAA;AACF,iBAAA;;;ACzED;AAEA;AAaA;;ACfA;;AAEG;;;;"}