@cdevhub/ngx-tw 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -15
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs +16 -5
- package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs +26 -15
- package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-badge.mjs +17 -5
- package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +27 -6
- package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-button.mjs +23 -11
- package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +5 -5
- package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +3 -3
- package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs +427 -122
- package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-card.mjs +21 -11
- package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs +215 -96
- package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +108 -64
- package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs +18 -6
- package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +55 -30
- package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs +218 -0
- package/fesm2022/cdevhub-ngx-tw-combobox-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs +236 -211
- package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs +200 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +34 -7
- package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-core.mjs +135 -15
- package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs +203 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +160 -102
- package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs +209 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +182 -107
- package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs +122 -0
- package/fesm2022/cdevhub-ngx-tw-dialog-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs +11 -2
- package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs +149 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +57 -67
- package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +42 -24
- package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs +114 -21
- package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-icon.mjs +16 -6
- package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-input.mjs +52 -61
- package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-item.mjs +18 -3
- package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs +168 -0
- package/fesm2022/cdevhub-ngx-tw-menu-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-menu.mjs +58 -21
- package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs +34 -1
- package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs +95 -45
- package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-popover.mjs +81 -32
- package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +1 -1
- package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-radio.mjs +131 -98
- package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +207 -42
- package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs +165 -0
- package/fesm2022/cdevhub-ngx-tw-select-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-select.mjs +386 -210
- package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
- package/fesm2022/{cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs → cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs} +3 -3
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-CqVJwgmp.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs +129 -0
- package/fesm2022/cdevhub-ngx-tw-sheet-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs +23 -7
- package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-slider.mjs +89 -54
- package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-sort.mjs +122 -17
- package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -19
- package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stat.mjs +63 -25
- package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs +35 -8
- package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-switch.mjs +54 -48
- package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +12 -15
- package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-table.mjs +74 -13
- package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs +84 -30
- package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs +172 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +107 -71
- package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs +41 -9
- package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-theme.mjs +257 -45
- package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs +201 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +184 -77
- package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs +110 -27
- package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
- package/fesm2022/{cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs → cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs} +107 -19
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-BlDxemsU.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-toast.mjs +21 -13
- package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +102 -15
- package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs +219 -0
- package/fesm2022/cdevhub-ngx-tw-transfer-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs +88 -69
- package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -1
- package/fesm2022/cdevhub-ngx-tw-tree.mjs +68 -19
- package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -1
- package/index.json +1 -1
- package/package.json +63 -2
- package/theme/_base.css +13 -0
- package/theme/_dark.css +110 -36
- package/theme/_high-contrast-dark.css +367 -0
- package/theme/_high-contrast.css +13 -2
- package/theme/_light.css +276 -0
- package/theme/_semantic.css +47 -12
- package/theme/_typography.css +17 -0
- package/theme/index.css +86 -7
- package/types/cdevhub-ngx-tw-accordion.d.ts +12 -4
- package/types/cdevhub-ngx-tw-avatar.d.ts +10 -3
- package/types/cdevhub-ngx-tw-button.d.ts +1 -0
- package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +2 -2
- package/types/cdevhub-ngx-tw-calendar-testing.d.ts +1 -1
- package/types/cdevhub-ngx-tw-calendar.d.ts +179 -73
- package/types/cdevhub-ngx-tw-card.d.ts +11 -3
- package/types/cdevhub-ngx-tw-carousel.d.ts +89 -20
- package/types/cdevhub-ngx-tw-checkbox.d.ts +40 -12
- package/types/cdevhub-ngx-tw-code-block.d.ts +11 -2
- package/types/cdevhub-ngx-tw-collapsible.d.ts +32 -5
- package/types/cdevhub-ngx-tw-combobox-testing.d.ts +157 -0
- package/types/cdevhub-ngx-tw-combobox.d.ts +94 -53
- package/types/cdevhub-ngx-tw-command-palette-testing.d.ts +136 -0
- package/types/cdevhub-ngx-tw-command-palette.d.ts +33 -5
- package/types/cdevhub-ngx-tw-core.d.ts +152 -21
- package/types/cdevhub-ngx-tw-date-picker-testing.d.ts +141 -0
- package/types/cdevhub-ngx-tw-date-picker.d.ts +37 -29
- package/types/cdevhub-ngx-tw-date-range-picker-testing.d.ts +148 -0
- package/types/cdevhub-ngx-tw-date-range-picker.d.ts +36 -29
- package/types/cdevhub-ngx-tw-dialog-testing.d.ts +98 -0
- package/types/cdevhub-ngx-tw-dialog.d.ts +12 -3
- package/types/cdevhub-ngx-tw-file-upload-testing.d.ts +120 -0
- package/types/cdevhub-ngx-tw-file-upload.d.ts +8 -10
- package/types/cdevhub-ngx-tw-flip-card.d.ts +18 -11
- package/types/cdevhub-ngx-tw-form-field.d.ts +19 -2
- package/types/cdevhub-ngx-tw-icon.d.ts +3 -3
- package/types/cdevhub-ngx-tw-input.d.ts +5 -8
- package/types/cdevhub-ngx-tw-item.d.ts +2 -0
- package/types/cdevhub-ngx-tw-menu-testing.d.ts +131 -0
- package/types/cdevhub-ngx-tw-menu.d.ts +2 -2
- package/types/cdevhub-ngx-tw-number-input.d.ts +20 -0
- package/types/cdevhub-ngx-tw-paginator.d.ts +58 -24
- package/types/cdevhub-ngx-tw-popover.d.ts +41 -10
- package/types/cdevhub-ngx-tw-progress-bar.d.ts +1 -1
- package/types/cdevhub-ngx-tw-radio.d.ts +68 -25
- package/types/cdevhub-ngx-tw-segmented-control.d.ts +79 -16
- package/types/cdevhub-ngx-tw-select-testing.d.ts +114 -0
- package/types/cdevhub-ngx-tw-select.d.ts +104 -33
- package/types/cdevhub-ngx-tw-sheet-testing.d.ts +104 -0
- package/types/cdevhub-ngx-tw-sheet.d.ts +19 -3
- package/types/cdevhub-ngx-tw-slider.d.ts +79 -25
- package/types/cdevhub-ngx-tw-sort.d.ts +45 -4
- package/types/cdevhub-ngx-tw-split.d.ts +32 -2
- package/types/cdevhub-ngx-tw-stat.d.ts +14 -4
- package/types/cdevhub-ngx-tw-stepper.d.ts +16 -2
- package/types/cdevhub-ngx-tw-switch.d.ts +35 -13
- package/types/cdevhub-ngx-tw-tab-nav.d.ts +7 -6
- package/types/cdevhub-ngx-tw-table.d.ts +53 -10
- package/types/cdevhub-ngx-tw-tabs.d.ts +41 -10
- package/types/cdevhub-ngx-tw-tags-input-testing.d.ts +135 -0
- package/types/cdevhub-ngx-tw-tags-input.d.ts +26 -11
- package/types/cdevhub-ngx-tw-textarea.d.ts +3 -2
- package/types/cdevhub-ngx-tw-theme.d.ts +245 -39
- package/types/cdevhub-ngx-tw-time-picker-testing.d.ts +129 -0
- package/types/cdevhub-ngx-tw-time-picker.d.ts +76 -19
- package/types/cdevhub-ngx-tw-timeline.d.ts +36 -12
- package/types/cdevhub-ngx-tw-toast.d.ts +20 -6
- package/types/cdevhub-ngx-tw-tooltip.d.ts +28 -6
- package/types/cdevhub-ngx-tw-transfer-testing.d.ts +152 -0
- package/types/cdevhub-ngx-tw-transfer.d.ts +21 -8
- package/types/cdevhub-ngx-tw-tree.d.ts +6 -1
- package/fesm2022/cdevhub-ngx-tw-sheet-sheet-renderer-ByyNluUd.mjs.map +0 -1
- package/fesm2022/cdevhub-ngx-tw-toast-toast-renderer-DSu4YoTy.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdevhub-ngx-tw-item.mjs","sources":["../../../projects/ngx-tw/item/item.ts","../../../projects/ngx-tw/item/cdevhub-ngx-tw-item.ts"],"sourcesContent":["import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n output,\n type OnInit,\n} from '@angular/core';\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { tv } from 'tailwind-variants';\nimport type { TwSize } from '@cdevhub/ngx-tw/core';\n\n/** Density / typography scale for `tw-item`. A narrower subset of `TwSize` — the three sizes that match real use cases (table row, list item, section header). */\nexport type ItemSize = Extract<TwSize, 'sm' | 'md' | 'lg'>;\n\n/** Vertical alignment of the leading and trailing slots relative to the title/description stack. */\nexport type ItemAlign = 'start' | 'center';\n\nconst itemVariants = tv(\n {\n slots: {\n root: 'flex w-full text-fg',\n // Leading is a layout slot only: `shrink-0` + optional `mt-*` nudge for baseline\n // alignment. No `flex` / `items-*` here — those would conflict with the consumer's\n // own tile styling (e.g. `flex items-center justify-center` on an icon tile).\n leading: 'shrink-0',\n content: 'flex min-w-0 flex-col',\n title: 'text-fg font-medium',\n description: 'text-fg-muted',\n trailing: 'flex shrink-0',\n },\n variants: {\n size: {\n sm: {\n root: 'gap-2 py-1.5',\n content: 'gap-0',\n title: 'text-sm truncate',\n description: 'text-xs truncate',\n trailing: 'gap-1.5',\n },\n md: {\n root: 'gap-3 py-2',\n leading: 'mt-0.5',\n content: 'gap-1',\n title: 'text-sm',\n description: 'text-sm',\n trailing: 'gap-2',\n },\n lg: {\n root: 'gap-3 py-3',\n leading: 'mt-0.5',\n content: 'gap-1',\n title: 'text-base font-semibold',\n description: 'text-sm',\n trailing: 'gap-2',\n },\n },\n align: {\n start: {\n root: 'items-start',\n trailing: 'items-start',\n },\n center: {\n root: 'items-center',\n leading: 'mt-0',\n trailing: 'items-center',\n },\n },\n interactive: {\n true: {\n root: '-mx-2 cursor-pointer rounded-md px-2 transition-colors duration-normal hover:bg-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 motion-reduce:transition-none',\n },\n false: {},\n },\n disabled: {\n true: {\n root: 'pointer-events-none opacity-50',\n },\n false: {},\n },\n current: {\n true: {\n root: 'bg-primary-soft ring-2 ring-inset ring-primary-border',\n },\n false: {},\n },\n },\n compoundVariants: [\n { size: 'sm', align: 'center', class: { leading: 'mt-0', root: 'items-center' } },\n { size: 'md', align: 'center', class: { leading: 'mt-0', root: 'items-center' } },\n { size: 'lg', align: 'center', class: { leading: 'mt-0', root: 'items-center' } },\n ],\n defaultVariants: {\n size: 'md',\n align: 'start',\n interactive: false,\n disabled: false,\n current: false,\n },\n },\n { twMerge: true },\n);\n\n@Component({\n selector: 'tw-item',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'rootClasses()',\n '[attr.role]': 'interactive() ? \"button\" : null',\n '[attr.tabindex]': 'interactive() && !disabled() ? 0 : null',\n '[attr.aria-disabled]': 'disabled() ? \"true\" : null',\n '[attr.aria-current]': 'current() ? \"true\" : null',\n '(click)': 'onActivate($event)',\n '(keydown)': 'onKeydown($event)',\n },\n template: `\n <ng-content select=\"[twItemLeading]\" />\n <div [class]=\"contentClasses()\">\n <ng-content select=\"[twItemTitle]\" />\n <ng-content select=\"[twItemDescription]\" />\n </div>\n <ng-content select=\"[twItemTrailing]\" />\n `,\n})\nexport class ItemComponent implements OnInit {\n /** Density and typography scale. `'sm'` is compact with truncated single-line title and description (table rows). `'md'` is the default list-item size. `'lg'` is the section-header scale with a larger title. Defaults to `'md'`. */\n readonly size = input<ItemSize>('md');\n\n /** Vertical alignment of the leading and trailing slots relative to the content stack. `'start'` aligns them with the title baseline (recommended when a description is present). `'center'` vertically centers them on the whole block (recommended for single-line items). Defaults to `'start'`. */\n readonly align = input<ItemAlign>('start');\n\n /**\n * When `true`, the item is keyboard-activatable: adds `role=\"button\"`, `tabindex=\"0\"`, a hover background, pointer cursor, and a visible focus ring. Click and Enter/Space emit `selected`. Defaults to `false`.\n *\n * Do not project additional focusable elements (buttons, links, inputs) into `[twItemLeading]` or `[twItemTrailing]` when this is `true` — they create nested interactive controls that fail AXE. For action-row patterns, keep `interactive` as `false` and let the projected control carry the semantics instead.\n *\n * For `role=\"menuitem\"`, `role=\"option\"`, or other listbox/menu semantics, do not use `tw-item` — the menu, select, and command-palette components own those roles and the keyboard contracts that come with them.\n */\n readonly interactive = input(false, { transform: booleanAttribute });\n\n /** Disables an interactive item. Applies `opacity-50`, `pointer-events-none`, and sets `aria-disabled`. Only meaningful when `interactive` is `true`. Defaults to `false`. */\n readonly disabled = input(false, { transform: booleanAttribute });\n\n /** When `true`, marks the item as the visually highlighted \"current\" row (e.g. selected list entry, active settings tab). Applies a low-prominence primary tint, an inset ring, and `aria-current=\"true\"`. Stacks cleanly with `interactive` (the focus ring sits on top of the current ring). Defaults to `false`. */\n readonly current = input(false, { transform: booleanAttribute });\n\n /** Fires when an interactive item is activated via click, Enter, or Space. Payload is the originating DOM event. Does not emit when `interactive` is `false` or `disabled` is `true`. */\n readonly selected = output<Event>();\n\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly focusMonitor = inject(FocusMonitor);\n private readonly destroyRef = inject(DestroyRef);\n\n private readonly variantResult = computed(() =>\n itemVariants({\n size: this.size(),\n align: this.align(),\n interactive: this.interactive(),\n disabled: this.disabled(),\n current: this.current(),\n }),\n );\n\n readonly rootClasses = computed(() => this.variantResult().root());\n readonly leadingClasses = computed(() => this.variantResult().leading());\n readonly contentClasses = computed(() => this.variantResult().content());\n readonly titleClasses = computed(() => this.variantResult().title());\n readonly descriptionClasses = computed(() => this.variantResult().description());\n readonly trailingClasses = computed(() => this.variantResult().trailing());\n\n ngOnInit(): void {\n this.focusMonitor.monitor(this.elementRef);\n this.destroyRef.onDestroy(() => {\n this.focusMonitor.stopMonitoring(this.elementRef);\n });\n }\n\n onActivate(event: Event): void {\n if (!this.interactive() || this.disabled()) return;\n this.selected.emit(event);\n }\n\n onKeydown(event: KeyboardEvent): void {\n if (!this.interactive() || this.disabled()) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.selected.emit(event);\n }\n }\n}\n\n@Directive({\n selector: '[twItemLeading]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemLeadingDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.leadingClasses;\n}\n\n@Directive({\n selector: '[twItemTitle]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemTitleDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.titleClasses;\n}\n\n@Directive({\n selector: '[twItemDescription]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemDescriptionDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.descriptionClasses;\n}\n\n@Directive({\n selector: '[twItemTrailing]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemTrailingDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.trailingClasses;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-item.mjs","sources":["../../../projects/ngx-tw/item/item.ts","../../../projects/ngx-tw/item/cdevhub-ngx-tw-item.ts"],"sourcesContent":["import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n output,\n type OnInit,\n} from '@angular/core';\nimport { FocusMonitor } from '@angular/cdk/a11y';\nimport { tv } from 'tailwind-variants';\nimport type { TwSize } from '@cdevhub/ngx-tw/core';\n\n/** Density / typography scale for `tw-item`. A narrower subset of `TwSize` — the three sizes that match real use cases (table row, list item, section header). */\nexport type ItemSize = Extract<TwSize, 'sm' | 'md' | 'lg'>;\n\n/** Vertical alignment of the leading and trailing slots relative to the title/description stack. */\nexport type ItemAlign = 'start' | 'center';\n\nconst itemVariants = tv(\n {\n slots: {\n root: 'flex w-full text-fg',\n // Leading is a layout slot only: `shrink-0` + optional `mt-*` nudge for baseline\n // alignment. No `flex` / `items-*` here — those would conflict with the consumer's\n // own tile styling (e.g. `flex items-center justify-center` on an icon tile).\n leading: 'shrink-0',\n content: 'flex min-w-0 flex-col',\n title: 'text-fg font-medium',\n description: 'text-fg-muted',\n trailing: 'flex shrink-0',\n },\n variants: {\n // `tw-item` is on the `min-h-*` list (docs/vertical-rhythm.md §2), not the\n // pinned one: a title + description is a two-line stack, so the box must\n // stay free to grow. `py-*` is therefore kept exactly as it is.\n //\n // The three-step `ItemSize` axis maps onto the control scale by its own\n // single-line natural height, so each floor binds at the size it belongs\n // to rather than being decorative:\n // sm → 32 (`min-h-8`) — py-1.5 (12) + text-sm line box (20)\n // md → 36 (`min-h-9`) — py-2 (16) + text-sm line box (20)\n // lg → 48 (`min-h-12`) — py-3 (24) + text-base line box (24)\n // The scale's 24px (`xs`) step sits below `tw-item`'s densest row and its\n // 44px (`lg`) step sits below the section-header line box, so both are\n // skipped: `lg` takes the 48px step it already measures.\n size: {\n sm: {\n root: 'gap-2 py-1.5 min-h-8',\n content: 'gap-0',\n title: 'text-sm truncate',\n description: 'text-xs truncate',\n trailing: 'gap-1.5',\n },\n md: {\n root: 'gap-3 py-2 min-h-9',\n leading: 'mt-0.5',\n content: 'gap-1',\n title: 'text-sm',\n description: 'text-sm',\n trailing: 'gap-2',\n },\n lg: {\n root: 'gap-3 py-3 min-h-12',\n leading: 'mt-0.5',\n content: 'gap-1',\n title: 'text-base font-semibold',\n description: 'text-sm',\n trailing: 'gap-2',\n },\n },\n align: {\n start: {\n root: 'items-start',\n trailing: 'items-start',\n },\n center: {\n root: 'items-center',\n leading: 'mt-0',\n trailing: 'items-center',\n },\n },\n interactive: {\n true: {\n root: '-mx-2 cursor-pointer rounded-md px-2 transition-colors duration-normal hover:bg-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 motion-reduce:transition-none',\n },\n false: {},\n },\n disabled: {\n true: {\n root: 'pointer-events-none opacity-50',\n },\n false: {},\n },\n current: {\n true: {\n root: 'bg-primary-soft ring-2 ring-inset ring-primary-border',\n },\n false: {},\n },\n },\n compoundVariants: [\n { size: 'sm', align: 'center', class: { leading: 'mt-0', root: 'items-center' } },\n { size: 'md', align: 'center', class: { leading: 'mt-0', root: 'items-center' } },\n { size: 'lg', align: 'center', class: { leading: 'mt-0', root: 'items-center' } },\n ],\n defaultVariants: {\n size: 'md',\n align: 'start',\n interactive: false,\n disabled: false,\n current: false,\n },\n },\n { twMerge: true },\n);\n\n@Component({\n selector: 'tw-item',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'rootClasses()',\n '[attr.role]': 'interactive() ? \"button\" : null',\n '[attr.tabindex]': 'interactive() && !disabled() ? 0 : null',\n '[attr.aria-disabled]': 'disabled() ? \"true\" : null',\n '[attr.aria-current]': 'current() ? \"true\" : null',\n '(click)': 'onActivate($event)',\n '(keydown)': 'onKeydown($event)',\n },\n template: `\n <ng-content select=\"[twItemLeading]\" />\n <div [class]=\"contentClasses()\">\n <ng-content select=\"[twItemTitle]\" />\n <ng-content select=\"[twItemDescription]\" />\n </div>\n <ng-content select=\"[twItemTrailing]\" />\n `,\n})\nexport class ItemComponent implements OnInit {\n /** Density and typography scale. `'sm'` is compact with truncated single-line title and description (table rows). `'md'` is the default list-item size. `'lg'` is the section-header scale with a larger title. Defaults to `'md'`. */\n readonly size = input<ItemSize>('md');\n\n /** Vertical alignment of the leading and trailing slots relative to the content stack. `'start'` aligns them with the title baseline (recommended when a description is present). `'center'` vertically centers them on the whole block (recommended for single-line items). Defaults to `'start'`. */\n readonly align = input<ItemAlign>('start');\n\n /**\n * When `true`, the item is keyboard-activatable: adds `role=\"button\"`, `tabindex=\"0\"`, a hover background, pointer cursor, and a visible focus ring. Click and Enter/Space emit `selected`. Defaults to `false`.\n *\n * Do not project additional focusable elements (buttons, links, inputs) into `[twItemLeading]` or `[twItemTrailing]` when this is `true` — they create nested interactive controls that fail AXE. For action-row patterns, keep `interactive` as `false` and let the projected control carry the semantics instead.\n *\n * For `role=\"menuitem\"`, `role=\"option\"`, or other listbox/menu semantics, do not use `tw-item` — the menu, select, and command-palette components own those roles and the keyboard contracts that come with them.\n */\n readonly interactive = input(false, { transform: booleanAttribute });\n\n /** Disables an interactive item. Applies `opacity-50`, `pointer-events-none`, and sets `aria-disabled`. Only meaningful when `interactive` is `true`. Defaults to `false`. */\n readonly disabled = input(false, { transform: booleanAttribute });\n\n /** When `true`, marks the item as the visually highlighted \"current\" row (e.g. selected list entry, active settings tab). Applies a low-prominence primary tint, an inset ring, and `aria-current=\"true\"`. Stacks cleanly with `interactive` (the focus ring sits on top of the current ring). Defaults to `false`. */\n readonly current = input(false, { transform: booleanAttribute });\n\n /** Fires when an interactive item is activated via click, Enter, or Space. Payload is the originating DOM event. Does not emit when `interactive` is `false` or `disabled` is `true`. */\n readonly selected = output<Event>();\n\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly focusMonitor = inject(FocusMonitor);\n private readonly destroyRef = inject(DestroyRef);\n\n private readonly variantResult = computed(() =>\n itemVariants({\n size: this.size(),\n align: this.align(),\n interactive: this.interactive(),\n disabled: this.disabled(),\n current: this.current(),\n }),\n );\n\n readonly rootClasses = computed(() => this.variantResult().root());\n readonly leadingClasses = computed(() => this.variantResult().leading());\n readonly contentClasses = computed(() => this.variantResult().content());\n readonly titleClasses = computed(() => this.variantResult().title());\n readonly descriptionClasses = computed(() => this.variantResult().description());\n readonly trailingClasses = computed(() => this.variantResult().trailing());\n\n ngOnInit(): void {\n this.focusMonitor.monitor(this.elementRef);\n this.destroyRef.onDestroy(() => {\n this.focusMonitor.stopMonitoring(this.elementRef);\n });\n }\n\n /** @internal Emits `selected` on click when the item is interactive and enabled. */\n onActivate(event: Event): void {\n if (!this.interactive() || this.disabled()) return;\n this.selected.emit(event);\n }\n\n /** @internal Emits `selected` on Enter/Space when the item is interactive and enabled. */\n onKeydown(event: KeyboardEvent): void {\n if (!this.interactive() || this.disabled()) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.selected.emit(event);\n }\n }\n}\n\n@Directive({\n selector: '[twItemLeading]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemLeadingDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.leadingClasses;\n}\n\n@Directive({\n selector: '[twItemTitle]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemTitleDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.titleClasses;\n}\n\n@Directive({\n selector: '[twItemDescription]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemDescriptionDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.descriptionClasses;\n}\n\n@Directive({\n selector: '[twItemTrailing]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class ItemTrailingDirective {\n private readonly item = inject(ItemComponent);\n readonly classes = this.item.trailingClasses;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Harness for a single item inside an open `tw-menu` panel.
|
|
5
|
+
*
|
|
6
|
+
* Hosts on the ARIA role rather than on the `twMenuItem*` attribute selectors,
|
|
7
|
+
* so one harness covers plain items, checkbox items and radio items — the roles
|
|
8
|
+
* are contributed by the CDK directives `tw-menu` composes and are the same
|
|
9
|
+
* thing assistive technology reads.
|
|
10
|
+
*
|
|
11
|
+
* Items render into the CDK overlay, not inside the trigger, so they are reached
|
|
12
|
+
* through {@link MenuHarness} rather than located directly against a fixture.
|
|
13
|
+
*/
|
|
14
|
+
class MenuItemHarness extends ComponentHarness {
|
|
15
|
+
static hostSelector = '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]';
|
|
16
|
+
/** Predicate for `locatorFor` / `locatorForAll`. */
|
|
17
|
+
static with(options = {}) {
|
|
18
|
+
return new HarnessPredicate(MenuItemHarness, options)
|
|
19
|
+
.addOption('text', options.text, async (h, text) => HarnessPredicate.stringMatches(await h.getText(), text))
|
|
20
|
+
.addOption('disabled', options.disabled, async (h, disabled) => (await h.isDisabled()) === disabled)
|
|
21
|
+
.addOption('checked', options.checked, async (h, checked) => (await h.isChecked()) === checked);
|
|
22
|
+
}
|
|
23
|
+
/** The item's rendered text, trimmed. Includes any projected description or shortcut text. */
|
|
24
|
+
async getText() {
|
|
25
|
+
return (await (await this.host()).text()).trim();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The item's ARIA role — `'menuitem'`, `'menuitemcheckbox'` or
|
|
29
|
+
* `'menuitemradio'`. Lets a test tell the three kinds apart.
|
|
30
|
+
*/
|
|
31
|
+
async getRole() {
|
|
32
|
+
return (await this.host()).getAttribute('role');
|
|
33
|
+
}
|
|
34
|
+
/** Whether the item reports `aria-disabled="true"`. */
|
|
35
|
+
async isDisabled() {
|
|
36
|
+
return (await (await this.host()).getAttribute('aria-disabled')) === 'true';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Checked state of a checkbox or radio item, or `null` for a plain item,
|
|
40
|
+
* which carries no `aria-checked` at all.
|
|
41
|
+
*/
|
|
42
|
+
async isChecked() {
|
|
43
|
+
const checked = await (await this.host()).getAttribute('aria-checked');
|
|
44
|
+
return checked === null ? null : checked === 'true';
|
|
45
|
+
}
|
|
46
|
+
/** Clicks the item. A disabled item ignores the click, as in the browser. */
|
|
47
|
+
async click() {
|
|
48
|
+
await (await this.host()).click();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Harness for a `[twMenuTrigger]` and the `tw-menu` panel it opens.
|
|
54
|
+
*
|
|
55
|
+
* ## Why this is a parallel harness and not a delegating one
|
|
56
|
+
*
|
|
57
|
+
* `tw-menu` composes `CdkMenu` / `CdkMenuItem` through `hostDirectives`, so a
|
|
58
|
+
* thin harness delegating to a CDK one would be preferable — except that
|
|
59
|
+
* `@angular/cdk` ships **no component harnesses at all**. Its only testing
|
|
60
|
+
* entry points are `@angular/cdk/testing`, `@angular/cdk/testing/testbed` and
|
|
61
|
+
* `@angular/cdk/testing/selenium-webdriver`, all of which are harness
|
|
62
|
+
* *infrastructure*; the component harnesses live in `@angular/material/*\/testing`,
|
|
63
|
+
* and `@angular/material` is not a dependency of this library. There is nothing
|
|
64
|
+
* to delegate to. What composition does buy us is that the locators below are
|
|
65
|
+
* ARIA roles and attributes CDK guarantees (`role="menuitem"`,
|
|
66
|
+
* `aria-expanded`, `aria-controls`), not ngx-tw class names.
|
|
67
|
+
*
|
|
68
|
+
* ## Why the host selector is not `[twMenuTrigger]`
|
|
69
|
+
*
|
|
70
|
+
* `twMenuTrigger` takes a required `TemplateRef`, so it is always written as a
|
|
71
|
+
* property binding — `[twMenuTrigger]="menu"` — and Angular renders **no
|
|
72
|
+
* attribute** for a bound input. `[twMenuTrigger]` therefore matches nothing in
|
|
73
|
+
* the DOM. `MenuTriggerDirective` adds no host class or attribute of its own
|
|
74
|
+
* (contrast Material, whose `MatMenuTrigger` adds `.mat-mdc-menu-trigger`
|
|
75
|
+
* precisely so its harness can find it), so the only durable marker is the one
|
|
76
|
+
* CDK contributes: `aria-haspopup="menu"`, bound unconditionally by
|
|
77
|
+
* `CdkMenuTrigger` whenever it has a template. Nothing else in ngx-tw renders
|
|
78
|
+
* that value — `[twContextMenuTrigger]` deliberately renders none — so the match
|
|
79
|
+
* is exact today. If `MenuTriggerDirective` ever grows a host marker, widening
|
|
80
|
+
* this selector to it is a non-breaking change.
|
|
81
|
+
*
|
|
82
|
+
* ## Loading it
|
|
83
|
+
*
|
|
84
|
+
* The host is the trigger, which lives in the fixture, so the ordinary
|
|
85
|
+
* `TestbedHarnessEnvironment.loader(fixture)` is correct. The panel renders into
|
|
86
|
+
* the CDK overlay container outside the fixture, and this harness resolves it
|
|
87
|
+
* internally via `documentRootLocatorFactory()` — a consumer never needs
|
|
88
|
+
* `documentRootLoader`.
|
|
89
|
+
*
|
|
90
|
+
* The panel is located by the id in the trigger's `aria-controls`, so a fixture
|
|
91
|
+
* holding several menus (or an open submenu) still resolves each trigger to its
|
|
92
|
+
* own panel.
|
|
93
|
+
*
|
|
94
|
+
* Only `[twMenuTrigger]` is covered. `[twContextMenuTrigger]` opens on a
|
|
95
|
+
* `contextmenu` event at pointer coordinates and exposes neither `aria-expanded`
|
|
96
|
+
* nor `aria-haspopup`; it is deliberately out of scope.
|
|
97
|
+
*/
|
|
98
|
+
class MenuHarness extends ComponentHarness {
|
|
99
|
+
static hostSelector = '[aria-haspopup="menu"]';
|
|
100
|
+
/** Predicate for `locatorFor` / `locatorForAll`. */
|
|
101
|
+
static with(options = {}) {
|
|
102
|
+
return new HarnessPredicate(MenuHarness, options).addOption('triggerText', options.triggerText, async (h, text) => HarnessPredicate.stringMatches(await h.getTriggerText(), text));
|
|
103
|
+
}
|
|
104
|
+
/** The text currently rendered in the trigger, trimmed. */
|
|
105
|
+
async getTriggerText() {
|
|
106
|
+
return (await (await this.host()).text()).trim();
|
|
107
|
+
}
|
|
108
|
+
/** Whether the menu is open, read from the trigger's `aria-expanded`. */
|
|
109
|
+
async isOpen() {
|
|
110
|
+
return (await (await this.host()).getAttribute('aria-expanded')) === 'true';
|
|
111
|
+
}
|
|
112
|
+
/** Opens the menu by clicking the trigger. No-op when already open. */
|
|
113
|
+
async open() {
|
|
114
|
+
if (await this.isOpen())
|
|
115
|
+
return;
|
|
116
|
+
await (await this.host()).click();
|
|
117
|
+
}
|
|
118
|
+
/** Closes the menu by clicking the trigger again. No-op when already closed. */
|
|
119
|
+
async close() {
|
|
120
|
+
if (!(await this.isOpen()))
|
|
121
|
+
return;
|
|
122
|
+
await (await this.host()).click();
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Every item in the open panel — plain, checkbox and radio alike. Returns an
|
|
126
|
+
* empty array when the menu is closed, because CDK removes the panel from the
|
|
127
|
+
* DOM rather than hiding it.
|
|
128
|
+
*/
|
|
129
|
+
async getItems(filters = {}) {
|
|
130
|
+
const panel = await this.getPanelLoader();
|
|
131
|
+
if (!panel)
|
|
132
|
+
return [];
|
|
133
|
+
return panel.getAllHarnesses(MenuItemHarness.with(filters));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Opens the menu if needed and clicks the first item whose text matches.
|
|
137
|
+
* Throws when nothing matches, rather than failing silently.
|
|
138
|
+
*
|
|
139
|
+
* CDK closes the menu when an item is activated, so a `getItems()` chained
|
|
140
|
+
* after this returns an empty array — call {@link open} again before
|
|
141
|
+
* re-reading item state.
|
|
142
|
+
*/
|
|
143
|
+
async clickItem(text) {
|
|
144
|
+
await this.open();
|
|
145
|
+
const matches = await this.getItems({ text });
|
|
146
|
+
if (matches.length === 0) {
|
|
147
|
+
throw new Error(`MenuHarness.clickItem: no item matching ${String(text)}.`);
|
|
148
|
+
}
|
|
149
|
+
await matches[0].click();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A loader rooted at this trigger's own panel, or `null` when the menu is
|
|
153
|
+
* closed. Scoping by `aria-controls` keeps sibling menus and submenus apart.
|
|
154
|
+
*/
|
|
155
|
+
async getPanelLoader() {
|
|
156
|
+
const id = await (await this.host()).getAttribute('aria-controls');
|
|
157
|
+
if (!id)
|
|
158
|
+
return null;
|
|
159
|
+
return this.documentRootLocatorFactory().harnessLoaderForOptional(`#${id}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Generated bundle index. Do not edit.
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
export { MenuHarness, MenuItemHarness };
|
|
168
|
+
//# sourceMappingURL=cdevhub-ngx-tw-menu-testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-menu-testing.mjs","sources":["../../../projects/ngx-tw/menu/testing/menu-item-harness.ts","../../../projects/ngx-tw/menu/testing/menu-harness.ts","../../../projects/ngx-tw/menu/testing/cdevhub-ngx-tw-menu-testing.ts"],"sourcesContent":["import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\nimport type { BaseHarnessFilters } from '@angular/cdk/testing';\n\n/** Filters accepted by `MenuItemHarness.with`. */\nexport interface MenuItemHarnessFilters extends BaseHarnessFilters {\n /** Match by the item's visible text. */\n text?: string | RegExp;\n /** Match disabled / enabled items. */\n disabled?: boolean;\n /** Match checked / unchecked checkbox and radio items. Never matches a plain item. */\n checked?: boolean;\n}\n\n/**\n * Harness for a single item inside an open `tw-menu` panel.\n *\n * Hosts on the ARIA role rather than on the `twMenuItem*` attribute selectors,\n * so one harness covers plain items, checkbox items and radio items — the roles\n * are contributed by the CDK directives `tw-menu` composes and are the same\n * thing assistive technology reads.\n *\n * Items render into the CDK overlay, not inside the trigger, so they are reached\n * through {@link MenuHarness} rather than located directly against a fixture.\n */\nexport class MenuItemHarness extends ComponentHarness {\n static hostSelector =\n '[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"]';\n\n /** Predicate for `locatorFor` / `locatorForAll`. */\n static with(\n options: MenuItemHarnessFilters = {},\n ): HarnessPredicate<MenuItemHarness> {\n return new HarnessPredicate(MenuItemHarness, options)\n .addOption('text', options.text, async (h, text) =>\n HarnessPredicate.stringMatches(await h.getText(), text),\n )\n .addOption(\n 'disabled',\n options.disabled,\n async (h, disabled) => (await h.isDisabled()) === disabled,\n )\n .addOption(\n 'checked',\n options.checked,\n async (h, checked) => (await h.isChecked()) === checked,\n );\n }\n\n /** The item's rendered text, trimmed. Includes any projected description or shortcut text. */\n async getText(): Promise<string> {\n return (await (await this.host()).text()).trim();\n }\n\n /**\n * The item's ARIA role — `'menuitem'`, `'menuitemcheckbox'` or\n * `'menuitemradio'`. Lets a test tell the three kinds apart.\n */\n async getRole(): Promise<string | null> {\n return (await this.host()).getAttribute('role');\n }\n\n /** Whether the item reports `aria-disabled=\"true\"`. */\n async isDisabled(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-disabled')) === 'true';\n }\n\n /**\n * Checked state of a checkbox or radio item, or `null` for a plain item,\n * which carries no `aria-checked` at all.\n */\n async isChecked(): Promise<boolean | null> {\n const checked = await (await this.host()).getAttribute('aria-checked');\n return checked === null ? null : checked === 'true';\n }\n\n /** Clicks the item. A disabled item ignores the click, as in the browser. */\n async click(): Promise<void> {\n await (await this.host()).click();\n }\n}\n","import { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\nimport type { BaseHarnessFilters, HarnessLoader } from '@angular/cdk/testing';\nimport {\n MenuItemHarness,\n type MenuItemHarnessFilters,\n} from './menu-item-harness';\n\n/** Filters accepted by `MenuHarness.with`. */\nexport interface MenuHarnessFilters extends BaseHarnessFilters {\n /** Match by the text rendered in the trigger. */\n triggerText?: string | RegExp;\n}\n\n/**\n * Harness for a `[twMenuTrigger]` and the `tw-menu` panel it opens.\n *\n * ## Why this is a parallel harness and not a delegating one\n *\n * `tw-menu` composes `CdkMenu` / `CdkMenuItem` through `hostDirectives`, so a\n * thin harness delegating to a CDK one would be preferable — except that\n * `@angular/cdk` ships **no component harnesses at all**. Its only testing\n * entry points are `@angular/cdk/testing`, `@angular/cdk/testing/testbed` and\n * `@angular/cdk/testing/selenium-webdriver`, all of which are harness\n * *infrastructure*; the component harnesses live in `@angular/material/*\\/testing`,\n * and `@angular/material` is not a dependency of this library. There is nothing\n * to delegate to. What composition does buy us is that the locators below are\n * ARIA roles and attributes CDK guarantees (`role=\"menuitem\"`,\n * `aria-expanded`, `aria-controls`), not ngx-tw class names.\n *\n * ## Why the host selector is not `[twMenuTrigger]`\n *\n * `twMenuTrigger` takes a required `TemplateRef`, so it is always written as a\n * property binding — `[twMenuTrigger]=\"menu\"` — and Angular renders **no\n * attribute** for a bound input. `[twMenuTrigger]` therefore matches nothing in\n * the DOM. `MenuTriggerDirective` adds no host class or attribute of its own\n * (contrast Material, whose `MatMenuTrigger` adds `.mat-mdc-menu-trigger`\n * precisely so its harness can find it), so the only durable marker is the one\n * CDK contributes: `aria-haspopup=\"menu\"`, bound unconditionally by\n * `CdkMenuTrigger` whenever it has a template. Nothing else in ngx-tw renders\n * that value — `[twContextMenuTrigger]` deliberately renders none — so the match\n * is exact today. If `MenuTriggerDirective` ever grows a host marker, widening\n * this selector to it is a non-breaking change.\n *\n * ## Loading it\n *\n * The host is the trigger, which lives in the fixture, so the ordinary\n * `TestbedHarnessEnvironment.loader(fixture)` is correct. The panel renders into\n * the CDK overlay container outside the fixture, and this harness resolves it\n * internally via `documentRootLocatorFactory()` — a consumer never needs\n * `documentRootLoader`.\n *\n * The panel is located by the id in the trigger's `aria-controls`, so a fixture\n * holding several menus (or an open submenu) still resolves each trigger to its\n * own panel.\n *\n * Only `[twMenuTrigger]` is covered. `[twContextMenuTrigger]` opens on a\n * `contextmenu` event at pointer coordinates and exposes neither `aria-expanded`\n * nor `aria-haspopup`; it is deliberately out of scope.\n */\nexport class MenuHarness extends ComponentHarness {\n static hostSelector = '[aria-haspopup=\"menu\"]';\n\n /** Predicate for `locatorFor` / `locatorForAll`. */\n static with(options: MenuHarnessFilters = {}): HarnessPredicate<MenuHarness> {\n return new HarnessPredicate(MenuHarness, options).addOption(\n 'triggerText',\n options.triggerText,\n async (h, text) => HarnessPredicate.stringMatches(await h.getTriggerText(), text),\n );\n }\n\n /** The text currently rendered in the trigger, trimmed. */\n async getTriggerText(): Promise<string> {\n return (await (await this.host()).text()).trim();\n }\n\n /** Whether the menu is open, read from the trigger's `aria-expanded`. */\n async isOpen(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-expanded')) === 'true';\n }\n\n /** Opens the menu by clicking the trigger. No-op when already open. */\n async open(): Promise<void> {\n if (await this.isOpen()) return;\n await (await this.host()).click();\n }\n\n /** Closes the menu by clicking the trigger again. No-op when already closed. */\n async close(): Promise<void> {\n if (!(await this.isOpen())) return;\n await (await this.host()).click();\n }\n\n /**\n * Every item in the open panel — plain, checkbox and radio alike. Returns an\n * empty array when the menu is closed, because CDK removes the panel from the\n * DOM rather than hiding it.\n */\n async getItems(\n filters: MenuItemHarnessFilters = {},\n ): Promise<MenuItemHarness[]> {\n const panel = await this.getPanelLoader();\n if (!panel) return [];\n return panel.getAllHarnesses(MenuItemHarness.with(filters));\n }\n\n /**\n * Opens the menu if needed and clicks the first item whose text matches.\n * Throws when nothing matches, rather than failing silently.\n *\n * CDK closes the menu when an item is activated, so a `getItems()` chained\n * after this returns an empty array — call {@link open} again before\n * re-reading item state.\n */\n async clickItem(text: string | RegExp): Promise<void> {\n await this.open();\n const matches = await this.getItems({ text });\n if (matches.length === 0) {\n throw new Error(`MenuHarness.clickItem: no item matching ${String(text)}.`);\n }\n await matches[0].click();\n }\n\n /**\n * A loader rooted at this trigger's own panel, or `null` when the menu is\n * closed. Scoping by `aria-controls` keeps sibling menus and submenus apart.\n */\n private async getPanelLoader(): Promise<HarnessLoader | null> {\n const id = await (await this.host()).getAttribute('aria-controls');\n if (!id) return null;\n return this.documentRootLocatorFactory().harnessLoaderForOptional(`#${id}`);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;AAaA;;;;;;;;;;AAUG;AACG,MAAO,eAAgB,SAAQ,gBAAgB,CAAA;AACnD,IAAA,OAAO,YAAY,GACjB,sEAAsE;;AAGxE,IAAA,OAAO,IAAI,CACT,OAAA,GAAkC,EAAE,EAAA;AAEpC,QAAA,OAAO,IAAI,gBAAgB,CAAC,eAAe,EAAE,OAAO;aACjD,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,IAAI,KAC7C,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC;aAExD,SAAS,CACR,UAAU,EACV,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,EAAE,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,QAAQ;aAE3D,SAAS,CACR,SAAS,EACT,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,MAAM,OAAO,CACxD;IACL;;AAGA,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE;IAClD;AAEA;;;AAGG;AACH,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC;IACjD;;AAGA,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC7E;AAEA;;;AAGG;AACH,IAAA,MAAM,SAAS,GAAA;AACb,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,cAAc,CAAC;AACtE,QAAA,OAAO,OAAO,KAAK,IAAI,GAAG,IAAI,GAAG,OAAO,KAAK,MAAM;IACrD;;AAGA,IAAA,MAAM,KAAK,GAAA;QACT,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACnC;;;ACjEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;AACG,MAAO,WAAY,SAAQ,gBAAgB,CAAA;AAC/C,IAAA,OAAO,YAAY,GAAG,wBAAwB;;AAG9C,IAAA,OAAO,IAAI,CAAC,OAAA,GAA8B,EAAE,EAAA;AAC1C,QAAA,OAAO,IAAI,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,SAAS,CACzD,aAAa,EACb,OAAO,CAAC,WAAW,EACnB,OAAO,CAAC,EAAE,IAAI,KAAK,gBAAgB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,CAClF;IACH;;AAGA,IAAA,MAAM,cAAc,GAAA;AAClB,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE;IAClD;;AAGA,IAAA,MAAM,MAAM,GAAA;AACV,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC,MAAM,MAAM;IAC7E;;AAGA,IAAA,MAAM,IAAI,GAAA;AACR,QAAA,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE;YAAE;QACzB,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACnC;;AAGA,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,IAAI,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;YAAE;QAC5B,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACnC;AAEA;;;;AAIG;AACH,IAAA,MAAM,QAAQ,CACZ,OAAA,GAAkC,EAAE,EAAA;AAEpC,QAAA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE;AACzC,QAAA,IAAI,CAAC,KAAK;AAAE,YAAA,OAAO,EAAE;QACrB,OAAO,KAAK,CAAC,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7D;AAEA;;;;;;;AAOG;IACH,MAAM,SAAS,CAAC,IAAqB,EAAA;AACnC,QAAA,MAAM,IAAI,CAAC,IAAI,EAAE;QACjB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;AAC7C,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;YACxB,MAAM,IAAI,KAAK,CAAC,CAAA,wCAAA,EAA2C,MAAM,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC;QAC7E;AACA,QAAA,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;IAC1B;AAEA;;;AAGG;AACK,IAAA,MAAM,cAAc,GAAA;AAC1B,QAAA,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,eAAe,CAAC;AAClE,QAAA,IAAI,CAAC,EAAE;AAAE,YAAA,OAAO,IAAI;QACpB,OAAO,IAAI,CAAC,0BAA0B,EAAE,CAAC,wBAAwB,CAAC,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC;IAC7E;;;ACnIF;;AAEG;;;;"}
|
|
@@ -29,12 +29,18 @@ const menuVariants = tv({
|
|
|
29
29
|
const menuItemVariants = tv({
|
|
30
30
|
base: 'relative flex w-full flex-wrap items-center gap-2 rounded-md cursor-pointer select-none transition-colors duration-normal motion-reduce:transition-none text-fg outline-none focus-visible:bg-surface-muted hover:bg-surface-muted',
|
|
31
31
|
variants: {
|
|
32
|
+
// Menu rows are on the `min-h-*` list (docs/vertical-rhythm.md §2), not
|
|
33
|
+
// the pinned one: `[twMenuItemDescription]` wraps onto a second line via
|
|
34
|
+
// `basis-full`, so the box must stay free to grow. The floor lands on the
|
|
35
|
+
// control scale (24 / 32 / 36 / 44 / 48) and `py-*` is kept exactly as it
|
|
36
|
+
// was — it sets the breathing room around a wrapped two-line row, where
|
|
37
|
+
// the floor no longer binds.
|
|
32
38
|
size: {
|
|
33
|
-
xs: 'px-1.5 py-0.5 text-xs',
|
|
34
|
-
sm: 'px-2 py-1 text-xs',
|
|
35
|
-
md: 'px-3 py-1.5 text-sm',
|
|
36
|
-
lg: 'px-4 py-2 text-sm',
|
|
37
|
-
xl: 'px-5 py-2.5 text-base',
|
|
39
|
+
xs: 'px-1.5 py-0.5 text-xs min-h-6',
|
|
40
|
+
sm: 'px-2 py-1 text-xs min-h-8',
|
|
41
|
+
md: 'px-3 py-1.5 text-sm min-h-9',
|
|
42
|
+
lg: 'px-4 py-2 text-sm min-h-11',
|
|
43
|
+
xl: 'px-5 py-2.5 text-base min-h-12',
|
|
38
44
|
},
|
|
39
45
|
// Slot tokens own light/dark contrast — no `dark:`, no shade picks.
|
|
40
46
|
// `undefined` (the default) leaves the base text-fg styling untouched.
|
|
@@ -59,44 +65,66 @@ const menuItemVariants = tv({
|
|
|
59
65
|
},
|
|
60
66
|
defaultVariants: { size: 'md', disabled: false },
|
|
61
67
|
}, { twMerge: true });
|
|
68
|
+
// Leading icon on a menu item. Follows CLAUDE.md "Icon Sizing" → glyph
|
|
69
|
+
// sub-scale, saturating at `lg`: 3 / 4 / 5 / 6 / 6. Previously 4/4/4/5/5,
|
|
70
|
+
// which collapsed xs/sm/md onto one value and left `xl` indistinguishable
|
|
71
|
+
// from `lg`.
|
|
72
|
+
//
|
|
73
|
+
// `xl` deliberately reuses `size-6` rather than the glyph scale's `size-8`.
|
|
74
|
+
// Menu rows are `flex items-center` on a `min-h-*` floor (see the size ramp
|
|
75
|
+
// above and docs/vertical-rhythm.md §2). At `xl` a 32px glyph plus `py-2.5`
|
|
76
|
+
// (20px) measures 52px against a `min-h-12` floor of 48px, so the floor
|
|
77
|
+
// stops binding — and only for rows that project a glyph, so an `xl` menu
|
|
78
|
+
// would render 52px and 48px rows side by side. Every other step still
|
|
79
|
+
// binds (xs 16<24, sm 24<32, md 32<36, lg 40<44). This is the same
|
|
80
|
+
// saturation CLAUDE.md already codifies for the square-interactive scale,
|
|
81
|
+
// where the breadcrumb overflow trigger reuses `size-9` at both `lg` and
|
|
82
|
+
// `xl`. Raising `xl` here means raising the row floor to match.
|
|
62
83
|
const menuItemIconVariants = tv({
|
|
63
84
|
base: 'shrink-0 text-fg-muted',
|
|
64
85
|
variants: {
|
|
65
86
|
size: {
|
|
66
|
-
xs: 'size-
|
|
87
|
+
xs: 'size-3',
|
|
67
88
|
sm: 'size-4',
|
|
68
|
-
md: 'size-
|
|
69
|
-
lg: 'size-
|
|
70
|
-
xl: 'size-
|
|
89
|
+
md: 'size-5',
|
|
90
|
+
lg: 'size-6',
|
|
91
|
+
xl: 'size-6',
|
|
71
92
|
},
|
|
72
93
|
},
|
|
73
94
|
defaultVariants: { size: 'md' },
|
|
74
95
|
}, { twMerge: true });
|
|
96
|
+
// Selection marker (check / radio dot wrapper). This is the box the glyph is
|
|
97
|
+
// centred in, so it rides the same glyph sub-scale as the leading icon —
|
|
98
|
+
// otherwise the check and the icon on adjacent items sit on different scales.
|
|
99
|
+
// Previously 4/4/4/5/5.
|
|
75
100
|
const menuItemIndicatorVariants = tv({
|
|
76
101
|
base: 'shrink-0 flex items-center justify-center',
|
|
77
102
|
variants: {
|
|
78
103
|
size: {
|
|
79
|
-
xs: 'size-
|
|
104
|
+
xs: 'size-3',
|
|
80
105
|
sm: 'size-4',
|
|
81
|
-
md: 'size-
|
|
82
|
-
lg: 'size-
|
|
83
|
-
xl: 'size-
|
|
106
|
+
md: 'size-5',
|
|
107
|
+
lg: 'size-6',
|
|
108
|
+
xl: 'size-6',
|
|
84
109
|
},
|
|
85
110
|
},
|
|
86
111
|
defaultVariants: { size: 'md' },
|
|
87
112
|
}, { twMerge: true });
|
|
88
113
|
// Submenu indicator (trailing chevron). Keeps the `ml-auto pl-2` layout intent
|
|
89
|
-
// separate from the leading-icon scale
|
|
90
|
-
// CLAUDE.md "Icon Sizing"
|
|
114
|
+
// separate from the leading-icon scale, but the size axis is the same
|
|
115
|
+
// CLAUDE.md "Icon Sizing" glyph sub-scale (3/4/5/6/8) the other two menu
|
|
116
|
+
// glyph ramps use, so the chevron tracks the parent menu's density and every
|
|
117
|
+
// step is visually distinct. Previously 3/4/4/5/5, which duplicated `sm`→`md`
|
|
118
|
+
// and `lg`→`xl`.
|
|
91
119
|
const menuItemSubmenuIndicatorVariants = tv({
|
|
92
120
|
base: 'ml-auto pl-2 shrink-0 text-fg-muted',
|
|
93
121
|
variants: {
|
|
94
122
|
size: {
|
|
95
123
|
xs: 'size-3',
|
|
96
124
|
sm: 'size-4',
|
|
97
|
-
md: 'size-
|
|
98
|
-
lg: 'size-
|
|
99
|
-
xl: 'size-
|
|
125
|
+
md: 'size-5',
|
|
126
|
+
lg: 'size-6',
|
|
127
|
+
xl: 'size-6',
|
|
100
128
|
},
|
|
101
129
|
},
|
|
102
130
|
defaultVariants: { size: 'md' },
|
|
@@ -106,9 +134,9 @@ class MenuComponent {
|
|
|
106
134
|
/** Controls item density and padding. Defaults to `'md'`. */
|
|
107
135
|
size = input('md', /* @ts-ignore */
|
|
108
136
|
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
109
|
-
/** Accessible label for the menu panel. Use when no visible heading describes the menu (e.g. a kebab-icon trigger). */
|
|
137
|
+
/** Accessible label for the menu panel. Use when no visible heading describes the menu (e.g. a kebab-icon trigger). Defaults to `undefined`. Alias: `aria-label`. */
|
|
110
138
|
ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
|
|
111
|
-
/** ID of an element that labels the menu panel. Ignored when `ariaLabel` is set. */
|
|
139
|
+
/** ID of an element that labels the menu panel. Ignored when `ariaLabel` is set. Defaults to `undefined`. Alias: `aria-labelledby`. */
|
|
112
140
|
ariaLabelledBy = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabelledBy" } : /* istanbul ignore next */ {}), alias: 'aria-labelledby' });
|
|
113
141
|
classes = computed(() => menuVariants({ size: this.size() }), /* @ts-ignore */
|
|
114
142
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
@@ -139,7 +167,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
139
167
|
// ── MenuTriggerDirective ──
|
|
140
168
|
class MenuTriggerDirective {
|
|
141
169
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MenuTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
142
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: MenuTriggerDirective, isStandalone: true, selector: "[twMenuTrigger]", hostDirectives: [{ directive: i1.CdkMenuTrigger, inputs: ["cdkMenuTriggerFor", "twMenuTrigger", "cdkMenuPosition", "position", "cdkMenuTriggerData", "data"], outputs: ["cdkMenuOpened", "opened", "cdkMenuClosed", "closed"] }], ngImport: i0 });
|
|
170
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.7", type: MenuTriggerDirective, isStandalone: true, selector: "[twMenuTrigger]", host: { attributes: { "data-tw-menu-trigger": "" } }, hostDirectives: [{ directive: i1.CdkMenuTrigger, inputs: ["cdkMenuTriggerFor", "twMenuTrigger", "cdkMenuPosition", "position", "cdkMenuTriggerData", "data"], outputs: ["cdkMenuOpened", "opened", "cdkMenuClosed", "closed"] }], ngImport: i0 });
|
|
143
171
|
}
|
|
144
172
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: MenuTriggerDirective, decorators: [{
|
|
145
173
|
type: Directive,
|
|
@@ -159,6 +187,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
|
|
|
159
187
|
outputs: ['cdkMenuOpened: opened', 'cdkMenuClosed: closed'],
|
|
160
188
|
},
|
|
161
189
|
],
|
|
190
|
+
host: {
|
|
191
|
+
// Static marker so the directive is locatable in tests and by consumers.
|
|
192
|
+
// Its own selector is not usable for that: `[twMenuTrigger]` takes a required
|
|
193
|
+
// `TemplateRef`, so it is ALWAYS property-bound and Angular emits no
|
|
194
|
+
// attribute for a bound input. Material solves this with a class
|
|
195
|
+
// (`.mat-mdc-menu-trigger`); `data-tw-*` is this repo's existing convention
|
|
196
|
+
// (see `data-tw-table-loading`, `data-tw-sort-arrow`) and carries no styling.
|
|
197
|
+
'data-tw-menu-trigger': '',
|
|
198
|
+
},
|
|
162
199
|
}]
|
|
163
200
|
}] });
|
|
164
201
|
// ── ContextMenuTriggerDirective ──
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdevhub-ngx-tw-menu.mjs","sources":["../../../projects/ngx-tw/menu/menu.ts","../../../projects/ngx-tw/menu/cdevhub-ngx-tw-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n Directive,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n CdkContextMenuTrigger,\n CdkMenu,\n CdkMenuGroup,\n CdkMenuItem,\n CdkMenuItemCheckbox,\n CdkMenuItemRadio,\n CdkMenuTrigger,\n} from '@angular/cdk/menu';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor, TwSize } from '@cdevhub/ngx-tw/core';\n\n// ── Variant configs ──\n\nconst menuVariants = tv(\n {\n base: 'min-w-48 flex flex-col max-h-96 rounded-lg bg-surface-overlay border border-border shadow-md overflow-y-auto text-fg',\n variants: {\n // Menu panels intentionally use sub-`p-1` padding at xs/sm because items\n // carry their own inline padding — the codified `p-2`/`p-3`/`p-4` container\n // scale would over-pad the panel gutter. The size axis here scales the panel\n // border-to-item gap only, not item density.\n size: {\n xs: 'p-0.5 [&>tw-separator]:-mx-0.5 [&>tw-separator]:my-0.5',\n sm: 'p-0.5 [&>tw-separator]:-mx-0.5 [&>tw-separator]:my-0.5',\n md: 'p-1 [&>tw-separator]:-mx-1 [&>tw-separator]:my-1',\n lg: 'p-1.5 [&>tw-separator]:-mx-1.5 [&>tw-separator]:my-1',\n xl: 'p-2 [&>tw-separator]:-mx-2 [&>tw-separator]:my-1',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// Menu items use the codified menu-item focus carve-out: `focus-visible:bg-surface-muted`\n// (and color-tinted equivalents below) in place of the canonical outline ring. See the\n// \"Focus Rings → Menu-item carve-out\" section in CLAUDE.md.\nconst menuItemVariants = tv(\n {\n base: 'relative flex w-full flex-wrap items-center gap-2 rounded-md cursor-pointer select-none transition-colors duration-normal motion-reduce:transition-none text-fg outline-none focus-visible:bg-surface-muted hover:bg-surface-muted',\n variants: {\n size: {\n xs: 'px-1.5 py-0.5 text-xs',\n sm: 'px-2 py-1 text-xs',\n md: 'px-3 py-1.5 text-sm',\n lg: 'px-4 py-2 text-sm',\n xl: 'px-5 py-2.5 text-base',\n },\n // Slot tokens own light/dark contrast — no `dark:`, no shade picks.\n // `undefined` (the default) leaves the base text-fg styling untouched.\n color: {\n primary: 'text-primary-fg hover:bg-primary-soft focus-visible:bg-primary-soft',\n secondary: 'text-secondary-fg hover:bg-secondary-soft focus-visible:bg-secondary-soft',\n accent: 'text-accent-fg hover:bg-accent-soft focus-visible:bg-accent-soft',\n info: 'text-info-fg hover:bg-info-soft focus-visible:bg-info-soft',\n success: 'text-success-fg hover:bg-success-soft focus-visible:bg-success-soft',\n warning: 'text-warning-fg hover:bg-warning-soft focus-visible:bg-warning-soft',\n error: 'text-error-fg hover:bg-error-soft focus-visible:bg-error-soft',\n neutral: 'text-fg-muted hover:bg-surface-muted focus-visible:bg-surface-muted',\n },\n // `cursor-not-allowed` is layered so a programmatically-focused disabled item\n // still reads as disabled — `pointer-events-none` blocks pointer activation, but\n // the cursor cue communicates the state if focus lands here via CDK's own paths.\n // CDK's `FocusableOption` honours `cdkItem.disabled` (synced via the effect below)\n // and skips disabled items in keyboard navigation automatically.\n disabled: {\n true: 'opacity-50 pointer-events-none cursor-not-allowed',\n },\n },\n defaultVariants: { size: 'md', disabled: false },\n },\n { twMerge: true },\n);\n\nconst menuItemIconVariants = tv(\n {\n base: 'shrink-0 text-fg-muted',\n variants: {\n size: {\n xs: 'size-4',\n sm: 'size-4',\n md: 'size-4',\n lg: 'size-5',\n xl: 'size-5',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\nconst menuItemIndicatorVariants = tv(\n {\n base: 'shrink-0 flex items-center justify-center',\n variants: {\n size: {\n xs: 'size-4',\n sm: 'size-4',\n md: 'size-4',\n lg: 'size-5',\n xl: 'size-5',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// Submenu indicator (trailing chevron). Keeps the `ml-auto pl-2` layout intent\n// separate from the leading-icon scale; size axis follows the glyph scale per\n// CLAUDE.md \"Icon Sizing\" so the chevron scales with the parent menu's density.\nconst menuItemSubmenuIndicatorVariants = tv(\n {\n base: 'ml-auto pl-2 shrink-0 text-fg-muted',\n variants: {\n size: {\n xs: 'size-3',\n sm: 'size-4',\n md: 'size-4',\n lg: 'size-5',\n xl: 'size-5',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// ── MenuComponent ──\n\n@Component({\n selector: 'tw-menu',\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: CdkMenu,\n outputs: ['closed'],\n },\n ],\n host: {\n '[class]': 'classes()',\n '[attr.aria-label]': 'ariaLabel() ?? null',\n '[attr.aria-labelledby]': 'ariaLabel() ? null : (ariaLabelledBy() ?? null)',\n '[animate.enter]': '\"scale-in\"',\n '[animate.leave]': '\"scale-out\"',\n },\n template: `<ng-content />`,\n})\nexport class MenuComponent {\n /** Controls item density and padding. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Accessible label for the menu panel. Use when no visible heading describes the menu (e.g. a kebab-icon trigger). */\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\n\n /** ID of an element that labels the menu panel. Ignored when `ariaLabel` is set. */\n readonly ariaLabelledBy = input<string | undefined>(undefined, { alias: 'aria-labelledby' });\n\n readonly classes = computed(() => menuVariants({ size: this.size() }));\n}\n\n// ── MenuTriggerDirective ──\n\n@Directive({\n selector: '[twMenuTrigger]',\n hostDirectives: [\n {\n directive: CdkMenuTrigger,\n inputs: [\n 'cdkMenuTriggerFor: twMenuTrigger',\n // Forward CDK's positioning so consumers can anchor the menu (e.g. bottom-end vs bottom-start).\n // Accepts `ConnectedPosition[]` from `@angular/cdk/overlay`.\n 'cdkMenuPosition: position',\n // Forward menu context data so consumers can parameterise the template.\n 'cdkMenuTriggerData: data',\n ],\n outputs: ['cdkMenuOpened: opened', 'cdkMenuClosed: closed'],\n },\n ],\n})\nexport class MenuTriggerDirective {}\n\n// ── ContextMenuTriggerDirective ──\n\n@Directive({\n selector: '[twContextMenuTrigger]',\n hostDirectives: [\n {\n directive: CdkContextMenuTrigger,\n inputs: [\n 'cdkContextMenuTriggerFor: twContextMenuTrigger',\n 'cdkContextMenuDisabled: disabled',\n // Context menus open at pointer coordinates; `position` here tunes the\n // `ConnectedPosition[]` fallback list once CDK has anchored the overlay.\n 'cdkContextMenuPosition: position',\n 'cdkContextMenuTriggerData: data',\n ],\n outputs: ['cdkContextMenuOpened: opened', 'cdkContextMenuClosed: closed'],\n },\n ],\n})\nexport class ContextMenuTriggerDirective {}\n\n// ── MenuItemDirective ──\n\n@Directive({\n selector: '[twMenuItem]',\n hostDirectives: [\n {\n directive: CdkMenuItem,\n outputs: ['cdkMenuItemTriggered: triggered'],\n },\n ],\n host: {\n '[class]': 'classes()',\n },\n})\nexport class MenuItemDirective {\n /**\n * Semantic role tint applied to the item. Use `'error'` for destructive actions.\n * Defaults to `undefined` — no role tint is applied and the item inherits the\n * base `text-fg` styling at full prominence; `'neutral'` (the explicit muted\n * variant) is a distinct value with `text-fg-muted` + `bg-surface-muted` hovers.\n */\n readonly color = input<TwColor | undefined>(undefined);\n\n /** Whether this item is disabled. Defaults to `false`. */\n readonly disabled = input(false);\n\n private readonly menu = inject(MenuComponent, { optional: true });\n private readonly cdkItem = inject(CdkMenuItem);\n\n constructor() {\n // Single source of truth: the local `disabled` signal drives both visual state\n // and the underlying CDK directive's behavior (`disabled` is a plain property on CDK).\n effect(() => {\n this.cdkItem.disabled = this.disabled();\n });\n }\n\n readonly classes = computed(() =>\n menuItemVariants({\n size: this.menu?.size() ?? 'md',\n color: this.color(),\n disabled: this.disabled(),\n }),\n );\n}\n\n// ── MenuItemCheckboxComponent ──\n\n@Component({\n selector: '[twMenuItemCheckbox]',\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: CdkMenuItemCheckbox,\n inputs: ['cdkMenuItemChecked: checked'],\n outputs: ['cdkMenuItemTriggered: triggered'],\n },\n ],\n host: {\n '[class]': 'classes()',\n },\n template: `\n <span [class]=\"indicatorClasses()\">\n @if (cdkCheckbox.checked) {\n <svg class=\"size-full\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\" clip-rule=\"evenodd\"/>\n </svg>\n }\n </span>\n <ng-content />\n `,\n})\nexport class MenuItemCheckboxComponent {\n /** Whether this item is disabled. Defaults to `false`. */\n readonly disabled = input(false);\n\n /** Fires when the item is activated, carrying the new `checked` value after CDK toggles it. */\n readonly checkedChange = output<boolean>();\n\n protected readonly cdkCheckbox = inject(CdkMenuItemCheckbox);\n private readonly menu = inject(MenuComponent, { optional: true });\n\n private readonly resolvedSize = computed(() => this.menu?.size() ?? 'md');\n\n constructor() {\n effect(() => {\n this.cdkCheckbox.disabled = this.disabled();\n });\n // CDK fires `triggered` BEFORE updating `checked`; emit the post-toggle value.\n this.cdkCheckbox.triggered\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.checkedChange.emit(!this.cdkCheckbox.checked));\n }\n\n readonly classes = computed(() =>\n menuItemVariants({\n size: this.resolvedSize(),\n disabled: this.disabled(),\n }),\n );\n\n readonly indicatorClasses = computed(() =>\n menuItemIndicatorVariants({ size: this.resolvedSize() }),\n );\n}\n\n// ── MenuItemRadioComponent ──\n\n@Component({\n selector: '[twMenuItemRadio]',\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: CdkMenuItemRadio,\n inputs: ['cdkMenuItemChecked: checked'],\n outputs: ['cdkMenuItemTriggered: triggered'],\n },\n ],\n host: {\n '[class]': 'classes()',\n },\n template: `\n <span [class]=\"indicatorClasses()\">\n @if (cdkRadio.checked) {\n <svg class=\"size-full\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <circle cx=\"10\" cy=\"10\" r=\"5\"/>\n </svg>\n }\n </span>\n <ng-content />\n `,\n})\nexport class MenuItemRadioComponent {\n /** Whether this item is disabled. Defaults to `false`. */\n readonly disabled = input(false);\n\n /** Fires when the item is activated, carrying the new `checked` value after CDK selects it. */\n readonly checkedChange = output<boolean>();\n\n protected readonly cdkRadio = inject(CdkMenuItemRadio);\n private readonly menu = inject(MenuComponent, { optional: true });\n\n private readonly resolvedSize = computed(() => this.menu?.size() ?? 'md');\n\n constructor() {\n effect(() => {\n this.cdkRadio.disabled = this.disabled();\n });\n // Radio activation always selects the item; emit `true` (the post-trigger checked state).\n this.cdkRadio.triggered\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.checkedChange.emit(true));\n }\n\n readonly classes = computed(() =>\n menuItemVariants({\n size: this.resolvedSize(),\n disabled: this.disabled(),\n }),\n );\n\n readonly indicatorClasses = computed(() =>\n menuItemIndicatorVariants({ size: this.resolvedSize() }),\n );\n}\n\n// ── MenuGroupDirective ──\n\n@Directive({\n selector: '[twMenuGroup]',\n hostDirectives: [CdkMenuGroup],\n})\nexport class MenuGroupDirective {}\n\n// ── Content directives ──\n\n/** Styles a leading icon inside a menu item. */\n@Directive({\n selector: '[twMenuItemIcon]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class MenuItemIconDirective {\n private readonly menu = inject(MenuComponent, { optional: true });\n\n readonly classes = computed(() =>\n menuItemIconVariants({ size: this.menu?.size() ?? 'md' }),\n );\n}\n\n/** Styles secondary description text inside a menu item. */\n@Directive({\n selector: '[twMenuItemDescription]',\n host: {\n class: 'block text-xs text-fg-muted min-w-0 truncate order-last basis-full',\n },\n})\nexport class MenuItemDescriptionDirective {}\n\n/** Right-aligns and mutes keyboard shortcut hint text. */\n@Directive({\n selector: '[twMenuItemShortcut]',\n host: {\n class: 'ml-auto pl-3 text-xs text-fg-subtle tracking-wide',\n },\n})\nexport class MenuItemShortcutDirective {}\n\n/** Styles the trailing chevron for submenu triggers. */\n@Directive({\n selector: '[twMenuItemSubmenuIcon]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class MenuItemSubmenuIndicatorDirective {\n private readonly menu = inject(MenuComponent, { optional: true });\n\n readonly classes = computed(() =>\n menuItemSubmenuIndicatorVariants({ size: this.menu?.size() ?? 'md' }),\n );\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;AAuBA;AAEA,MAAM,YAAY,GAAG,EAAE,CACrB;AACE,IAAA,IAAI,EAAE,sHAAsH;AAC5H,IAAA,QAAQ,EAAE;;;;;AAKR,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,wDAAwD;AAC5D,YAAA,EAAE,EAAE,wDAAwD;AAC5D,YAAA,EAAE,EAAE,kDAAkD;AACtD,YAAA,EAAE,EAAE,sDAAsD;AAC1D,YAAA,EAAE,EAAE,kDAAkD;AACvD,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;AAChC,CAAA,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB;AAED;AACA;AACA;AACA,MAAM,gBAAgB,GAAG,EAAE,CACzB;AACE,IAAA,IAAI,EAAE,oOAAoO;AAC1O,IAAA,QAAQ,EAAE;AACR,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,uBAAuB;AAC3B,YAAA,EAAE,EAAE,mBAAmB;AACvB,YAAA,EAAE,EAAE,qBAAqB;AACzB,YAAA,EAAE,EAAE,mBAAmB;AACvB,YAAA,EAAE,EAAE,uBAAuB;AAC5B,SAAA;;;AAGD,QAAA,KAAK,EAAE;AACL,YAAA,OAAO,EAAE,qEAAqE;AAC9E,YAAA,SAAS,EAAE,2EAA2E;AACtF,YAAA,MAAM,EAAE,kEAAkE;AAC1E,YAAA,IAAI,EAAE,4DAA4D;AAClE,YAAA,OAAO,EAAE,qEAAqE;AAC9E,YAAA,OAAO,EAAE,qEAAqE;AAC9E,YAAA,KAAK,EAAE,+DAA+D;AACtE,YAAA,OAAO,EAAE,qEAAqE;AAC/E,SAAA;;;;;;AAMD,QAAA,QAAQ,EAAE;AACR,YAAA,IAAI,EAAE,mDAAmD;AAC1D,SAAA;AACF,KAAA;IACD,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;AACjD,CAAA,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB;AAED,MAAM,oBAAoB,GAAG,EAAE,CAC7B;AACE,IAAA,IAAI,EAAE,wBAAwB;AAC9B,IAAA,QAAQ,EAAE;AACR,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACb,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;AAChC,CAAA,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB;AAED,MAAM,yBAAyB,GAAG,EAAE,CAClC;AACE,IAAA,IAAI,EAAE,2CAA2C;AACjD,IAAA,QAAQ,EAAE;AACR,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACb,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;AAChC,CAAA,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB;AAED;AACA;AACA;AACA,MAAM,gCAAgC,GAAG,EAAE,CACzC;AACE,IAAA,IAAI,EAAE,qCAAqC;AAC3C,IAAA,QAAQ,EAAE;AACR,QAAA,IAAI,EAAE;AACJ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACZ,YAAA,EAAE,EAAE,QAAQ;AACb,SAAA;AACF,KAAA;AACD,IAAA,eAAe,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;AAChC,CAAA,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,CAClB;AAED;MAoBa,aAAa,CAAA;;IAEf,IAAI,GAAG,KAAK,CAAS,IAAI;6EAAC;;IAG1B,SAAS,GAAG,KAAK,CAAqB,SAAS,iFAAI,KAAK,EAAE,YAAY,EAAA,CAAG;;IAGzE,cAAc,GAAG,KAAK,CAAqB,SAAS,sFAAI,KAAK,EAAE,iBAAiB,EAAA,CAAG;AAEnF,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gFAAC;uGAV3D,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,ixBAFd,CAAA,cAAA,CAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAEf,aAAa,EAAA,UAAA,EAAA,CAAA;kBAlBzB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,SAAS;oBACnB,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,cAAc,EAAE;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,OAAO;4BAClB,OAAO,EAAE,CAAC,QAAQ,CAAC;AACpB,yBAAA;AACF,qBAAA;AACD,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACtB,wBAAA,mBAAmB,EAAE,qBAAqB;AAC1C,wBAAA,wBAAwB,EAAE,iDAAiD;AAC3E,wBAAA,iBAAiB,EAAE,YAAY;AAC/B,wBAAA,iBAAiB,EAAE,aAAa;AACjC,qBAAA;AACD,oBAAA,QAAQ,EAAE,CAAA,cAAA,CAAgB;AAC3B,iBAAA;;AAcD;MAmBa,oBAAoB,CAAA;uGAApB,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAA,EAAA,CAAA,cAAA,EAAA,MAAA,EAAA,CAAA,mBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,eAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAjBhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,iBAAiB;AAC3B,oBAAA,cAAc,EAAE;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,cAAc;AACzB,4BAAA,MAAM,EAAE;gCACN,kCAAkC;;;gCAGlC,2BAA2B;;gCAE3B,0BAA0B;AAC3B,6BAAA;AACD,4BAAA,OAAO,EAAE,CAAC,uBAAuB,EAAE,uBAAuB,CAAC;AAC5D,yBAAA;AACF,qBAAA;AACF,iBAAA;;AAGD;MAmBa,2BAA2B,CAAA;uGAA3B,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA3B,2BAA2B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,MAAA,EAAA,CAAA,0BAAA,EAAA,sBAAA,EAAA,wBAAA,EAAA,UAAA,EAAA,wBAAA,EAAA,UAAA,EAAA,2BAAA,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,sBAAA,EAAA,QAAA,EAAA,sBAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA3B,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBAjBvC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,wBAAwB;AAClC,oBAAA,cAAc,EAAE;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,qBAAqB;AAChC,4BAAA,MAAM,EAAE;gCACN,gDAAgD;gCAChD,kCAAkC;;;gCAGlC,kCAAkC;gCAClC,iCAAiC;AAClC,6BAAA;AACD,4BAAA,OAAO,EAAE,CAAC,8BAA8B,EAAE,8BAA8B,CAAC;AAC1E,yBAAA;AACF,qBAAA;AACF,iBAAA;;AAGD;MAca,iBAAiB,CAAA;AAC5B;;;;;AAKG;IACM,KAAK,GAAG,KAAK,CAAsB,SAAS;8EAAC;;IAG7C,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;IAEf,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAChD,IAAA,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC;AAE9C,IAAA,WAAA,GAAA;;;QAGE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE;AACzC,QAAA,CAAC,CAAC;IACJ;AAES,IAAA,OAAO,GAAG,QAAQ,CAAC,MAC1B,gBAAgB,CAAC;QACf,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI;AAC/B,QAAA,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;AACnB,QAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;KAC1B,CAAC;gFACH;uGA7BU,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAjB,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,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,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAA,EAAA,CAAA,WAAA,EAAA,OAAA,EAAA,CAAA,sBAAA,EAAA,WAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAjB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAZ7B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,cAAc;AACxB,oBAAA,cAAc,EAAE;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,WAAW;4BACtB,OAAO,EAAE,CAAC,iCAAiC,CAAC;AAC7C,yBAAA;AACF,qBAAA;AACD,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACvB,qBAAA;AACF,iBAAA;;AAiCD;MA0Ba,yBAAyB,CAAA;;IAE3B,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;;IAGvB,aAAa,GAAG,MAAM,EAAW;AAEvB,IAAA,WAAW,GAAG,MAAM,CAAC,mBAAmB,CAAC;IAC3C,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAEhD,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI;qFAAC;AAEzE,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC7C,QAAA,CAAC,CAAC;;QAEF,IAAI,CAAC,WAAW,CAAC;aACd,IAAI,CAAC,kBAAkB,EAAE;AACzB,aAAA,SAAS,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACxE;AAES,IAAA,OAAO,GAAG,QAAQ,CAAC,MAC1B,gBAAgB,CAAC;AACf,QAAA,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE;AACzB,QAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;KAC1B,CAAC;gFACH;AAEQ,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MACnC,yBAAyB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;yFACzD;uGA/BU,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAzB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,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,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,oBAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,sBAAA,EAAA,WAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAX1B;;;;;;;;;AAST,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAEU,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAxBrC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,sBAAsB;oBAChC,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,cAAc,EAAE;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,mBAAmB;4BAC9B,MAAM,EAAE,CAAC,6BAA6B,CAAC;4BACvC,OAAO,EAAE,CAAC,iCAAiC,CAAC;AAC7C,yBAAA;AACF,qBAAA;AACD,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACvB,qBAAA;AACD,oBAAA,QAAQ,EAAE;;;;;;;;;AAST,EAAA,CAAA;AACF,iBAAA;;AAmCD;MA0Ba,sBAAsB,CAAA;;IAExB,QAAQ,GAAG,KAAK,CAAC,KAAK;iFAAC;;IAGvB,aAAa,GAAG,MAAM,EAAW;AAEvB,IAAA,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC;IACrC,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAEhD,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI;qFAAC;AAEzE,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC1C,QAAA,CAAC,CAAC;;QAEF,IAAI,CAAC,QAAQ,CAAC;aACX,IAAI,CAAC,kBAAkB,EAAE;AACzB,aAAA,SAAS,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD;AAES,IAAA,OAAO,GAAG,QAAQ,CAAC,MAC1B,gBAAgB,CAAC;AACf,QAAA,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE;AACzB,QAAA,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;KAC1B,CAAC;gFACH;AAEQ,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MACnC,yBAAyB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;yFACzD;uGA/BU,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,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,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,oBAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,sBAAA,EAAA,WAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAXvB;;;;;;;;;AAST,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAEU,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAxBlC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;oBAC7B,eAAe,EAAE,uBAAuB,CAAC,MAAM;AAC/C,oBAAA,cAAc,EAAE;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,gBAAgB;4BAC3B,MAAM,EAAE,CAAC,6BAA6B,CAAC;4BACvC,OAAO,EAAE,CAAC,iCAAiC,CAAC;AAC7C,yBAAA;AACF,qBAAA;AACD,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACvB,qBAAA;AACD,oBAAA,QAAQ,EAAE;;;;;;;;;AAST,EAAA,CAAA;AACF,iBAAA;;AAmCD;MAMa,kBAAkB,CAAA;uGAAlB,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAlB,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,eAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAA,EAAA,CAAA,YAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAlB,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAJ9B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,eAAe;oBACzB,cAAc,EAAE,CAAC,YAAY,CAAC;AAC/B,iBAAA;;AAGD;AAEA;MAOa,qBAAqB,CAAA;IACf,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAExD,OAAO,GAAG,QAAQ,CAAC,MAC1B,oBAAoB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;gFAC1D;uGALU,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAArB,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAArB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBANjC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,kBAAkB;AAC5B,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACvB,qBAAA;AACF,iBAAA;;AASD;MAOa,4BAA4B,CAAA;uGAA5B,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA5B,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,oEAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA5B,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBANxC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,yBAAyB;AACnC,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,oEAAoE;AAC5E,qBAAA;AACF,iBAAA;;AAGD;MAOa,yBAAyB,CAAA;uGAAzB,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAzB,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,sBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mDAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAzB,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBANrC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,sBAAsB;AAChC,oBAAA,IAAI,EAAE;AACJ,wBAAA,KAAK,EAAE,mDAAmD;AAC3D,qBAAA;AACF,iBAAA;;AAGD;MAOa,iCAAiC,CAAA;IAC3B,IAAI,GAAG,MAAM,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAExD,OAAO,GAAG,QAAQ,CAAC,MAC1B,gCAAgC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;gFACtE;uGALU,iCAAiC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAjC,iCAAiC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,OAAA,EAAA,WAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAjC,iCAAiC,EAAA,UAAA,EAAA,CAAA;kBAN7C,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,yBAAyB;AACnC,oBAAA,IAAI,EAAE;AACJ,wBAAA,SAAS,EAAE,WAAW;AACvB,qBAAA;AACF,iBAAA;;;AC9aD;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-tw-menu.mjs","sources":["../../../projects/ngx-tw/menu/menu.ts","../../../projects/ngx-tw/menu/cdevhub-ngx-tw-menu.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n Directive,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport {\n CdkContextMenuTrigger,\n CdkMenu,\n CdkMenuGroup,\n CdkMenuItem,\n CdkMenuItemCheckbox,\n CdkMenuItemRadio,\n CdkMenuTrigger,\n} from '@angular/cdk/menu';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor, TwSize } from '@cdevhub/ngx-tw/core';\n\n// ── Variant configs ──\n\nconst menuVariants = tv(\n {\n base: 'min-w-48 flex flex-col max-h-96 rounded-lg bg-surface-overlay border border-border shadow-md overflow-y-auto text-fg',\n variants: {\n // Menu panels intentionally use sub-`p-1` padding at xs/sm because items\n // carry their own inline padding — the codified `p-2`/`p-3`/`p-4` container\n // scale would over-pad the panel gutter. The size axis here scales the panel\n // border-to-item gap only, not item density.\n size: {\n xs: 'p-0.5 [&>tw-separator]:-mx-0.5 [&>tw-separator]:my-0.5',\n sm: 'p-0.5 [&>tw-separator]:-mx-0.5 [&>tw-separator]:my-0.5',\n md: 'p-1 [&>tw-separator]:-mx-1 [&>tw-separator]:my-1',\n lg: 'p-1.5 [&>tw-separator]:-mx-1.5 [&>tw-separator]:my-1',\n xl: 'p-2 [&>tw-separator]:-mx-2 [&>tw-separator]:my-1',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// Menu items use the codified menu-item focus carve-out: `focus-visible:bg-surface-muted`\n// (and color-tinted equivalents below) in place of the canonical outline ring. See the\n// \"Focus Rings → Menu-item carve-out\" section in CLAUDE.md.\nconst menuItemVariants = tv(\n {\n base: 'relative flex w-full flex-wrap items-center gap-2 rounded-md cursor-pointer select-none transition-colors duration-normal motion-reduce:transition-none text-fg outline-none focus-visible:bg-surface-muted hover:bg-surface-muted',\n variants: {\n // Menu rows are on the `min-h-*` list (docs/vertical-rhythm.md §2), not\n // the pinned one: `[twMenuItemDescription]` wraps onto a second line via\n // `basis-full`, so the box must stay free to grow. The floor lands on the\n // control scale (24 / 32 / 36 / 44 / 48) and `py-*` is kept exactly as it\n // was — it sets the breathing room around a wrapped two-line row, where\n // the floor no longer binds.\n size: {\n xs: 'px-1.5 py-0.5 text-xs min-h-6',\n sm: 'px-2 py-1 text-xs min-h-8',\n md: 'px-3 py-1.5 text-sm min-h-9',\n lg: 'px-4 py-2 text-sm min-h-11',\n xl: 'px-5 py-2.5 text-base min-h-12',\n },\n // Slot tokens own light/dark contrast — no `dark:`, no shade picks.\n // `undefined` (the default) leaves the base text-fg styling untouched.\n color: {\n primary: 'text-primary-fg hover:bg-primary-soft focus-visible:bg-primary-soft',\n secondary: 'text-secondary-fg hover:bg-secondary-soft focus-visible:bg-secondary-soft',\n accent: 'text-accent-fg hover:bg-accent-soft focus-visible:bg-accent-soft',\n info: 'text-info-fg hover:bg-info-soft focus-visible:bg-info-soft',\n success: 'text-success-fg hover:bg-success-soft focus-visible:bg-success-soft',\n warning: 'text-warning-fg hover:bg-warning-soft focus-visible:bg-warning-soft',\n error: 'text-error-fg hover:bg-error-soft focus-visible:bg-error-soft',\n neutral: 'text-fg-muted hover:bg-surface-muted focus-visible:bg-surface-muted',\n },\n // `cursor-not-allowed` is layered so a programmatically-focused disabled item\n // still reads as disabled — `pointer-events-none` blocks pointer activation, but\n // the cursor cue communicates the state if focus lands here via CDK's own paths.\n // CDK's `FocusableOption` honours `cdkItem.disabled` (synced via the effect below)\n // and skips disabled items in keyboard navigation automatically.\n disabled: {\n true: 'opacity-50 pointer-events-none cursor-not-allowed',\n },\n },\n defaultVariants: { size: 'md', disabled: false },\n },\n { twMerge: true },\n);\n\n// Leading icon on a menu item. Follows CLAUDE.md \"Icon Sizing\" → glyph\n// sub-scale, saturating at `lg`: 3 / 4 / 5 / 6 / 6. Previously 4/4/4/5/5,\n// which collapsed xs/sm/md onto one value and left `xl` indistinguishable\n// from `lg`.\n//\n// `xl` deliberately reuses `size-6` rather than the glyph scale's `size-8`.\n// Menu rows are `flex items-center` on a `min-h-*` floor (see the size ramp\n// above and docs/vertical-rhythm.md §2). At `xl` a 32px glyph plus `py-2.5`\n// (20px) measures 52px against a `min-h-12` floor of 48px, so the floor\n// stops binding — and only for rows that project a glyph, so an `xl` menu\n// would render 52px and 48px rows side by side. Every other step still\n// binds (xs 16<24, sm 24<32, md 32<36, lg 40<44). This is the same\n// saturation CLAUDE.md already codifies for the square-interactive scale,\n// where the breadcrumb overflow trigger reuses `size-9` at both `lg` and\n// `xl`. Raising `xl` here means raising the row floor to match.\nconst menuItemIconVariants = tv(\n {\n base: 'shrink-0 text-fg-muted',\n variants: {\n size: {\n xs: 'size-3',\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n xl: 'size-6',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// Selection marker (check / radio dot wrapper). This is the box the glyph is\n// centred in, so it rides the same glyph sub-scale as the leading icon —\n// otherwise the check and the icon on adjacent items sit on different scales.\n// Previously 4/4/4/5/5.\nconst menuItemIndicatorVariants = tv(\n {\n base: 'shrink-0 flex items-center justify-center',\n variants: {\n size: {\n xs: 'size-3',\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n xl: 'size-6',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// Submenu indicator (trailing chevron). Keeps the `ml-auto pl-2` layout intent\n// separate from the leading-icon scale, but the size axis is the same\n// CLAUDE.md \"Icon Sizing\" glyph sub-scale (3/4/5/6/8) the other two menu\n// glyph ramps use, so the chevron tracks the parent menu's density and every\n// step is visually distinct. Previously 3/4/4/5/5, which duplicated `sm`→`md`\n// and `lg`→`xl`.\nconst menuItemSubmenuIndicatorVariants = tv(\n {\n base: 'ml-auto pl-2 shrink-0 text-fg-muted',\n variants: {\n size: {\n xs: 'size-3',\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n xl: 'size-6',\n },\n },\n defaultVariants: { size: 'md' },\n },\n { twMerge: true },\n);\n\n// ── MenuComponent ──\n\n@Component({\n selector: 'tw-menu',\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: CdkMenu,\n outputs: ['closed'],\n },\n ],\n host: {\n '[class]': 'classes()',\n '[attr.aria-label]': 'ariaLabel() ?? null',\n '[attr.aria-labelledby]': 'ariaLabel() ? null : (ariaLabelledBy() ?? null)',\n '[animate.enter]': '\"scale-in\"',\n '[animate.leave]': '\"scale-out\"',\n },\n template: `<ng-content />`,\n})\nexport class MenuComponent {\n /** Controls item density and padding. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Accessible label for the menu panel. Use when no visible heading describes the menu (e.g. a kebab-icon trigger). Defaults to `undefined`. Alias: `aria-label`. */\n readonly ariaLabel = input<string | undefined>(undefined, { alias: 'aria-label' });\n\n /** ID of an element that labels the menu panel. Ignored when `ariaLabel` is set. Defaults to `undefined`. Alias: `aria-labelledby`. */\n readonly ariaLabelledBy = input<string | undefined>(undefined, { alias: 'aria-labelledby' });\n\n readonly classes = computed(() => menuVariants({ size: this.size() }));\n}\n\n// ── MenuTriggerDirective ──\n\n@Directive({\n selector: '[twMenuTrigger]',\n hostDirectives: [\n {\n directive: CdkMenuTrigger,\n inputs: [\n 'cdkMenuTriggerFor: twMenuTrigger',\n // Forward CDK's positioning so consumers can anchor the menu (e.g. bottom-end vs bottom-start).\n // Accepts `ConnectedPosition[]` from `@angular/cdk/overlay`.\n 'cdkMenuPosition: position',\n // Forward menu context data so consumers can parameterise the template.\n 'cdkMenuTriggerData: data',\n ],\n outputs: ['cdkMenuOpened: opened', 'cdkMenuClosed: closed'],\n },\n ],\n host: {\n // Static marker so the directive is locatable in tests and by consumers.\n // Its own selector is not usable for that: `[twMenuTrigger]` takes a required\n // `TemplateRef`, so it is ALWAYS property-bound and Angular emits no\n // attribute for a bound input. Material solves this with a class\n // (`.mat-mdc-menu-trigger`); `data-tw-*` is this repo's existing convention\n // (see `data-tw-table-loading`, `data-tw-sort-arrow`) and carries no styling.\n 'data-tw-menu-trigger': '',\n },\n})\nexport class MenuTriggerDirective {}\n\n// ── ContextMenuTriggerDirective ──\n\n@Directive({\n selector: '[twContextMenuTrigger]',\n hostDirectives: [\n {\n directive: CdkContextMenuTrigger,\n inputs: [\n 'cdkContextMenuTriggerFor: twContextMenuTrigger',\n 'cdkContextMenuDisabled: disabled',\n // Context menus open at pointer coordinates; `position` here tunes the\n // `ConnectedPosition[]` fallback list once CDK has anchored the overlay.\n 'cdkContextMenuPosition: position',\n 'cdkContextMenuTriggerData: data',\n ],\n outputs: ['cdkContextMenuOpened: opened', 'cdkContextMenuClosed: closed'],\n },\n ],\n})\nexport class ContextMenuTriggerDirective {}\n\n// ── MenuItemDirective ──\n\n@Directive({\n selector: '[twMenuItem]',\n hostDirectives: [\n {\n directive: CdkMenuItem,\n outputs: ['cdkMenuItemTriggered: triggered'],\n },\n ],\n host: {\n '[class]': 'classes()',\n },\n})\nexport class MenuItemDirective {\n /**\n * Semantic role tint applied to the item. Use `'error'` for destructive actions.\n * Defaults to `undefined` — no role tint is applied and the item inherits the\n * base `text-fg` styling at full prominence; `'neutral'` (the explicit muted\n * variant) is a distinct value with `text-fg-muted` + `bg-surface-muted` hovers.\n */\n readonly color = input<TwColor | undefined>(undefined);\n\n /** Whether this item is disabled. Defaults to `false`. */\n readonly disabled = input(false);\n\n private readonly menu = inject(MenuComponent, { optional: true });\n private readonly cdkItem = inject(CdkMenuItem);\n\n constructor() {\n // Single source of truth: the local `disabled` signal drives both visual state\n // and the underlying CDK directive's behavior (`disabled` is a plain property on CDK).\n effect(() => {\n this.cdkItem.disabled = this.disabled();\n });\n }\n\n readonly classes = computed(() =>\n menuItemVariants({\n size: this.menu?.size() ?? 'md',\n color: this.color(),\n disabled: this.disabled(),\n }),\n );\n}\n\n// ── MenuItemCheckboxComponent ──\n\n@Component({\n selector: '[twMenuItemCheckbox]',\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: CdkMenuItemCheckbox,\n inputs: ['cdkMenuItemChecked: checked'],\n outputs: ['cdkMenuItemTriggered: triggered'],\n },\n ],\n host: {\n '[class]': 'classes()',\n },\n template: `\n <span [class]=\"indicatorClasses()\">\n @if (cdkCheckbox.checked) {\n <svg class=\"size-full\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\" clip-rule=\"evenodd\"/>\n </svg>\n }\n </span>\n <ng-content />\n `,\n})\nexport class MenuItemCheckboxComponent {\n /** Whether this item is disabled. Defaults to `false`. */\n readonly disabled = input(false);\n\n /** Fires when the item is activated, carrying the new `checked` value after CDK toggles it. */\n readonly checkedChange = output<boolean>();\n\n protected readonly cdkCheckbox = inject(CdkMenuItemCheckbox);\n private readonly menu = inject(MenuComponent, { optional: true });\n\n private readonly resolvedSize = computed(() => this.menu?.size() ?? 'md');\n\n constructor() {\n effect(() => {\n this.cdkCheckbox.disabled = this.disabled();\n });\n // CDK fires `triggered` BEFORE updating `checked`; emit the post-toggle value.\n this.cdkCheckbox.triggered\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.checkedChange.emit(!this.cdkCheckbox.checked));\n }\n\n readonly classes = computed(() =>\n menuItemVariants({\n size: this.resolvedSize(),\n disabled: this.disabled(),\n }),\n );\n\n readonly indicatorClasses = computed(() =>\n menuItemIndicatorVariants({ size: this.resolvedSize() }),\n );\n}\n\n// ── MenuItemRadioComponent ──\n\n@Component({\n selector: '[twMenuItemRadio]',\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: CdkMenuItemRadio,\n inputs: ['cdkMenuItemChecked: checked'],\n outputs: ['cdkMenuItemTriggered: triggered'],\n },\n ],\n host: {\n '[class]': 'classes()',\n },\n template: `\n <span [class]=\"indicatorClasses()\">\n @if (cdkRadio.checked) {\n <svg class=\"size-full\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <circle cx=\"10\" cy=\"10\" r=\"5\"/>\n </svg>\n }\n </span>\n <ng-content />\n `,\n})\nexport class MenuItemRadioComponent {\n /** Whether this item is disabled. Defaults to `false`. */\n readonly disabled = input(false);\n\n /** Fires when the item is activated, carrying the new `checked` value after CDK selects it. */\n readonly checkedChange = output<boolean>();\n\n protected readonly cdkRadio = inject(CdkMenuItemRadio);\n private readonly menu = inject(MenuComponent, { optional: true });\n\n private readonly resolvedSize = computed(() => this.menu?.size() ?? 'md');\n\n constructor() {\n effect(() => {\n this.cdkRadio.disabled = this.disabled();\n });\n // Radio activation always selects the item; emit `true` (the post-trigger checked state).\n this.cdkRadio.triggered\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.checkedChange.emit(true));\n }\n\n readonly classes = computed(() =>\n menuItemVariants({\n size: this.resolvedSize(),\n disabled: this.disabled(),\n }),\n );\n\n readonly indicatorClasses = computed(() =>\n menuItemIndicatorVariants({ size: this.resolvedSize() }),\n );\n}\n\n// ── MenuGroupDirective ──\n\n@Directive({\n selector: '[twMenuGroup]',\n hostDirectives: [CdkMenuGroup],\n})\nexport class MenuGroupDirective {}\n\n// ── Content directives ──\n\n/** Styles a leading icon inside a menu item. */\n@Directive({\n selector: '[twMenuItemIcon]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class MenuItemIconDirective {\n private readonly menu = inject(MenuComponent, { optional: true });\n\n readonly classes = computed(() =>\n menuItemIconVariants({ size: this.menu?.size() ?? 'md' }),\n );\n}\n\n/** Styles secondary description text inside a menu item. */\n@Directive({\n selector: '[twMenuItemDescription]',\n host: {\n class: 'block text-xs text-fg-muted min-w-0 truncate order-last basis-full',\n },\n})\nexport class MenuItemDescriptionDirective {}\n\n/** Right-aligns and mutes keyboard shortcut hint text. */\n@Directive({\n selector: '[twMenuItemShortcut]',\n host: {\n class: 'ml-auto pl-3 text-xs text-fg-subtle tracking-wide',\n },\n})\nexport class MenuItemShortcutDirective {}\n\n/** Styles the trailing chevron for submenu triggers. */\n@Directive({\n selector: '[twMenuItemSubmenuIcon]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class MenuItemSubmenuIndicatorDirective {\n private readonly menu = inject(MenuComponent, { optional: true });\n\n readonly classes = computed(() =>\n menuItemSubmenuIndicatorVariants({ size: this.menu?.size() ?? 'md' }),\n );\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|