@mesgflow/ui-kit 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/LICENSE +21 -0
- package/README.md +200 -0
- package/fesm2022/mesgflow-ui-kit-accordion.mjs +75 -0
- package/fesm2022/mesgflow-ui-kit-accordion.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-alert.mjs +165 -0
- package/fesm2022/mesgflow-ui-kit-alert.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-avatar-group.mjs +88 -0
- package/fesm2022/mesgflow-ui-kit-avatar-group.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-avatar.mjs +123 -0
- package/fesm2022/mesgflow-ui-kit-avatar.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-badge.mjs +68 -0
- package/fesm2022/mesgflow-ui-kit-badge.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-banner.mjs +111 -0
- package/fesm2022/mesgflow-ui-kit-banner.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-box-input.mjs +78 -0
- package/fesm2022/mesgflow-ui-kit-box-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-brand.mjs +120 -0
- package/fesm2022/mesgflow-ui-kit-brand.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-breadcrumb.mjs +84 -0
- package/fesm2022/mesgflow-ui-kit-breadcrumb.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-button-group.mjs +37 -0
- package/fesm2022/mesgflow-ui-kit-button-group.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-button.mjs +359 -0
- package/fesm2022/mesgflow-ui-kit-button.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-card.mjs +128 -0
- package/fesm2022/mesgflow-ui-kit-card.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-chart.mjs +538 -0
- package/fesm2022/mesgflow-ui-kit-chart.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-checkbox.mjs +45 -0
- package/fesm2022/mesgflow-ui-kit-checkbox.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-chip.mjs +123 -0
- package/fesm2022/mesgflow-ui-kit-chip.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-code-block.mjs +71 -0
- package/fesm2022/mesgflow-ui-kit-code-block.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-collapsible.mjs +89 -0
- package/fesm2022/mesgflow-ui-kit-collapsible.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-color-picker.mjs +210 -0
- package/fesm2022/mesgflow-ui-kit-color-picker.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-combobox.mjs +181 -0
- package/fesm2022/mesgflow-ui-kit-combobox.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-command.mjs +491 -0
- package/fesm2022/mesgflow-ui-kit-command.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-context-menu.mjs +92 -0
- package/fesm2022/mesgflow-ui-kit-context-menu.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-copy-button.mjs +167 -0
- package/fesm2022/mesgflow-ui-kit-copy-button.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-core.mjs +624 -0
- package/fesm2022/mesgflow-ui-kit-core.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-date-picker.mjs +643 -0
- package/fesm2022/mesgflow-ui-kit-date-picker.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-description-list.mjs +76 -0
- package/fesm2022/mesgflow-ui-kit-description-list.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-dialog.mjs +700 -0
- package/fesm2022/mesgflow-ui-kit-dialog.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-divider.mjs +62 -0
- package/fesm2022/mesgflow-ui-kit-divider.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-dropzone.mjs +126 -0
- package/fesm2022/mesgflow-ui-kit-dropzone.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-empty-state.mjs +70 -0
- package/fesm2022/mesgflow-ui-kit-empty-state.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-field.mjs +42 -0
- package/fesm2022/mesgflow-ui-kit-field.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-hover-card.mjs +171 -0
- package/fesm2022/mesgflow-ui-kit-hover-card.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-i18n-tr.mjs +258 -0
- package/fesm2022/mesgflow-ui-kit-i18n-tr.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-icon.mjs +174 -0
- package/fesm2022/mesgflow-ui-kit-icon.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-input.mjs +448 -0
- package/fesm2022/mesgflow-ui-kit-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-kbd.mjs +24 -0
- package/fesm2022/mesgflow-ui-kit-kbd.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-link.mjs +48 -0
- package/fesm2022/mesgflow-ui-kit-link.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-menu.mjs +105 -0
- package/fesm2022/mesgflow-ui-kit-menu.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-number-input.mjs +153 -0
- package/fesm2022/mesgflow-ui-kit-number-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-otp-input.mjs +164 -0
- package/fesm2022/mesgflow-ui-kit-otp-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-page-header.mjs +83 -0
- package/fesm2022/mesgflow-ui-kit-page-header.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-pagination.mjs +99 -0
- package/fesm2022/mesgflow-ui-kit-pagination.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-password-input.mjs +120 -0
- package/fesm2022/mesgflow-ui-kit-password-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-popover.mjs +213 -0
- package/fesm2022/mesgflow-ui-kit-popover.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-progress.mjs +82 -0
- package/fesm2022/mesgflow-ui-kit-progress.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-radio.mjs +123 -0
- package/fesm2022/mesgflow-ui-kit-radio.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-rating.mjs +116 -0
- package/fesm2022/mesgflow-ui-kit-rating.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-scroll-area.mjs +84 -0
- package/fesm2022/mesgflow-ui-kit-scroll-area.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-search-input.mjs +154 -0
- package/fesm2022/mesgflow-ui-kit-search-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-segmented-control.mjs +95 -0
- package/fesm2022/mesgflow-ui-kit-segmented-control.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-select.mjs +227 -0
- package/fesm2022/mesgflow-ui-kit-select.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-sidebar.mjs +449 -0
- package/fesm2022/mesgflow-ui-kit-sidebar.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-skeleton.mjs +74 -0
- package/fesm2022/mesgflow-ui-kit-skeleton.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-slider.mjs +179 -0
- package/fesm2022/mesgflow-ui-kit-slider.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-spinner.mjs +67 -0
- package/fesm2022/mesgflow-ui-kit-spinner.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-splitter.mjs +97 -0
- package/fesm2022/mesgflow-ui-kit-splitter.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-stat-tile.mjs +98 -0
- package/fesm2022/mesgflow-ui-kit-stat-tile.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-stepper.mjs +133 -0
- package/fesm2022/mesgflow-ui-kit-stepper.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-switch.mjs +73 -0
- package/fesm2022/mesgflow-ui-kit-switch.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-table.mjs +1783 -0
- package/fesm2022/mesgflow-ui-kit-table.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-tabs.mjs +569 -0
- package/fesm2022/mesgflow-ui-kit-tabs.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-tag-input.mjs +138 -0
- package/fesm2022/mesgflow-ui-kit-tag-input.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-theme-switcher.mjs +53 -0
- package/fesm2022/mesgflow-ui-kit-theme-switcher.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-theming.mjs +1016 -0
- package/fesm2022/mesgflow-ui-kit-theming.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-time-picker.mjs +138 -0
- package/fesm2022/mesgflow-ui-kit-time-picker.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-timeline.mjs +91 -0
- package/fesm2022/mesgflow-ui-kit-timeline.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-toast.mjs +202 -0
- package/fesm2022/mesgflow-ui-kit-toast.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-toggle.mjs +243 -0
- package/fesm2022/mesgflow-ui-kit-toggle.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-toolbar.mjs +99 -0
- package/fesm2022/mesgflow-ui-kit-toolbar.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-tooltip.mjs +160 -0
- package/fesm2022/mesgflow-ui-kit-tooltip.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-tour.mjs +272 -0
- package/fesm2022/mesgflow-ui-kit-tour.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-tree-select.mjs +177 -0
- package/fesm2022/mesgflow-ui-kit-tree-select.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit-tree.mjs +82 -0
- package/fesm2022/mesgflow-ui-kit-tree.mjs.map +1 -0
- package/fesm2022/mesgflow-ui-kit.mjs +12851 -0
- package/fesm2022/mesgflow-ui-kit.mjs.map +1 -0
- package/package.json +374 -0
- package/preset.css +20 -0
- package/tokens/color.css +693 -0
- package/tokens/contrast.css +68 -0
- package/tokens/elevation.css +68 -0
- package/tokens/motion.css +277 -0
- package/tokens/radius.css +69 -0
- package/tokens/typography.css +127 -0
- package/tokens.css +41 -0
- package/types/mesgflow-ui-kit-accordion.d.ts +42 -0
- package/types/mesgflow-ui-kit-alert.d.ts +60 -0
- package/types/mesgflow-ui-kit-avatar-group.d.ts +28 -0
- package/types/mesgflow-ui-kit-avatar.d.ts +23 -0
- package/types/mesgflow-ui-kit-badge.d.ts +39 -0
- package/types/mesgflow-ui-kit-banner.d.ts +42 -0
- package/types/mesgflow-ui-kit-box-input.d.ts +45 -0
- package/types/mesgflow-ui-kit-brand.d.ts +48 -0
- package/types/mesgflow-ui-kit-breadcrumb.d.ts +26 -0
- package/types/mesgflow-ui-kit-button-group.d.ts +17 -0
- package/types/mesgflow-ui-kit-button.d.ts +75 -0
- package/types/mesgflow-ui-kit-card.d.ts +71 -0
- package/types/mesgflow-ui-kit-chart.d.ts +242 -0
- package/types/mesgflow-ui-kit-checkbox.d.ts +17 -0
- package/types/mesgflow-ui-kit-chip.d.ts +46 -0
- package/types/mesgflow-ui-kit-code-block.d.ts +56 -0
- package/types/mesgflow-ui-kit-collapsible.d.ts +39 -0
- package/types/mesgflow-ui-kit-color-picker.d.ts +78 -0
- package/types/mesgflow-ui-kit-combobox.d.ts +74 -0
- package/types/mesgflow-ui-kit-command.d.ts +185 -0
- package/types/mesgflow-ui-kit-context-menu.d.ts +40 -0
- package/types/mesgflow-ui-kit-copy-button.d.ts +47 -0
- package/types/mesgflow-ui-kit-core.d.ts +508 -0
- package/types/mesgflow-ui-kit-date-picker.d.ts +215 -0
- package/types/mesgflow-ui-kit-description-list.d.ts +23 -0
- package/types/mesgflow-ui-kit-dialog.d.ts +342 -0
- package/types/mesgflow-ui-kit-divider.d.ts +23 -0
- package/types/mesgflow-ui-kit-dropzone.d.ts +47 -0
- package/types/mesgflow-ui-kit-empty-state.d.ts +18 -0
- package/types/mesgflow-ui-kit-field.d.ts +26 -0
- package/types/mesgflow-ui-kit-hover-card.d.ts +52 -0
- package/types/mesgflow-ui-kit-i18n-tr.d.ts +14 -0
- package/types/mesgflow-ui-kit-icon.d.ts +76 -0
- package/types/mesgflow-ui-kit-input.d.ts +186 -0
- package/types/mesgflow-ui-kit-kbd.d.ts +9 -0
- package/types/mesgflow-ui-kit-link.d.ts +20 -0
- package/types/mesgflow-ui-kit-menu.d.ts +53 -0
- package/types/mesgflow-ui-kit-number-input.d.ts +55 -0
- package/types/mesgflow-ui-kit-otp-input.d.ts +44 -0
- package/types/mesgflow-ui-kit-page-header.d.ts +31 -0
- package/types/mesgflow-ui-kit-pagination.d.ts +50 -0
- package/types/mesgflow-ui-kit-password-input.d.ts +33 -0
- package/types/mesgflow-ui-kit-popover.d.ts +62 -0
- package/types/mesgflow-ui-kit-progress.d.ts +32 -0
- package/types/mesgflow-ui-kit-radio.d.ts +59 -0
- package/types/mesgflow-ui-kit-rating.d.ts +56 -0
- package/types/mesgflow-ui-kit-scroll-area.d.ts +27 -0
- package/types/mesgflow-ui-kit-search-input.d.ts +72 -0
- package/types/mesgflow-ui-kit-segmented-control.d.ts +54 -0
- package/types/mesgflow-ui-kit-select.d.ts +89 -0
- package/types/mesgflow-ui-kit-sidebar.d.ts +224 -0
- package/types/mesgflow-ui-kit-skeleton.d.ts +29 -0
- package/types/mesgflow-ui-kit-slider.d.ts +40 -0
- package/types/mesgflow-ui-kit-spinner.d.ts +31 -0
- package/types/mesgflow-ui-kit-splitter.d.ts +40 -0
- package/types/mesgflow-ui-kit-stat-tile.d.ts +54 -0
- package/types/mesgflow-ui-kit-stepper.d.ts +48 -0
- package/types/mesgflow-ui-kit-switch.d.ts +34 -0
- package/types/mesgflow-ui-kit-table.d.ts +805 -0
- package/types/mesgflow-ui-kit-tabs.d.ts +269 -0
- package/types/mesgflow-ui-kit-tag-input.d.ts +33 -0
- package/types/mesgflow-ui-kit-theme-switcher.d.ts +27 -0
- package/types/mesgflow-ui-kit-theming.d.ts +745 -0
- package/types/mesgflow-ui-kit-time-picker.d.ts +54 -0
- package/types/mesgflow-ui-kit-timeline.d.ts +27 -0
- package/types/mesgflow-ui-kit-toast.d.ts +94 -0
- package/types/mesgflow-ui-kit-toggle.d.ts +110 -0
- package/types/mesgflow-ui-kit-toolbar.d.ts +52 -0
- package/types/mesgflow-ui-kit-tooltip.d.ts +55 -0
- package/types/mesgflow-ui-kit-tour.d.ts +66 -0
- package/types/mesgflow-ui-kit-tree-select.d.ts +65 -0
- package/types/mesgflow-ui-kit-tree.d.ts +44 -0
- package/types/mesgflow-ui-kit.d.ts +5444 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesgflow-ui-kit-tour.mjs","sources":["../../../projects/ui-kit/tour/tour.model.ts","../../../projects/ui-kit/tour/tour-card.ts","../../../projects/ui-kit/tour/tour-card.html","../../../projects/ui-kit/tour/tour-spotlight.ts","../../../projects/ui-kit/tour/tour.service.ts","../../../projects/ui-kit/tour/mesgflow-ui-kit-tour.ts"],"sourcesContent":["import { ElementRef, computed, signal } from '@angular/core';\r\n\r\nexport type TourPlacement = 'bottom' | 'top' | 'start' | 'end';\r\n\r\nexport interface TourStep {\r\n /**\r\n * Vurgulanacak öğe: CSS seçicisi, öğe ya da `ElementRef`. Verilmezse adım ekran ortasında\r\n * bir karşılama/kapanış kartı olarak gösterilir (spot ışığı deliksiz karartır).\r\n */\r\n target?: string | Element | ElementRef<Element>;\r\n title: string;\r\n content: string;\r\n /** Kartın hedefe göre yeri — mantıksal (`start`/`end` RTL'de yer değiştirir). Sığmazsa karşı taraf. */\r\n placement?: TourPlacement;\r\n}\r\n\r\nexport type TourResult = 'completed' | 'skipped';\r\n\r\nexport interface TourOptions {\r\n /** Hedefin çevresindeki boşluk (px). */\r\n padding?: number;\r\n /** Her adım değişiminde (0 tabanlı indeks) — analitik ya da hedefin görünür olması için. */\r\n stepChange?: (index: number, step: TourStep) => void;\r\n}\r\n\r\nexport interface SpotlightRect {\r\n top: number;\r\n left: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\n/** Bir tur çalışmasının durumu — servis ile spot ışığı ve kart bileşenleri bunu paylaşır. */\r\nexport class TourRun {\r\n readonly index = signal(0);\r\n /** Hedefin viewport'taki kutusu (padding dahil); hedefsiz adımda `null`. */\r\n readonly rect = signal<SpotlightRect | null>(null);\r\n\r\n readonly step = computed(() => this.steps[this.index()]!);\r\n readonly isFirst = computed(() => this.index() === 0);\r\n readonly isLast = computed(() => this.index() === this.steps.length - 1);\r\n\r\n constructor(\r\n readonly steps: readonly TourStep[],\r\n private readonly onNavigate: (index: number) => void,\r\n private readonly onFinish: (result: TourResult) => void,\r\n ) {}\r\n\r\n next(): void {\r\n if (this.isLast()) this.onFinish('completed');\r\n else this.onNavigate(this.index() + 1);\r\n }\r\n\r\n back(): void {\r\n if (!this.isFirst()) this.onNavigate(this.index() - 1);\r\n }\r\n\r\n skip(): void {\r\n this.onFinish('skipped');\r\n }\r\n}\r\n","import { A11yModule } from '@angular/cdk/a11y';\r\nimport { Component, ElementRef, afterRenderEffect, inject } from '@angular/core';\r\nimport { Button } from '@mesgflow/ui-kit/button';\r\nimport { MF_TOUR_LABELS } from '@mesgflow/ui-kit/core';\r\nimport { Icon } from '@mesgflow/ui-kit/icon';\r\nimport { TourRun } from './tour.model';\r\n\r\nlet tourCardIdSeq = 0;\r\n\r\n/**\r\n * Adım kartı — modal `role=\"dialog\"`, odak kartın içinde tutulur (`cdkTrapFocus`). Her adım\r\n * değişiminde odak kartın KENDİSİNE taşınır: ekran okuyucu `aria-labelledby` (başlık) +\r\n * `aria-describedby` (içerik) üzerinden yeni adımı baştan okur. Esc turu atlar.\r\n */\r\n@Component({\r\n selector: 'mf-tour-card',\r\n imports: [A11yModule, Button, Icon],\r\n templateUrl: './tour-card.html',\r\n})\r\nexport class TourCard {\r\n protected readonly run = inject(TourRun);\r\n protected readonly labels = inject(MF_TOUR_LABELS);\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n\r\n private readonly id = `mf-tour-${++tourCardIdSeq}`;\r\n protected readonly titleId = `${this.id}-title`;\r\n protected readonly contentId = `${this.id}-content`;\r\n\r\n constructor() {\r\n afterRenderEffect(() => {\r\n this.run.index();\r\n this.host.nativeElement.querySelector<HTMLElement>('[role=\"dialog\"]')?.focus();\r\n });\r\n }\r\n}\r\n","<div\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n tabindex=\"-1\"\r\n cdkTrapFocus\r\n [attr.aria-labelledby]=\"titleId\"\r\n [attr.aria-describedby]=\"contentId\"\r\n class=\"w-[min(20rem,calc(100vw-2rem))] animate-overlay-in rounded-xl border border-hairline bg-overlay p-4 shadow-3 outline-none\"\r\n (keydown.escape)=\"run.skip()\"\r\n>\r\n <div class=\"flex items-center justify-between gap-2\">\r\n <span class=\"font-mono text-eyebrow text-help uppercase tabular-nums\">\r\n {{ run.index() + 1 }} {{ labels().stepOf }} {{ run.steps.length }}\r\n </span>\r\n <button\r\n type=\"button\"\r\n class=\"-me-1.5 inline-flex size-7 cursor-pointer appearance-none items-center justify-center rounded-md border-0 bg-transparent text-fg-subtle transition-colors duration-fast ease-emphasis hover:bg-state-hover hover:text-fg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring\"\r\n [attr.aria-label]=\"labels().skip\"\r\n (click)=\"run.skip()\"\r\n >\r\n <span mfIcon [size]=\"16\">close</span>\r\n </button>\r\n </div>\r\n\r\n <h2 [id]=\"titleId\" class=\"mt-1.5 font-display text-base font-semibold text-fg\">\r\n {{ run.step().title }}\r\n </h2>\r\n <p [id]=\"contentId\" class=\"mt-1 text-sm text-fg-muted\">{{ run.step().content }}</p>\r\n\r\n <div class=\"mt-4 flex items-center gap-2\">\r\n <!-- İlerleme: adım başına bir çizgi; salt görsel, sayı zaten yukarıda. -->\r\n <div class=\"flex flex-1 items-center gap-1\" aria-hidden=\"true\">\r\n @for (step of run.steps; track $index) {\r\n <span\r\n class=\"h-1 flex-1 rounded-full transition-colors duration-base ease-emphasis\"\r\n [class]=\"$index <= run.index() ? 'bg-help' : 'bg-surface-alt'\"\r\n ></span>\r\n }\r\n </div>\r\n @if (!run.isFirst()) {\r\n <button\r\n mfButton\r\n appearance=\"text\"\r\n tone=\"neutral\"\r\n size=\"sm\"\r\n type=\"button\"\r\n (click)=\"run.back()\"\r\n >\r\n {{ labels().back }}\r\n </button>\r\n }\r\n <button mfButton tone=\"help\" size=\"sm\" type=\"button\" (click)=\"run.next()\">\r\n {{ run.isLast() ? labels().done : labels().next }}\r\n </button>\r\n </div>\r\n</div>\r\n","import { Component, inject } from '@angular/core';\r\nimport { TourRun } from './tour.model';\r\n\r\n/** Dialog arka planıyla aynı karartma (bkz. motion.css `.mf-dialog-backdrop`), biraz daha koyu. */\r\nconst SCRIM = 'color-mix(in srgb, var(--color-neutral-975) 55%, transparent)';\r\n\r\n/**\r\n * Tam ekran katman: tıklamaları yutar (tur modal) ve hedefin çevresi dışını karartır. Delik,\r\n * hedef kutusuna oturan bir öğenin çok büyük `box-shadow`'u — maske/SVG yolu gerekmez, konumu\r\n * `transition` ile adımlar arasında kayar. Hedefsiz adımda düz karartma.\r\n */\r\n@Component({\r\n selector: 'mf-tour-spotlight',\r\n host: { class: 'fixed inset-0 block' },\r\n template: `\r\n @if (run.rect(); as rect) {\r\n <div class=\"absolute inset-0\" aria-hidden=\"true\"></div>\r\n <div\r\n aria-hidden=\"true\"\r\n class=\"pointer-events-none fixed rounded-lg outline outline-2 outline-offset-0 outline-help transition-[top,left,width,height] duration-base ease-emphasis\"\r\n [style.top.px]=\"rect.top\"\r\n [style.left.px]=\"rect.left\"\r\n [style.width.px]=\"rect.width\"\r\n [style.height.px]=\"rect.height\"\r\n [style.box-shadow]=\"'0 0 0 200vmax ' + scrim\"\r\n ></div>\r\n } @else {\r\n <div class=\"absolute inset-0\" aria-hidden=\"true\" [style.background-color]=\"scrim\"></div>\r\n }\r\n `,\r\n})\r\nexport class TourSpotlight {\r\n protected readonly run = inject(TourRun);\r\n protected readonly scrim = SCRIM;\r\n}\r\n","import {\r\n createFlexibleConnectedPositionStrategy,\r\n createGlobalPositionStrategy,\r\n createOverlayRef,\r\n createRepositionScrollStrategy,\r\n type ConnectedPosition,\r\n type OverlayRef,\r\n} from '@angular/cdk/overlay';\r\nimport { ComponentPortal } from '@angular/cdk/portal';\r\nimport { DOCUMENT, ElementRef, Injector, Service, inject } from '@angular/core';\r\nimport { isRtl } from '@mesgflow/ui-kit/core';\r\nimport { TourCard } from './tour-card';\r\nimport {\r\n TourRun,\r\n type SpotlightRect,\r\n type TourOptions,\r\n type TourPlacement,\r\n type TourResult,\r\n type TourStep,\r\n} from './tour.model';\r\nimport { TourSpotlight } from './tour-spotlight';\r\n\r\nconst GAP = 12;\r\nconst DEFAULT_PADDING = 6;\r\n\r\n/** Tercih edilen taraf önce, sığmazsa karşısı, sonra diğer eksen. */\r\nconst POSITIONS: Record<TourPlacement, ConnectedPosition[]> = {\r\n bottom: [\r\n { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: GAP },\r\n { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -GAP },\r\n ],\r\n top: [\r\n { originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom', offsetY: -GAP },\r\n { originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top', offsetY: GAP },\r\n ],\r\n end: [\r\n { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: GAP },\r\n { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -GAP },\r\n ],\r\n start: [\r\n { originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center', offsetX: -GAP },\r\n { originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center', offsetX: GAP },\r\n ],\r\n};\r\n\r\n/**\r\n * `const result = await tour.start([{ target: '#new-campaign', title: '…', content: '…' }, …]);`\r\n *\r\n * Ürün turu / coachmark — `help` tonu tam bunun için. İki overlay: tam ekran spot ışığı (karartır,\r\n * tıklamaları yutar) ve hedefe bağlı adım kartı. Her adımda hedef görünür alana kaydırılır\r\n * (azaltılmış harekette anında), kaydırma/yeniden boyutlandırmada delik ve kart birlikte izler.\r\n * Bulunamayan hedef ortalanmış karta düşer (tur kırılmaz). Aynı anda tek tur; bitince odak\r\n * turdan önceki öğeye döner. Sonuç: `'completed'` ya da `'skipped'` (Esc, ×).\r\n */\r\n@Service()\r\nexport class TourService {\r\n private readonly injector = inject(Injector);\r\n private readonly document = inject(DOCUMENT);\r\n private active: Promise<TourResult> | null = null;\r\n\r\n get isActive(): boolean {\r\n return this.active !== null;\r\n }\r\n\r\n start(steps: readonly TourStep[], options: TourOptions = {}): Promise<TourResult> {\r\n if (this.active) return this.active;\r\n if (steps.length === 0) return Promise.resolve('completed');\r\n\r\n this.active = new Promise<TourResult>((resolve) => {\r\n const doc = this.document;\r\n const view = doc.defaultView;\r\n const padding = options.padding ?? DEFAULT_PADDING;\r\n const previousFocus = doc.activeElement as HTMLElement | null;\r\n const direction = isRtl(doc.documentElement) ? 'rtl' : 'ltr';\r\n let target: Element | null = null;\r\n let frame = 0;\r\n\r\n const run: TourRun = new TourRun(\r\n steps,\r\n (index) => show(index),\r\n (result) => finish(result),\r\n );\r\n const injector = Injector.create({\r\n providers: [{ provide: TourRun, useValue: run }],\r\n parent: this.injector,\r\n });\r\n\r\n const spotlight = createOverlayRef(this.injector, {\r\n positionStrategy: createGlobalPositionStrategy(this.injector),\r\n width: '100vw',\r\n height: '100vh',\r\n direction,\r\n });\r\n spotlight.attach(new ComponentPortal(TourSpotlight, null, injector));\r\n\r\n const card: OverlayRef = createOverlayRef(this.injector, { direction });\r\n\r\n const measure = () => {\r\n frame = 0;\r\n if (!target) {\r\n run.rect.set(null);\r\n return;\r\n }\r\n const box = target.getBoundingClientRect();\r\n run.rect.set({\r\n top: box.top - padding,\r\n left: box.left - padding,\r\n width: box.width + padding * 2,\r\n height: box.height + padding * 2,\r\n } satisfies SpotlightRect);\r\n card.updatePosition();\r\n };\r\n const schedule = () => {\r\n if (!frame) frame = view?.requestAnimationFrame(measure) ?? 0;\r\n };\r\n\r\n const place = (step: TourStep) => {\r\n const strategy = target\r\n ? createFlexibleConnectedPositionStrategy(this.injector, target as HTMLElement)\r\n .withPositions(POSITIONS[step.placement ?? 'bottom'])\r\n .withViewportMargin(12)\r\n .withPush(true)\r\n : createGlobalPositionStrategy(this.injector).centerHorizontally().centerVertically();\r\n card.updatePositionStrategy(strategy);\r\n card.updateScrollStrategy(createRepositionScrollStrategy(this.injector));\r\n };\r\n\r\n const show = (index: number) => {\r\n const step = steps[index]!;\r\n target = resolveTarget(step.target, doc);\r\n run.index.set(index);\r\n options.stepChange?.(index, step);\r\n if (target) {\r\n const reduced = view?.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? true;\r\n (target as HTMLElement).scrollIntoView?.({\r\n block: 'center',\r\n inline: 'nearest',\r\n behavior: reduced ? 'auto' : 'smooth',\r\n });\r\n }\r\n place(step);\r\n if (!card.hasAttached()) card.attach(new ComponentPortal(TourCard, null, injector));\r\n measure();\r\n };\r\n\r\n const finish = (result: TourResult) => {\r\n view?.removeEventListener('scroll', schedule, true);\r\n view?.removeEventListener('resize', schedule);\r\n if (frame) view?.cancelAnimationFrame(frame);\r\n card.dispose();\r\n spotlight.dispose();\r\n this.active = null;\r\n previousFocus?.focus?.();\r\n resolve(result);\r\n };\r\n\r\n view?.addEventListener('scroll', schedule, true);\r\n view?.addEventListener('resize', schedule);\r\n show(0);\r\n });\r\n\r\n return this.active;\r\n }\r\n}\r\n\r\nfunction resolveTarget(target: TourStep['target'], doc: Document): Element | null {\r\n if (!target) return null;\r\n if (typeof target === 'string') return doc.querySelector(target);\r\n return target instanceof ElementRef ? target.nativeElement : target;\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;;AAgCA;MACa,OAAO,CAAA;AAUP,IAAA,KAAA;AACQ,IAAA,UAAA;AACA,IAAA,QAAA;IAXV,KAAK,GAAG,MAAM,CAAC,CAAC;8EAAC;;IAEjB,IAAI,GAAG,MAAM,CAAuB,IAAI;6EAAC;AAEzC,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAE;6EAAC;IAChD,OAAO,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC;gFAAC;AAC5C,IAAA,MAAM,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;+EAAC;AAExE,IAAA,WAAA,CACW,KAA0B,EAClB,UAAmC,EACnC,QAAsC,EAAA;QAF9C,IAAA,CAAA,KAAK,GAAL,KAAK;QACG,IAAA,CAAA,UAAU,GAAV,UAAU;QACV,IAAA,CAAA,QAAQ,GAAR,QAAQ;IACxB;IAEH,IAAI,GAAA;QACF,IAAI,IAAI,CAAC,MAAM,EAAE;AAAE,YAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;;YACxC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACxC;IAEA,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACxD;IAEA,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC1B;AACD;;ACrDD,IAAI,aAAa,GAAG,CAAC;AAErB;;;;AAIG;MAMU,QAAQ,CAAA;AACA,IAAA,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;AACrB,IAAA,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC;AACjC,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC;AAElD,IAAA,EAAE,GAAG,CAAA,QAAA,EAAW,EAAE,aAAa,EAAE;AAC/B,IAAA,OAAO,GAAG,CAAA,EAAG,IAAI,CAAC,EAAE,QAAQ;AAC5B,IAAA,SAAS,GAAG,CAAA,EAAG,IAAI,CAAC,EAAE,UAAU;AAEnD,IAAA,WAAA,GAAA;QACE,iBAAiB,CAAC,MAAK;AACrB,YAAA,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;AAChB,YAAA,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,CAAc,iBAAiB,CAAC,EAAE,KAAK,EAAE;AAChF,QAAA,CAAC,CAAC;IACJ;uGAdW,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAR,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAQ,wECnBrB,k0EAwDA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDxCY,UAAU,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,cAAA,EAAA,yBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,MAAM,8LAAE,IAAI,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;2FAGvB,QAAQ,EAAA,UAAA,EAAA,CAAA;kBALpB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,WACf,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,EAAA,QAAA,EAAA,k0EAAA,EAAA;;;AEbrC;AACA,MAAM,KAAK,GAAG,+DAA+D;AAE7E;;;;AAIG;MAqBU,aAAa,CAAA;AACL,IAAA,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;IACrB,KAAK,GAAG,KAAK;uGAFrB,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,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,qBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAjBd,CAAA;;;;;;;;;;;;;;;AAeT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA;;2FAEU,aAAa,EAAA,UAAA,EAAA,CAAA;kBApBzB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE;AACtC,oBAAA,QAAQ,EAAE,CAAA;;;;;;;;;;;;;;;AAeT,EAAA,CAAA;AACF,iBAAA;;;ACRD,MAAM,GAAG,GAAG,EAAE;AACd,MAAM,eAAe,GAAG,CAAC;AAEzB;AACA,MAAM,SAAS,GAA+C;AAC5D,IAAA,MAAM,EAAE;AACN,QAAA,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;QAC3F,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE;AAC7F,KAAA;AACD,IAAA,GAAG,EAAE;QACH,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE;AAC5F,QAAA,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;AAC5F,KAAA;AACD,IAAA,GAAG,EAAE;AACH,QAAA,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;QAC1F,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE;AAC5F,KAAA;AACD,IAAA,KAAK,EAAE;QACL,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE;AAC3F,QAAA,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;AAC3F,KAAA;CACF;AAED;;;;;;;;AAQG;MAEU,WAAW,CAAA;AACL,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IACpC,MAAM,GAA+B,IAAI;AAEjD,IAAA,IAAI,QAAQ,GAAA;AACV,QAAA,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI;IAC7B;AAEA,IAAA,KAAK,CAAC,KAA0B,EAAE,OAAA,GAAuB,EAAE,EAAA;QACzD,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM;AACnC,QAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;QAE3D,IAAI,CAAC,MAAM,GAAG,IAAI,OAAO,CAAa,CAAC,OAAO,KAAI;AAChD,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ;AACzB,YAAA,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW;AAC5B,YAAA,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,eAAe;AAClD,YAAA,MAAM,aAAa,GAAG,GAAG,CAAC,aAAmC;AAC7D,YAAA,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,KAAK,GAAG,KAAK;YAC5D,IAAI,MAAM,GAAmB,IAAI;YACjC,IAAI,KAAK,GAAG,CAAC;YAEb,MAAM,GAAG,GAAY,IAAI,OAAO,CAC9B,KAAK,EACL,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,EACtB,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAC3B;AACD,YAAA,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;gBAC/B,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;gBAChD,MAAM,EAAE,IAAI,CAAC,QAAQ;AACtB,aAAA,CAAC;AAEF,YAAA,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE;AAChD,gBAAA,gBAAgB,EAAE,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC7D,gBAAA,KAAK,EAAE,OAAO;AACd,gBAAA,MAAM,EAAE,OAAO;gBACf,SAAS;AACV,aAAA,CAAC;AACF,YAAA,SAAS,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,aAAa,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAEpE,YAAA,MAAM,IAAI,GAAe,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC;YAEvE,MAAM,OAAO,GAAG,MAAK;gBACnB,KAAK,GAAG,CAAC;gBACT,IAAI,CAAC,MAAM,EAAE;AACX,oBAAA,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;oBAClB;gBACF;AACA,gBAAA,MAAM,GAAG,GAAG,MAAM,CAAC,qBAAqB,EAAE;AAC1C,gBAAA,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AACX,oBAAA,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,OAAO;AACtB,oBAAA,IAAI,EAAE,GAAG,CAAC,IAAI,GAAG,OAAO;AACxB,oBAAA,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,OAAO,GAAG,CAAC;AAC9B,oBAAA,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,GAAG,CAAC;AACT,iBAAA,CAAC;gBAC1B,IAAI,CAAC,cAAc,EAAE;AACvB,YAAA,CAAC;YACD,MAAM,QAAQ,GAAG,MAAK;AACpB,gBAAA,IAAI,CAAC,KAAK;oBAAE,KAAK,GAAG,IAAI,EAAE,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC;AAC/D,YAAA,CAAC;AAED,YAAA,MAAM,KAAK,GAAG,CAAC,IAAc,KAAI;gBAC/B,MAAM,QAAQ,GAAG;sBACb,uCAAuC,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAqB;yBACzE,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC;yBACnD,kBAAkB,CAAC,EAAE;yBACrB,QAAQ,CAAC,IAAI;AAClB,sBAAE,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,kBAAkB,EAAE,CAAC,gBAAgB,EAAE;AACvF,gBAAA,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC;gBACrC,IAAI,CAAC,oBAAoB,CAAC,8BAA8B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC1E,YAAA,CAAC;AAED,YAAA,MAAM,IAAI,GAAG,CAAC,KAAa,KAAI;AAC7B,gBAAA,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAE;gBAC1B,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC;AACxC,gBAAA,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;gBACpB,OAAO,CAAC,UAAU,GAAG,KAAK,EAAE,IAAI,CAAC;gBACjC,IAAI,MAAM,EAAE;AACV,oBAAA,MAAM,OAAO,GAAG,IAAI,EAAE,UAAU,GAAG,kCAAkC,CAAC,CAAC,OAAO,IAAI,IAAI;oBACrF,MAAsB,CAAC,cAAc,GAAG;AACvC,wBAAA,KAAK,EAAE,QAAQ;AACf,wBAAA,MAAM,EAAE,SAAS;wBACjB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ;AACtC,qBAAA,CAAC;gBACJ;gBACA,KAAK,CAAC,IAAI,CAAC;AACX,gBAAA,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AAAE,oBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnF,gBAAA,OAAO,EAAE;AACX,YAAA,CAAC;AAED,YAAA,MAAM,MAAM,GAAG,CAAC,MAAkB,KAAI;gBACpC,IAAI,EAAE,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC;AACnD,gBAAA,IAAI,EAAE,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC;AAC7C,gBAAA,IAAI,KAAK;AAAE,oBAAA,IAAI,EAAE,oBAAoB,CAAC,KAAK,CAAC;gBAC5C,IAAI,CAAC,OAAO,EAAE;gBACd,SAAS,CAAC,OAAO,EAAE;AACnB,gBAAA,IAAI,CAAC,MAAM,GAAG,IAAI;AAClB,gBAAA,aAAa,EAAE,KAAK,IAAI;gBACxB,OAAO,CAAC,MAAM,CAAC;AACjB,YAAA,CAAC;YAED,IAAI,EAAE,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC;AAChD,YAAA,IAAI,EAAE,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC;YAC1C,IAAI,CAAC,CAAC,CAAC;AACT,QAAA,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC,MAAM;IACpB;uGA3GW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,OAAA,EAAA,CAAA;wGAAX,WAAW,EAAA,CAAA;;2FAAX,WAAW,EAAA,UAAA,EAAA,CAAA;kBADvB;;AA+GD,SAAS,aAAa,CAAC,MAA0B,EAAE,GAAa,EAAA;AAC9D,IAAA,IAAI,CAAC,MAAM;AAAE,QAAA,OAAO,IAAI;IACxB,IAAI,OAAO,MAAM,KAAK,QAAQ;AAAE,QAAA,OAAO,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC;AAChE,IAAA,OAAO,MAAM,YAAY,UAAU,GAAG,MAAM,CAAC,aAAa,GAAG,MAAM;AACrE;;ACzKA;;AAEG;;"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import * as i1 from '@angular/cdk/overlay';
|
|
2
|
+
import { OverlayModule } from '@angular/cdk/overlay';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { input, model, booleanAttribute, inject, viewChild, signal, computed, afterRenderEffect, untracked, forwardRef, Component } from '@angular/core';
|
|
5
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
|
+
import { Chip } from '@mesgflow/ui-kit/chip';
|
|
7
|
+
import { ValueAccessorBase, MF_TREE_SELECT_LABELS, cn } from '@mesgflow/ui-kit/core';
|
|
8
|
+
import { Icon } from '@mesgflow/ui-kit/icon';
|
|
9
|
+
import { Input } from '@mesgflow/ui-kit/input';
|
|
10
|
+
import { Popover } from '@mesgflow/ui-kit/popover';
|
|
11
|
+
import { selectTriggerVariants } from '@mesgflow/ui-kit/select';
|
|
12
|
+
import { Tree } from '@mesgflow/ui-kit/tree';
|
|
13
|
+
|
|
14
|
+
/** Küçük harf + aksan atma + ı→i — "istanbul" "İstanbul"u, "cagri" "Çağrı"yı bulur. */
|
|
15
|
+
function fold(text) {
|
|
16
|
+
return text.toLocaleLowerCase().normalize('NFD').replace(/\p{M}/gu, '').replace(/ı/g, 'i');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Etiketi sorguyu içeren düğümleri, ATALARIYLA birlikte tutar (bağlam kaybolmasın — "Kadıköy"
|
|
20
|
+
* bulunduğunda "İstanbul › Kadıköy" yolu görünür). Eşleşen bir düğümün çocukları da kalır
|
|
21
|
+
* (bir kategoriyi aramak altındakileri de gösterir). Boş sorgu ağacı aynen döner.
|
|
22
|
+
*/
|
|
23
|
+
function filterTree(nodes, query) {
|
|
24
|
+
const q = fold(query.trim());
|
|
25
|
+
if (!q)
|
|
26
|
+
return [...nodes];
|
|
27
|
+
const walk = (list) => list.flatMap((node) => {
|
|
28
|
+
if (fold(node.label).includes(q))
|
|
29
|
+
return [node];
|
|
30
|
+
const children = node.children ? walk(node.children) : [];
|
|
31
|
+
return children.length ? [{ ...node, children }] : [];
|
|
32
|
+
});
|
|
33
|
+
return walk(nodes);
|
|
34
|
+
}
|
|
35
|
+
/** `value → label` eşlemesi (tetikleyici metni/yongaları için) — değer kimliğiyle (`===`). */
|
|
36
|
+
function flattenTree(nodes) {
|
|
37
|
+
const map = new Map();
|
|
38
|
+
const walk = (list) => list.forEach((node) => {
|
|
39
|
+
map.set(node.value, node.label);
|
|
40
|
+
if (node.children)
|
|
41
|
+
walk(node.children);
|
|
42
|
+
});
|
|
43
|
+
walk(nodes);
|
|
44
|
+
return map;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* `<mf-tree-select [nodes]="regions" [(value)]="chosen" multi searchable />`
|
|
49
|
+
*
|
|
50
|
+
* Hiyerarşik seçenekler için Select — kategori, bölge, klasör. Tetikleyici Select ile AYNI
|
|
51
|
+
* görünüm (çoklu seçimde yongalar + "+N"); panel kitin `Tree`'si (WAI-ARIA tree: oklar, Home/End,
|
|
52
|
+
* yazarak ara, Enter/Space seçim — `@angular/aria/tree`'den).
|
|
53
|
+
*
|
|
54
|
+
* `searchable`: panelin başında aksan duyarsız arama — eşleşmeler ATALARIYLA tutulur ve dallar
|
|
55
|
+
* açılır (bkz. `filterTree`). Tek seçimde seçim paneli kapatır ve odağı tetikleyiciye döndürür;
|
|
56
|
+
* çoklu seçimde panel açık kalır. `value` her zaman dizi (Tree ile aynı sözleşme).
|
|
57
|
+
*/
|
|
58
|
+
class TreeSelect extends ValueAccessorBase {
|
|
59
|
+
nodes = input.required(/* @ts-ignore */
|
|
60
|
+
...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
|
|
61
|
+
value = model([], /* @ts-ignore */
|
|
62
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
63
|
+
multi = input(false, { ...(ngDevMode ? { debugName: "multi" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
64
|
+
searchable = input(false, { ...(ngDevMode ? { debugName: "searchable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
65
|
+
placeholder = input(/* @ts-ignore */
|
|
66
|
+
...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
67
|
+
size = input('md', /* @ts-ignore */
|
|
68
|
+
...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
69
|
+
hasError = input(false, /* @ts-ignore */
|
|
70
|
+
...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
|
|
71
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
72
|
+
/** Tetikleyicinin (ve ağacın) erişilebilir adı — görünür bir etiket yoksa zorunlu. */
|
|
73
|
+
ariaLabel = input('', /* @ts-ignore */
|
|
74
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
75
|
+
maxVisibleChips = input(2, /* @ts-ignore */
|
|
76
|
+
...(ngDevMode ? [{ debugName: "maxVisibleChips" }] : /* istanbul ignore next */ []));
|
|
77
|
+
labels = inject(MF_TREE_SELECT_LABELS);
|
|
78
|
+
trigger = viewChild.required('trigger', /* @ts-ignore */
|
|
79
|
+
...(ngDevMode ? [{ debugName: "trigger" }] : /* istanbul ignore next */ []));
|
|
80
|
+
panel = viewChild('panel', /* @ts-ignore */
|
|
81
|
+
...(ngDevMode ? [{ debugName: "panel" }] : /* istanbul ignore next */ []));
|
|
82
|
+
open = signal(false, /* @ts-ignore */
|
|
83
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
84
|
+
query = signal('', /* @ts-ignore */
|
|
85
|
+
...(ngDevMode ? [{ debugName: "query" }] : /* istanbul ignore next */ []));
|
|
86
|
+
formDisabled = signal(false, /* @ts-ignore */
|
|
87
|
+
...(ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []));
|
|
88
|
+
isDisabled = computed(() => this.disabled() || this.formDisabled(), /* @ts-ignore */
|
|
89
|
+
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
90
|
+
effectivePlaceholder = computed(() => this.placeholder() ?? this.labels().placeholder, /* @ts-ignore */
|
|
91
|
+
...(ngDevMode ? [{ debugName: "effectivePlaceholder" }] : /* istanbul ignore next */ []));
|
|
92
|
+
visibleNodes = computed(() => filterTree(this.nodes(), this.query()), /* @ts-ignore */
|
|
93
|
+
...(ngDevMode ? [{ debugName: "visibleNodes" }] : /* istanbul ignore next */ []));
|
|
94
|
+
searching = computed(() => this.query().trim().length > 0, /* @ts-ignore */
|
|
95
|
+
...(ngDevMode ? [{ debugName: "searching" }] : /* istanbul ignore next */ []));
|
|
96
|
+
labelByValue = computed(() => flattenTree(this.nodes()), /* @ts-ignore */
|
|
97
|
+
...(ngDevMode ? [{ debugName: "labelByValue" }] : /* istanbul ignore next */ []));
|
|
98
|
+
selectedLabels = computed(() => this.value()
|
|
99
|
+
.map((v) => this.labelByValue().get(v))
|
|
100
|
+
.filter((label) => !!label), /* @ts-ignore */
|
|
101
|
+
...(ngDevMode ? [{ debugName: "selectedLabels" }] : /* istanbul ignore next */ []));
|
|
102
|
+
visibleChips = computed(() => this.selectedLabels().slice(0, this.maxVisibleChips()), /* @ts-ignore */
|
|
103
|
+
...(ngDevMode ? [{ debugName: "visibleChips" }] : /* istanbul ignore next */ []));
|
|
104
|
+
overflowCount = computed(() => Math.max(0, this.selectedLabels().length - this.maxVisibleChips()), /* @ts-ignore */
|
|
105
|
+
...(ngDevMode ? [{ debugName: "overflowCount" }] : /* istanbul ignore next */ []));
|
|
106
|
+
triggerClasses = computed(() => cn(selectTriggerVariants({ size: this.size(), hasError: this.hasError() })), /* @ts-ignore */
|
|
107
|
+
...(ngDevMode ? [{ debugName: "triggerClasses" }] : /* istanbul ignore next */ []));
|
|
108
|
+
constructor() {
|
|
109
|
+
super();
|
|
110
|
+
// Panel açılınca odağı içeri taşı: arama kutusu, yoksa ağacın ETKİN öğesi. Ağaç dolaşan
|
|
111
|
+
// tabindex kullanır — tuşlar `tabindex="0"` olan treeitem'da işlenir; `role="tree"` kabına
|
|
112
|
+
// odak vermek oklarla gezinmeyi ölü bırakıyordu (gerçek tarayıcıda yakalandı).
|
|
113
|
+
afterRenderEffect(() => {
|
|
114
|
+
if (!this.open())
|
|
115
|
+
return;
|
|
116
|
+
const panel = this.panel()?.nativeElement;
|
|
117
|
+
untracked(() => panel
|
|
118
|
+
?.querySelector('input, [role="treeitem"][tabindex="0"], [role="treeitem"]')
|
|
119
|
+
?.focus());
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
toggle() {
|
|
123
|
+
if (this.isDisabled())
|
|
124
|
+
return;
|
|
125
|
+
if (this.open())
|
|
126
|
+
this.close(false);
|
|
127
|
+
else {
|
|
128
|
+
this.query.set('');
|
|
129
|
+
this.open.set(true);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
onTriggerKeydown(event) {
|
|
133
|
+
if (event.key === 'ArrowDown' && !this.open()) {
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
this.toggle();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
onTreeValue(values) {
|
|
139
|
+
const next = this.multi() ? values : values.slice(-1);
|
|
140
|
+
const changed = next.length !== this.value().length || next.some((v, i) => v !== this.value()[i]);
|
|
141
|
+
if (!changed)
|
|
142
|
+
return;
|
|
143
|
+
this.value.set(next);
|
|
144
|
+
this.onChange(next);
|
|
145
|
+
this.onTouched();
|
|
146
|
+
if (!this.multi() && next.length)
|
|
147
|
+
this.close(true);
|
|
148
|
+
}
|
|
149
|
+
close(restoreFocus) {
|
|
150
|
+
this.open.set(false);
|
|
151
|
+
if (restoreFocus)
|
|
152
|
+
this.trigger().nativeElement.focus();
|
|
153
|
+
}
|
|
154
|
+
writeValue(value) {
|
|
155
|
+
this.value.set(value ?? []);
|
|
156
|
+
}
|
|
157
|
+
setDisabledState(disabled) {
|
|
158
|
+
this.formDisabled.set(disabled);
|
|
159
|
+
}
|
|
160
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: TreeSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
161
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: TreeSelect, isStandalone: true, selector: "mf-tree-select", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleChips: { classPropertyName: "maxVisibleChips", publicName: "maxVisibleChips", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { classAttribute: "block" }, providers: [
|
|
162
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TreeSelect), multi: true },
|
|
163
|
+
], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["trigger"], descendants: true, isSignal: true }, { propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], exportAs: ["mfTreeSelect"], usesInheritance: true, ngImport: i0, template: "<button\r\n #trigger\r\n type=\"button\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n [class]=\"triggerClasses()\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-expanded]=\"open()\"\r\n aria-haspopup=\"tree\"\r\n (click)=\"toggle()\"\r\n (keydown)=\"onTriggerKeydown($event)\"\r\n>\r\n @if (selectedLabels().length === 0) {\r\n <span class=\"truncate text-fg-subtle\">{{ effectivePlaceholder() }}</span>\r\n } @else if (multi()) {\r\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1\">\r\n @for (label of visibleChips(); track label) {\r\n <mf-chip size=\"sm\">{{ label }}</mf-chip>\r\n }\r\n @if (overflowCount() > 0) {\r\n <mf-chip size=\"sm\">+{{ overflowCount() }}</mf-chip>\r\n }\r\n </span>\r\n } @else {\r\n <span class=\"truncate\">{{ selectedLabels()[0] }}</span>\r\n }\r\n <span mfIcon [size]=\"18\" class=\"shrink-0 text-fg-subtle\">unfold_more</span>\r\n</button>\r\n\r\n<mf-popover\r\n [origin]=\"origin\"\r\n [open]=\"open()\"\r\n placement=\"bottom-start\"\r\n padding=\"sm\"\r\n [matchTriggerWidth]=\"true\"\r\n (closed)=\"close(true)\"\r\n>\r\n <div #panel class=\"flex max-h-80 flex-col gap-1\">\r\n @if (searchable()) {\r\n <input\r\n mfInput\r\n size=\"sm\"\r\n type=\"search\"\r\n autocomplete=\"off\"\r\n [placeholder]=\"labels().searchPlaceholder\"\r\n [attr.aria-label]=\"labels().searchPlaceholder\"\r\n [value]=\"query()\"\r\n (input)=\"query.set($any($event.target).value)\"\r\n />\r\n }\r\n <div class=\"min-h-0 overflow-y-auto\">\r\n @if (visibleNodes().length === 0) {\r\n <p class=\"px-2.5 py-6 text-center text-sm text-fg-subtle\" role=\"status\">\r\n {{ labels().noResults }}\r\n </p>\r\n } @else {\r\n <mf-tree\r\n [nodes]=\"visibleNodes()\"\r\n [value]=\"value()\"\r\n (valueChange)=\"onTreeValue($event)\"\r\n [multi]=\"multi()\"\r\n [expandAll]=\"searching()\"\r\n [ariaLabel]=\"ariaLabel() || effectivePlaceholder()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n</mf-popover>\r\n", dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: Chip, selector: "mf-chip", inputs: ["tone", "size", "selected", "disabled", "removable", "removeLabel"], outputs: ["removed"], exportAs: ["mfChip"] }, { kind: "directive", type: Icon, selector: "span[mfIcon]", inputs: ["size", "filled"] }, { kind: "directive", type: Input, selector: "input[mfInput]:not([type=checkbox]):not([type=radio]), textarea[mfInput]", inputs: ["size", "hasError", "autosize", "minRows", "maxRows"] }, { kind: "component", type: Popover, selector: "mf-popover", inputs: ["origin", "open", "placement", "padding", "hasBackdrop", "matchTriggerWidth", "panelClass"], outputs: ["openChange", "closed"], exportAs: ["mfPopover"] }, { kind: "component", type: Tree, selector: "mf-tree", inputs: ["nodes", "value", "multi", "ariaLabel", "expandAll"], outputs: ["valueChange"], exportAs: ["mfTree"] }] });
|
|
164
|
+
}
|
|
165
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: TreeSelect, decorators: [{
|
|
166
|
+
type: Component,
|
|
167
|
+
args: [{ selector: 'mf-tree-select', exportAs: 'mfTreeSelect', imports: [OverlayModule, Chip, Icon, Input, Popover, Tree], host: { class: 'block' }, providers: [
|
|
168
|
+
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TreeSelect), multi: true },
|
|
169
|
+
], template: "<button\r\n #trigger\r\n type=\"button\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n [class]=\"triggerClasses()\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-expanded]=\"open()\"\r\n aria-haspopup=\"tree\"\r\n (click)=\"toggle()\"\r\n (keydown)=\"onTriggerKeydown($event)\"\r\n>\r\n @if (selectedLabels().length === 0) {\r\n <span class=\"truncate text-fg-subtle\">{{ effectivePlaceholder() }}</span>\r\n } @else if (multi()) {\r\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1\">\r\n @for (label of visibleChips(); track label) {\r\n <mf-chip size=\"sm\">{{ label }}</mf-chip>\r\n }\r\n @if (overflowCount() > 0) {\r\n <mf-chip size=\"sm\">+{{ overflowCount() }}</mf-chip>\r\n }\r\n </span>\r\n } @else {\r\n <span class=\"truncate\">{{ selectedLabels()[0] }}</span>\r\n }\r\n <span mfIcon [size]=\"18\" class=\"shrink-0 text-fg-subtle\">unfold_more</span>\r\n</button>\r\n\r\n<mf-popover\r\n [origin]=\"origin\"\r\n [open]=\"open()\"\r\n placement=\"bottom-start\"\r\n padding=\"sm\"\r\n [matchTriggerWidth]=\"true\"\r\n (closed)=\"close(true)\"\r\n>\r\n <div #panel class=\"flex max-h-80 flex-col gap-1\">\r\n @if (searchable()) {\r\n <input\r\n mfInput\r\n size=\"sm\"\r\n type=\"search\"\r\n autocomplete=\"off\"\r\n [placeholder]=\"labels().searchPlaceholder\"\r\n [attr.aria-label]=\"labels().searchPlaceholder\"\r\n [value]=\"query()\"\r\n (input)=\"query.set($any($event.target).value)\"\r\n />\r\n }\r\n <div class=\"min-h-0 overflow-y-auto\">\r\n @if (visibleNodes().length === 0) {\r\n <p class=\"px-2.5 py-6 text-center text-sm text-fg-subtle\" role=\"status\">\r\n {{ labels().noResults }}\r\n </p>\r\n } @else {\r\n <mf-tree\r\n [nodes]=\"visibleNodes()\"\r\n [value]=\"value()\"\r\n (valueChange)=\"onTreeValue($event)\"\r\n [multi]=\"multi()\"\r\n [expandAll]=\"searching()\"\r\n [ariaLabel]=\"ariaLabel() || effectivePlaceholder()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n</mf-popover>\r\n" }]
|
|
170
|
+
}], ctorParameters: () => [], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], maxVisibleChips: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleChips", required: false }] }], trigger: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Generated bundle index. Do not edit.
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
export { TreeSelect, filterTree, flattenTree };
|
|
177
|
+
//# sourceMappingURL=mesgflow-ui-kit-tree-select.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesgflow-ui-kit-tree-select.mjs","sources":["../../../projects/ui-kit/tree-select/tree-filter.ts","../../../projects/ui-kit/tree-select/tree-select.ts","../../../projects/ui-kit/tree-select/tree-select.html","../../../projects/ui-kit/tree-select/mesgflow-ui-kit-tree-select.ts"],"sourcesContent":["import type { TreeNode } from '@mesgflow/ui-kit/tree';\r\n\r\n/** Küçük harf + aksan atma + ı→i — \"istanbul\" \"İstanbul\"u, \"cagri\" \"Çağrı\"yı bulur. */\r\nfunction fold(text: string): string {\r\n return text.toLocaleLowerCase().normalize('NFD').replace(/\\p{M}/gu, '').replace(/ı/g, 'i');\r\n}\r\n\r\n/**\r\n * Etiketi sorguyu içeren düğümleri, ATALARIYLA birlikte tutar (bağlam kaybolmasın — \"Kadıköy\"\r\n * bulunduğunda \"İstanbul › Kadıköy\" yolu görünür). Eşleşen bir düğümün çocukları da kalır\r\n * (bir kategoriyi aramak altındakileri de gösterir). Boş sorgu ağacı aynen döner.\r\n */\r\nexport function filterTree<T>(nodes: readonly TreeNode<T>[], query: string): TreeNode<T>[] {\r\n const q = fold(query.trim());\r\n if (!q) return [...nodes];\r\n const walk = (list: readonly TreeNode<T>[]): TreeNode<T>[] =>\r\n list.flatMap((node) => {\r\n if (fold(node.label).includes(q)) return [node];\r\n const children = node.children ? walk(node.children) : [];\r\n return children.length ? [{ ...node, children }] : [];\r\n });\r\n return walk(nodes);\r\n}\r\n\r\n/** `value → label` eşlemesi (tetikleyici metni/yongaları için) — değer kimliğiyle (`===`). */\r\nexport function flattenTree<T>(nodes: readonly TreeNode<T>[]): Map<T, string> {\r\n const map = new Map<T, string>();\r\n const walk = (list: readonly TreeNode<T>[]) =>\r\n list.forEach((node) => {\r\n map.set(node.value, node.label);\r\n if (node.children) walk(node.children);\r\n });\r\n walk(nodes);\r\n return map;\r\n}\r\n","import { OverlayModule } from '@angular/cdk/overlay';\r\nimport {\r\n Component,\r\n ElementRef,\r\n afterRenderEffect,\r\n booleanAttribute,\r\n computed,\r\n forwardRef,\r\n inject,\r\n input,\r\n model,\r\n signal,\r\n untracked,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms';\r\nimport { Chip } from '@mesgflow/ui-kit/chip';\r\nimport { MF_TREE_SELECT_LABELS, ValueAccessorBase, cn, type MfSize } from '@mesgflow/ui-kit/core';\r\nimport { Icon } from '@mesgflow/ui-kit/icon';\r\nimport { Input } from '@mesgflow/ui-kit/input';\r\nimport { Popover } from '@mesgflow/ui-kit/popover';\r\nimport { selectTriggerVariants } from '@mesgflow/ui-kit/select';\r\nimport { Tree, type TreeNode } from '@mesgflow/ui-kit/tree';\r\nimport { filterTree, flattenTree } from './tree-filter';\r\n\r\n/**\r\n * `<mf-tree-select [nodes]=\"regions\" [(value)]=\"chosen\" multi searchable />`\r\n *\r\n * Hiyerarşik seçenekler için Select — kategori, bölge, klasör. Tetikleyici Select ile AYNI\r\n * görünüm (çoklu seçimde yongalar + \"+N\"); panel kitin `Tree`'si (WAI-ARIA tree: oklar, Home/End,\r\n * yazarak ara, Enter/Space seçim — `@angular/aria/tree`'den).\r\n *\r\n * `searchable`: panelin başında aksan duyarsız arama — eşleşmeler ATALARIYLA tutulur ve dallar\r\n * açılır (bkz. `filterTree`). Tek seçimde seçim paneli kapatır ve odağı tetikleyiciye döndürür;\r\n * çoklu seçimde panel açık kalır. `value` her zaman dizi (Tree ile aynı sözleşme).\r\n */\r\n@Component({\r\n selector: 'mf-tree-select',\r\n exportAs: 'mfTreeSelect',\r\n imports: [OverlayModule, Chip, Icon, Input, Popover, Tree],\r\n host: { class: 'block' },\r\n templateUrl: './tree-select.html',\r\n providers: [\r\n { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TreeSelect), multi: true },\r\n ],\r\n})\r\nexport class TreeSelect<T> extends ValueAccessorBase<T[]> implements ControlValueAccessor {\r\n readonly nodes = input.required<TreeNode<T>[]>();\r\n readonly value = model<T[]>([]);\r\n readonly multi = input(false, { transform: booleanAttribute });\r\n readonly searchable = input(false, { transform: booleanAttribute });\r\n readonly placeholder = input<string>();\r\n readonly size = input<MfSize>('md');\r\n readonly hasError = input(false);\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n /** Tetikleyicinin (ve ağacın) erişilebilir adı — görünür bir etiket yoksa zorunlu. */\r\n readonly ariaLabel = input('');\r\n readonly maxVisibleChips = input(2);\r\n\r\n protected readonly labels = inject(MF_TREE_SELECT_LABELS);\r\n private readonly trigger = viewChild.required<ElementRef<HTMLButtonElement>>('trigger');\r\n private readonly panel = viewChild<ElementRef<HTMLElement>>('panel');\r\n\r\n protected readonly open = signal(false);\r\n protected readonly query = signal('');\r\n private readonly formDisabled = signal(false);\r\n\r\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\r\n protected readonly effectivePlaceholder = computed(\r\n () => this.placeholder() ?? this.labels().placeholder,\r\n );\r\n protected readonly visibleNodes = computed(() => filterTree(this.nodes(), this.query()));\r\n protected readonly searching = computed(() => this.query().trim().length > 0);\r\n\r\n private readonly labelByValue = computed(() => flattenTree(this.nodes()));\r\n protected readonly selectedLabels = computed(() =>\r\n this.value()\r\n .map((v) => this.labelByValue().get(v))\r\n .filter((label): label is string => !!label),\r\n );\r\n protected readonly visibleChips = computed(() =>\r\n this.selectedLabels().slice(0, this.maxVisibleChips()),\r\n );\r\n protected readonly overflowCount = computed(() =>\r\n Math.max(0, this.selectedLabels().length - this.maxVisibleChips()),\r\n );\r\n\r\n protected readonly triggerClasses = computed(() =>\r\n cn(selectTriggerVariants({ size: this.size(), hasError: this.hasError() })),\r\n );\r\n\r\n constructor() {\r\n super();\r\n // Panel açılınca odağı içeri taşı: arama kutusu, yoksa ağacın ETKİN öğesi. Ağaç dolaşan\r\n // tabindex kullanır — tuşlar `tabindex=\"0\"` olan treeitem'da işlenir; `role=\"tree\"` kabına\r\n // odak vermek oklarla gezinmeyi ölü bırakıyordu (gerçek tarayıcıda yakalandı).\r\n afterRenderEffect(() => {\r\n if (!this.open()) return;\r\n const panel = this.panel()?.nativeElement;\r\n untracked(() =>\r\n panel\r\n ?.querySelector<HTMLElement>('input, [role=\"treeitem\"][tabindex=\"0\"], [role=\"treeitem\"]')\r\n ?.focus(),\r\n );\r\n });\r\n }\r\n\r\n protected toggle(): void {\r\n if (this.isDisabled()) return;\r\n if (this.open()) this.close(false);\r\n else {\r\n this.query.set('');\r\n this.open.set(true);\r\n }\r\n }\r\n\r\n protected onTriggerKeydown(event: KeyboardEvent): void {\r\n if (event.key === 'ArrowDown' && !this.open()) {\r\n event.preventDefault();\r\n this.toggle();\r\n }\r\n }\r\n\r\n protected onTreeValue(values: T[]): void {\r\n const next = this.multi() ? values : values.slice(-1);\r\n const changed =\r\n next.length !== this.value().length || next.some((v, i) => v !== this.value()[i]);\r\n if (!changed) return;\r\n this.value.set(next);\r\n this.onChange(next);\r\n this.onTouched();\r\n if (!this.multi() && next.length) this.close(true);\r\n }\r\n\r\n protected close(restoreFocus: boolean): void {\r\n this.open.set(false);\r\n if (restoreFocus) this.trigger().nativeElement.focus();\r\n }\r\n\r\n writeValue(value: T[] | null): void {\r\n this.value.set(value ?? []);\r\n }\r\n\r\n setDisabledState(disabled: boolean): void {\r\n this.formDisabled.set(disabled);\r\n }\r\n}\r\n","<button\r\n #trigger\r\n type=\"button\"\r\n cdkOverlayOrigin\r\n #origin=\"cdkOverlayOrigin\"\r\n [class]=\"triggerClasses()\"\r\n [disabled]=\"isDisabled()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n [attr.aria-expanded]=\"open()\"\r\n aria-haspopup=\"tree\"\r\n (click)=\"toggle()\"\r\n (keydown)=\"onTriggerKeydown($event)\"\r\n>\r\n @if (selectedLabels().length === 0) {\r\n <span class=\"truncate text-fg-subtle\">{{ effectivePlaceholder() }}</span>\r\n } @else if (multi()) {\r\n <span class=\"flex min-w-0 flex-1 flex-wrap items-center gap-1\">\r\n @for (label of visibleChips(); track label) {\r\n <mf-chip size=\"sm\">{{ label }}</mf-chip>\r\n }\r\n @if (overflowCount() > 0) {\r\n <mf-chip size=\"sm\">+{{ overflowCount() }}</mf-chip>\r\n }\r\n </span>\r\n } @else {\r\n <span class=\"truncate\">{{ selectedLabels()[0] }}</span>\r\n }\r\n <span mfIcon [size]=\"18\" class=\"shrink-0 text-fg-subtle\">unfold_more</span>\r\n</button>\r\n\r\n<mf-popover\r\n [origin]=\"origin\"\r\n [open]=\"open()\"\r\n placement=\"bottom-start\"\r\n padding=\"sm\"\r\n [matchTriggerWidth]=\"true\"\r\n (closed)=\"close(true)\"\r\n>\r\n <div #panel class=\"flex max-h-80 flex-col gap-1\">\r\n @if (searchable()) {\r\n <input\r\n mfInput\r\n size=\"sm\"\r\n type=\"search\"\r\n autocomplete=\"off\"\r\n [placeholder]=\"labels().searchPlaceholder\"\r\n [attr.aria-label]=\"labels().searchPlaceholder\"\r\n [value]=\"query()\"\r\n (input)=\"query.set($any($event.target).value)\"\r\n />\r\n }\r\n <div class=\"min-h-0 overflow-y-auto\">\r\n @if (visibleNodes().length === 0) {\r\n <p class=\"px-2.5 py-6 text-center text-sm text-fg-subtle\" role=\"status\">\r\n {{ labels().noResults }}\r\n </p>\r\n } @else {\r\n <mf-tree\r\n [nodes]=\"visibleNodes()\"\r\n [value]=\"value()\"\r\n (valueChange)=\"onTreeValue($event)\"\r\n [multi]=\"multi()\"\r\n [expandAll]=\"searching()\"\r\n [ariaLabel]=\"ariaLabel() || effectivePlaceholder()\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n</mf-popover>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Tree as Tree$1, TreeItem, TreeItemGroup } from '@angular/aria/tree';
|
|
2
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { input, model, effect, forwardRef, Component } from '@angular/core';
|
|
5
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
|
+
import { Icon } from '@mesgflow/ui-kit/icon';
|
|
7
|
+
import { ValueAccessorBase, cn } from '@mesgflow/ui-kit/core';
|
|
8
|
+
import { cva } from 'class-variance-authority';
|
|
9
|
+
|
|
10
|
+
const treeRowVariants = cva('flex cursor-pointer items-center gap-1 rounded-sm py-1 pe-2 text-fg-muted transition-colors duration-fast ease-emphasis ' +
|
|
11
|
+
'focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-focus-ring', {
|
|
12
|
+
variants: {
|
|
13
|
+
selected: {
|
|
14
|
+
true: 'bg-primary-tint text-primary-tint-fg',
|
|
15
|
+
false: 'hover:bg-surface-alt hover:text-fg',
|
|
16
|
+
},
|
|
17
|
+
disabled: {
|
|
18
|
+
true: 'pointer-events-none opacity-50',
|
|
19
|
+
false: '',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: { selected: false, disabled: false },
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* `<mf-tree [nodes]="layers" [(value)]="selectedIds" />` — katman/yapı
|
|
27
|
+
* paneli gibi iç içe, klavye gezintili ağaçlar için. ARIA/klavye (ok
|
|
28
|
+
* tuşları, typeahead, seviyeye göre girinti) `@angular/aria/tree`'nin
|
|
29
|
+
* `Tree`/`TreeItem`/`TreeItemGroup` pattern'inden geliyor — dokümantasyonun
|
|
30
|
+
* KENDİ önerdiği ÖZYİNELEMELİ (`ngTemplateOutlet` + kendi kendine referans
|
|
31
|
+
* veren `#treeNodes` template) render deseni birebir izlendi, çünkü veri
|
|
32
|
+
* derinliği (`TreeNode.children`) derleme zamanında bilinmiyor.
|
|
33
|
+
*/
|
|
34
|
+
class Tree extends ValueAccessorBase {
|
|
35
|
+
nodes = input.required(/* @ts-ignore */
|
|
36
|
+
...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
|
|
37
|
+
value = model([], /* @ts-ignore */
|
|
38
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
39
|
+
multi = input(false, /* @ts-ignore */
|
|
40
|
+
...(ngDevMode ? [{ debugName: "multi" }] : /* istanbul ignore next */ []));
|
|
41
|
+
ariaLabel = input('', /* @ts-ignore */
|
|
42
|
+
...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
43
|
+
/** Tüm dalları açık başlatır (ör. arama sonuçları) — kullanıcı yine tek tek kapatabilir. */
|
|
44
|
+
expandAll = input(false, /* @ts-ignore */
|
|
45
|
+
...(ngDevMode ? [{ debugName: "expandAll" }] : /* istanbul ignore next */ []));
|
|
46
|
+
constructor() {
|
|
47
|
+
super();
|
|
48
|
+
// `value()` `ngTree`'nin KENDİ iç seçim mantığından İKİ-YÖNLÜ bağlamayla
|
|
49
|
+
// (tree.html `[(value)]`) değişiyor — tek bir "seçim değişti" metodu YOK,
|
|
50
|
+
// bu yüzden CVA bildirimini bir effect ile köprülüyoruz. İLK çalışma
|
|
51
|
+
// (kurulumda, henüz gerçek bir kullanıcı etkileşimi YOKKEN) atlanır.
|
|
52
|
+
let first = true;
|
|
53
|
+
effect(() => {
|
|
54
|
+
const v = this.value();
|
|
55
|
+
if (first) {
|
|
56
|
+
first = false;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.onChange(v);
|
|
60
|
+
this.onTouched();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
writeValue(value) {
|
|
64
|
+
this.value.set(value);
|
|
65
|
+
}
|
|
66
|
+
rowClasses(selected, disabled) {
|
|
67
|
+
return cn(treeRowVariants({ selected: !!selected, disabled }));
|
|
68
|
+
}
|
|
69
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: Tree, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
70
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: Tree, isStandalone: true, selector: "mf-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, expandAll: { classPropertyName: "expandAll", publicName: "expandAll", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { classAttribute: "block" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Tree), multi: true }], exportAs: ["mfTree"], usesInheritance: true, ngImport: i0, template: "<ul\r\n ngTree\r\n #treeRef=\"ngTree\"\r\n [(value)]=\"value\"\r\n [multi]=\"multi()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n class=\"text-sm\"\r\n>\r\n <ng-template\r\n [ngTemplateOutlet]=\"treeNodes\"\r\n [ngTemplateOutletContext]=\"{ $implicit: nodes(), parent: treeRef }\"\r\n />\r\n</ul>\r\n\r\n<ng-template #treeNodes let-nodes let-parent=\"parent\">\r\n @for (node of nodes; track node.id) {\r\n <li\r\n ngTreeItem\r\n #item=\"ngTreeItem\"\r\n [parent]=\"parent\"\r\n [value]=\"node.value\"\r\n [label]=\"node.label\"\r\n [disabled]=\"!!node.disabled\"\r\n [expanded]=\"expandAll()\"\r\n >\r\n <span\r\n [class]=\"rowClasses(item.selected(), !!node.disabled)\"\r\n [style.padding-inline-start.px]=\"item.level() * 16\"\r\n >\r\n @if (node.children && node.children.length > 0) {\r\n <span\r\n mfIcon\r\n [size]=\"16\"\r\n class=\"shrink-0 transition-transform duration-fast rtl:-scale-x-100\"\r\n [class.rotate-90]=\"item.expanded()\"\r\n [class.rtl:-rotate-90]=\"item.expanded()\"\r\n >chevron_right</span\r\n >\r\n } @else {\r\n <span class=\"w-4 shrink-0\" aria-hidden=\"true\"></span>\r\n }\r\n <span class=\"truncate\">{{ node.label }}</span>\r\n </span>\r\n @if (node.children && node.children.length > 0) {\r\n <ul role=\"group\">\r\n <ng-template ngTreeItemGroup [ownedBy]=\"item\" #group=\"ngTreeItemGroup\">\r\n <ng-template\r\n [ngTemplateOutlet]=\"treeNodes\"\r\n [ngTemplateOutletContext]=\"{ $implicit: node.children, parent: group }\"\r\n />\r\n </ng-template>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n", dependencies: [{ kind: "directive", type: Tree$1, selector: "[ngTree]", inputs: ["id", "orientation", "multi", "disabled", "selectionMode", "focusMode", "wrap", "softDisabled", "typeaheadDelay", "tabindex", "value", "nav", "currentType"], outputs: ["valueChange"], exportAs: ["ngTree"] }, { kind: "directive", type: TreeItem, selector: "[ngTreeItem]", inputs: ["id", "value", "parent", "disabled", "selectable", "expanded", "label"], outputs: ["expandedChange"], exportAs: ["ngTreeItem"] }, { kind: "directive", type: TreeItemGroup, selector: "ng-template[ngTreeItemGroup]", inputs: ["ownedBy"], exportAs: ["ngTreeItemGroup"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: Icon, selector: "span[mfIcon]", inputs: ["size", "filled"] }] });
|
|
71
|
+
}
|
|
72
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: Tree, decorators: [{
|
|
73
|
+
type: Component,
|
|
74
|
+
args: [{ selector: 'mf-tree', exportAs: 'mfTree', host: { class: 'block' }, imports: [Tree$1, TreeItem, TreeItemGroup, NgTemplateOutlet, Icon], providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Tree), multi: true }], template: "<ul\r\n ngTree\r\n #treeRef=\"ngTree\"\r\n [(value)]=\"value\"\r\n [multi]=\"multi()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n class=\"text-sm\"\r\n>\r\n <ng-template\r\n [ngTemplateOutlet]=\"treeNodes\"\r\n [ngTemplateOutletContext]=\"{ $implicit: nodes(), parent: treeRef }\"\r\n />\r\n</ul>\r\n\r\n<ng-template #treeNodes let-nodes let-parent=\"parent\">\r\n @for (node of nodes; track node.id) {\r\n <li\r\n ngTreeItem\r\n #item=\"ngTreeItem\"\r\n [parent]=\"parent\"\r\n [value]=\"node.value\"\r\n [label]=\"node.label\"\r\n [disabled]=\"!!node.disabled\"\r\n [expanded]=\"expandAll()\"\r\n >\r\n <span\r\n [class]=\"rowClasses(item.selected(), !!node.disabled)\"\r\n [style.padding-inline-start.px]=\"item.level() * 16\"\r\n >\r\n @if (node.children && node.children.length > 0) {\r\n <span\r\n mfIcon\r\n [size]=\"16\"\r\n class=\"shrink-0 transition-transform duration-fast rtl:-scale-x-100\"\r\n [class.rotate-90]=\"item.expanded()\"\r\n [class.rtl:-rotate-90]=\"item.expanded()\"\r\n >chevron_right</span\r\n >\r\n } @else {\r\n <span class=\"w-4 shrink-0\" aria-hidden=\"true\"></span>\r\n }\r\n <span class=\"truncate\">{{ node.label }}</span>\r\n </span>\r\n @if (node.children && node.children.length > 0) {\r\n <ul role=\"group\">\r\n <ng-template ngTreeItemGroup [ownedBy]=\"item\" #group=\"ngTreeItemGroup\">\r\n <ng-template\r\n [ngTemplateOutlet]=\"treeNodes\"\r\n [ngTemplateOutletContext]=\"{ $implicit: node.children, parent: group }\"\r\n />\r\n </ng-template>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n" }]
|
|
75
|
+
}], ctorParameters: () => [], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], expandAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandAll", required: false }] }] } });
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Generated bundle index. Do not edit.
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
export { Tree, treeRowVariants };
|
|
82
|
+
//# sourceMappingURL=mesgflow-ui-kit-tree.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesgflow-ui-kit-tree.mjs","sources":["../../../projects/ui-kit/tree/tree.variants.ts","../../../projects/ui-kit/tree/tree.ts","../../../projects/ui-kit/tree/tree.html","../../../projects/ui-kit/tree/mesgflow-ui-kit-tree.ts"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\r\n\r\nexport const treeRowVariants = cva(\r\n 'flex cursor-pointer items-center gap-1 rounded-sm py-1 pe-2 text-fg-muted transition-colors duration-fast ease-emphasis ' +\r\n 'focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-focus-ring',\r\n {\r\n variants: {\r\n selected: {\r\n true: 'bg-primary-tint text-primary-tint-fg',\r\n false: 'hover:bg-surface-alt hover:text-fg',\r\n },\r\n disabled: {\r\n true: 'pointer-events-none opacity-50',\r\n false: '',\r\n },\r\n },\r\n defaultVariants: { selected: false, disabled: false },\r\n },\r\n);\r\n\r\nexport type TreeRowSelected = VariantProps<typeof treeRowVariants>['selected'];\r\n","import {\r\n Tree as AriaTree,\r\n TreeItem as AriaTreeItem,\r\n TreeItemGroup as AriaTreeItemGroup,\r\n} from '@angular/aria/tree';\r\nimport { NgTemplateOutlet } from '@angular/common';\r\nimport { Component, effect, forwardRef, input, model } from '@angular/core';\r\nimport { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms';\r\nimport { Icon } from '@mesgflow/ui-kit/icon';\r\nimport { ValueAccessorBase, cn } from '@mesgflow/ui-kit/core';\r\nimport { treeRowVariants } from './tree.variants';\r\n\r\nexport interface TreeNode<T> {\r\n id: string;\r\n label: string;\r\n value: T;\r\n children?: TreeNode<T>[];\r\n disabled?: boolean;\r\n}\r\n\r\n/**\r\n * `<mf-tree [nodes]=\"layers\" [(value)]=\"selectedIds\" />` — katman/yapı\r\n * paneli gibi iç içe, klavye gezintili ağaçlar için. ARIA/klavye (ok\r\n * tuşları, typeahead, seviyeye göre girinti) `@angular/aria/tree`'nin\r\n * `Tree`/`TreeItem`/`TreeItemGroup` pattern'inden geliyor — dokümantasyonun\r\n * KENDİ önerdiği ÖZYİNELEMELİ (`ngTemplateOutlet` + kendi kendine referans\r\n * veren `#treeNodes` template) render deseni birebir izlendi, çünkü veri\r\n * derinliği (`TreeNode.children`) derleme zamanında bilinmiyor.\r\n */\r\n@Component({\r\n selector: 'mf-tree',\r\n exportAs: 'mfTree',\r\n host: { class: 'block' },\r\n imports: [AriaTree, AriaTreeItem, AriaTreeItemGroup, NgTemplateOutlet, Icon],\r\n templateUrl: './tree.html',\r\n providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => Tree), multi: true }],\r\n})\r\nexport class Tree<T> extends ValueAccessorBase<T[]> implements ControlValueAccessor {\r\n readonly nodes = input.required<TreeNode<T>[]>();\r\n readonly value = model<T[]>([]);\r\n readonly multi = input(false);\r\n readonly ariaLabel = input('');\r\n /** Tüm dalları açık başlatır (ör. arama sonuçları) — kullanıcı yine tek tek kapatabilir. */\r\n readonly expandAll = input(false);\r\n\r\n constructor() {\r\n super();\r\n // `value()` `ngTree`'nin KENDİ iç seçim mantığından İKİ-YÖNLÜ bağlamayla\r\n // (tree.html `[(value)]`) değişiyor — tek bir \"seçim değişti\" metodu YOK,\r\n // bu yüzden CVA bildirimini bir effect ile köprülüyoruz. İLK çalışma\r\n // (kurulumda, henüz gerçek bir kullanıcı etkileşimi YOKKEN) atlanır.\r\n let first = true;\r\n effect(() => {\r\n const v = this.value();\r\n if (first) {\r\n first = false;\r\n return;\r\n }\r\n this.onChange(v);\r\n this.onTouched();\r\n });\r\n }\r\n\r\n writeValue(value: T[]): void {\r\n this.value.set(value);\r\n }\r\n\r\n protected rowClasses(selected: boolean | undefined, disabled: boolean): string {\r\n return cn(treeRowVariants({ selected: !!selected, disabled }));\r\n }\r\n}\r\n","<ul\r\n ngTree\r\n #treeRef=\"ngTree\"\r\n [(value)]=\"value\"\r\n [multi]=\"multi()\"\r\n [attr.aria-label]=\"ariaLabel() || null\"\r\n class=\"text-sm\"\r\n>\r\n <ng-template\r\n [ngTemplateOutlet]=\"treeNodes\"\r\n [ngTemplateOutletContext]=\"{ $implicit: nodes(), parent: treeRef }\"\r\n />\r\n</ul>\r\n\r\n<ng-template #treeNodes let-nodes let-parent=\"parent\">\r\n @for (node of nodes; track node.id) {\r\n <li\r\n ngTreeItem\r\n #item=\"ngTreeItem\"\r\n [parent]=\"parent\"\r\n [value]=\"node.value\"\r\n [label]=\"node.label\"\r\n [disabled]=\"!!node.disabled\"\r\n [expanded]=\"expandAll()\"\r\n >\r\n <span\r\n [class]=\"rowClasses(item.selected(), !!node.disabled)\"\r\n [style.padding-inline-start.px]=\"item.level() * 16\"\r\n >\r\n @if (node.children && node.children.length > 0) {\r\n <span\r\n mfIcon\r\n [size]=\"16\"\r\n class=\"shrink-0 transition-transform duration-fast rtl:-scale-x-100\"\r\n [class.rotate-90]=\"item.expanded()\"\r\n [class.rtl:-rotate-90]=\"item.expanded()\"\r\n >chevron_right</span\r\n >\r\n } @else {\r\n <span class=\"w-4 shrink-0\" aria-hidden=\"true\"></span>\r\n }\r\n <span class=\"truncate\">{{ node.label }}</span>\r\n </span>\r\n @if (node.children && node.children.length > 0) {\r\n <ul role=\"group\">\r\n <ng-template ngTreeItemGroup [ownedBy]=\"item\" #group=\"ngTreeItemGroup\">\r\n <ng-template\r\n [ngTemplateOutlet]=\"treeNodes\"\r\n [ngTemplateOutletContext]=\"{ $implicit: node.children, parent: group }\"\r\n />\r\n </ng-template>\r\n </ul>\r\n }\r\n </li>\r\n }\r\n</ng-template>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["AriaTree","AriaTreeItem","AriaTreeItemGroup"],"mappings":"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"}
|