@lifecorner/angular-ui-kit 3.4.1 → 3.5.1
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 +12 -2
- package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs +454 -0
- package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-alert.mjs +297 -0
- package/fesm2022/lifecorner-angular-ui-kit-alert.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-app-shell.mjs +190 -0
- package/fesm2022/lifecorner-angular-ui-kit-app-shell.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-area-chart.mjs +446 -0
- package/fesm2022/lifecorner-angular-ui-kit-area-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-avatar-group.mjs +158 -0
- package/fesm2022/lifecorner-angular-ui-kit-avatar-group.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-avatar.mjs +216 -0
- package/fesm2022/lifecorner-angular-ui-kit-avatar.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-badge.mjs +121 -0
- package/fesm2022/lifecorner-angular-ui-kit-badge.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-bar-chart.mjs +360 -0
- package/fesm2022/lifecorner-angular-ui-kit-bar-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs +344 -0
- package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-breadcrumbs.mjs +191 -0
- package/fesm2022/lifecorner-angular-ui-kit-breadcrumbs.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs +423 -0
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-calendar.mjs +368 -0
- package/fesm2022/lifecorner-angular-ui-kit-calendar.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-callout.mjs +203 -0
- package/fesm2022/lifecorner-angular-ui-kit-callout.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs +323 -0
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-chat.mjs +790 -0
- package/fesm2022/lifecorner-angular-ui-kit-chat.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-checkbox.mjs +325 -0
- package/fesm2022/lifecorner-angular-ui-kit-checkbox.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-chip.mjs +214 -0
- package/fesm2022/lifecorner-angular-ui-kit-chip.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-choice-prompt.mjs +375 -0
- package/fesm2022/lifecorner-angular-ui-kit-choice-prompt.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-code-block.mjs +518 -0
- package/fesm2022/lifecorner-angular-ui-kit-code-block.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-color-picker.mjs +278 -0
- package/fesm2022/lifecorner-angular-ui-kit-color-picker.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs +688 -0
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs +494 -0
- package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-container.mjs +103 -0
- package/fesm2022/lifecorner-angular-ui-kit-container.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs +308 -0
- package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-date-range-picker.mjs +466 -0
- package/fesm2022/lifecorner-angular-ui-kit-date-range-picker.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-datepicker.mjs +810 -0
- package/fesm2022/lifecorner-angular-ui-kit-datepicker.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-dependency-viewer.mjs +1761 -0
- package/fesm2022/lifecorner-angular-ui-kit-dependency-viewer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs +165 -0
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-diff-viewer.mjs +356 -0
- package/fesm2022/lifecorner-angular-ui-kit-diff-viewer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-divider.mjs +119 -0
- package/fesm2022/lifecorner-angular-ui-kit-divider.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs +762 -0
- package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-donut-chart.mjs +255 -0
- package/fesm2022/lifecorner-angular-ui-kit-donut-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs +308 -0
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-email-input.mjs +519 -0
- package/fesm2022/lifecorner-angular-ui-kit-email-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-empty-state.mjs +143 -0
- package/fesm2022/lifecorner-angular-ui-kit-empty-state.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-error-display.mjs +306 -0
- package/fesm2022/lifecorner-angular-ui-kit-error-display.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-field-group.mjs +154 -0
- package/fesm2022/lifecorner-angular-ui-kit-field-group.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs +281 -0
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-filter-bar.mjs +258 -0
- package/fesm2022/lifecorner-angular-ui-kit-filter-bar.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-footer.mjs +200 -0
- package/fesm2022/lifecorner-angular-ui-kit-footer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-funnel-chart.mjs +292 -0
- package/fesm2022/lifecorner-angular-ui-kit-funnel-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs +563 -0
- package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-gantt-chart.mjs +314 -0
- package/fesm2022/lifecorner-angular-ui-kit-gantt-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-gauge.mjs +265 -0
- package/fesm2022/lifecorner-angular-ui-kit-gauge.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs +955 -0
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-heatmap.mjs +305 -0
- package/fesm2022/lifecorner-angular-ui-kit-heatmap.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-hero.mjs +168 -0
- package/fesm2022/lifecorner-angular-ui-kit-hero.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-icon-names.mjs +9 -0
- package/fesm2022/lifecorner-angular-ui-kit-icon-names.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-icon.mjs +1026 -0
- package/fesm2022/lifecorner-angular-ui-kit-icon.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-input.mjs +595 -0
- package/fesm2022/lifecorner-angular-ui-kit-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-chart.mjs +105 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-overlay.mjs +50 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-overlay.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-url.mjs +22 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-url.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs +319 -0
- package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-line-chart.mjs +413 -0
- package/fesm2022/lifecorner-angular-ui-kit-line-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs +338 -0
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs +813 -0
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-logo.mjs +226 -0
- package/fesm2022/lifecorner-angular-ui-kit-logo.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-markdown.mjs +756 -0
- package/fesm2022/lifecorner-angular-ui-kit-markdown.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-menu.mjs +321 -0
- package/fesm2022/lifecorner-angular-ui-kit-menu.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-modal.mjs +329 -0
- package/fesm2022/lifecorner-angular-ui-kit-modal.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-models.mjs +0 -0
- package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs +419 -0
- package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +644 -0
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-number-input.mjs +401 -0
- package/fesm2022/lifecorner-angular-ui-kit-number-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-page-header.mjs +266 -0
- package/fesm2022/lifecorner-angular-ui-kit-page-header.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-page-layout.mjs +127 -0
- package/fesm2022/lifecorner-angular-ui-kit-page-layout.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-pagination.mjs +343 -0
- package/fesm2022/lifecorner-angular-ui-kit-pagination.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-password-input.mjs +696 -0
- package/fesm2022/lifecorner-angular-ui-kit-password-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-pie-chart.mjs +162 -0
- package/fesm2022/lifecorner-angular-ui-kit-pie-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs +159 -0
- package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-popover.mjs +190 -0
- package/fesm2022/lifecorner-angular-ui-kit-popover.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs +190 -0
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-progress-ring.mjs +175 -0
- package/fesm2022/lifecorner-angular-ui-kit-progress-ring.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-provider-button.mjs +255 -0
- package/fesm2022/lifecorner-angular-ui-kit-provider-button.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-radar-chart.mjs +309 -0
- package/fesm2022/lifecorner-angular-ui-kit-radar-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-radio.mjs +708 -0
- package/fesm2022/lifecorner-angular-ui-kit-radio.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-rating.mjs +327 -0
- package/fesm2022/lifecorner-angular-ui-kit-rating.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-rich-text-editor.mjs +718 -0
- package/fesm2022/lifecorner-angular-ui-kit-rich-text-editor.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-scatter-plot.mjs +415 -0
- package/fesm2022/lifecorner-angular-ui-kit-scatter-plot.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-search-input.mjs +290 -0
- package/fesm2022/lifecorner-angular-ui-kit-search-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-section.mjs +127 -0
- package/fesm2022/lifecorner-angular-ui-kit-section.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-select.mjs +650 -0
- package/fesm2022/lifecorner-angular-ui-kit-select.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs +691 -0
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-skeleton.mjs +144 -0
- package/fesm2022/lifecorner-angular-ui-kit-skeleton.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-slider.mjs +204 -0
- package/fesm2022/lifecorner-angular-ui-kit-slider.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-spacer.mjs +73 -0
- package/fesm2022/lifecorner-angular-ui-kit-spacer.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-sparkline.mjs +318 -0
- package/fesm2022/lifecorner-angular-ui-kit-sparkline.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-spinner.mjs +95 -0
- package/fesm2022/lifecorner-angular-ui-kit-spinner.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-split-pane.mjs +298 -0
- package/fesm2022/lifecorner-angular-ui-kit-split-pane.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-stack.mjs +162 -0
- package/fesm2022/lifecorner-angular-ui-kit-stack.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-stacked-bar-chart.mjs +412 -0
- package/fesm2022/lifecorner-angular-ui-kit-stacked-bar-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-stage-list.mjs +186 -0
- package/fesm2022/lifecorner-angular-ui-kit-stage-list.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-stat-trend.mjs +224 -0
- package/fesm2022/lifecorner-angular-ui-kit-stat-trend.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-status-dot.mjs +122 -0
- package/fesm2022/lifecorner-angular-ui-kit-status-dot.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-stepper.mjs +209 -0
- package/fesm2022/lifecorner-angular-ui-kit-stepper.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-switch.mjs +249 -0
- package/fesm2022/lifecorner-angular-ui-kit-switch.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +1434 -0
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-tabs.mjs +407 -0
- package/fesm2022/lifecorner-angular-ui-kit-tabs.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-tag-input.mjs +380 -0
- package/fesm2022/lifecorner-angular-ui-kit-tag-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs +440 -0
- package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-theme.mjs +145 -0
- package/fesm2022/lifecorner-angular-ui-kit-theme.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-timeline.mjs +262 -0
- package/fesm2022/lifecorner-angular-ui-kit-timeline.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs +352 -0
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-toggle-group.mjs +215 -0
- package/fesm2022/lifecorner-angular-ui-kit-toggle-group.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-tokens.mjs +134 -0
- package/fesm2022/lifecorner-angular-ui-kit-tokens.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-toolbar.mjs +225 -0
- package/fesm2022/lifecorner-angular-ui-kit-toolbar.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-tooltip.mjs +386 -0
- package/fesm2022/lifecorner-angular-ui-kit-tooltip.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-tree-view.mjs +509 -0
- package/fesm2022/lifecorner-angular-ui-kit-tree-view.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-typography.mjs +209 -0
- package/fesm2022/lifecorner-angular-ui-kit-typography.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-verification-code-input.mjs +365 -0
- package/fesm2022/lifecorner-angular-ui-kit-verification-code-input.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-waterfall-chart.mjs +371 -0
- package/fesm2022/lifecorner-angular-ui-kit-waterfall-chart.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit.mjs +109 -38925
- package/package.json +449 -1
- package/types/lifecorner-angular-ui-kit-accordion.d.ts +239 -0
- package/types/lifecorner-angular-ui-kit-alert.d.ts +189 -0
- package/types/lifecorner-angular-ui-kit-app-shell.d.ts +148 -0
- package/types/lifecorner-angular-ui-kit-area-chart.d.ts +180 -0
- package/types/lifecorner-angular-ui-kit-avatar-group.d.ts +62 -0
- package/types/lifecorner-angular-ui-kit-avatar.d.ts +131 -0
- package/types/lifecorner-angular-ui-kit-badge.d.ts +59 -0
- package/types/lifecorner-angular-ui-kit-bar-chart.d.ts +157 -0
- package/types/lifecorner-angular-ui-kit-bottom-nav.d.ts +184 -0
- package/types/lifecorner-angular-ui-kit-breadcrumbs.d.ts +55 -0
- package/types/lifecorner-angular-ui-kit-button.d.ts +181 -0
- package/types/lifecorner-angular-ui-kit-calendar.d.ts +136 -0
- package/types/lifecorner-angular-ui-kit-callout.d.ts +77 -0
- package/types/lifecorner-angular-ui-kit-card.d.ts +213 -0
- package/types/lifecorner-angular-ui-kit-chat.d.ts +379 -0
- package/types/lifecorner-angular-ui-kit-checkbox.d.ts +116 -0
- package/types/lifecorner-angular-ui-kit-chip.d.ts +104 -0
- package/types/lifecorner-angular-ui-kit-choice-prompt.d.ts +186 -0
- package/types/lifecorner-angular-ui-kit-code-block.d.ts +85 -0
- package/types/lifecorner-angular-ui-kit-color-picker.d.ts +88 -0
- package/types/lifecorner-angular-ui-kit-combobox.d.ts +222 -0
- package/types/lifecorner-angular-ui-kit-confirm-dialog.d.ts +211 -0
- package/types/lifecorner-angular-ui-kit-container.d.ts +47 -0
- package/types/lifecorner-angular-ui-kit-copy-field.d.ts +89 -0
- package/types/lifecorner-angular-ui-kit-date-range-picker.d.ts +126 -0
- package/types/lifecorner-angular-ui-kit-datepicker.d.ts +363 -0
- package/types/lifecorner-angular-ui-kit-dependency-viewer.d.ts +568 -0
- package/types/lifecorner-angular-ui-kit-description-list.d.ts +137 -0
- package/types/lifecorner-angular-ui-kit-diff-viewer.d.ts +93 -0
- package/types/lifecorner-angular-ui-kit-divider.d.ts +66 -0
- package/types/lifecorner-angular-ui-kit-document-viewer.d.ts +256 -0
- package/types/lifecorner-angular-ui-kit-donut-chart.d.ts +92 -0
- package/types/lifecorner-angular-ui-kit-drawer.d.ts +124 -0
- package/types/lifecorner-angular-ui-kit-email-input.d.ts +292 -0
- package/types/lifecorner-angular-ui-kit-empty-state.d.ts +81 -0
- package/types/lifecorner-angular-ui-kit-error-display.d.ts +157 -0
- package/types/lifecorner-angular-ui-kit-field-group.d.ts +69 -0
- package/types/lifecorner-angular-ui-kit-file-upload.d.ts +122 -0
- package/types/lifecorner-angular-ui-kit-filter-bar.d.ts +116 -0
- package/types/lifecorner-angular-ui-kit-footer.d.ts +97 -0
- package/types/lifecorner-angular-ui-kit-funnel-chart.d.ts +97 -0
- package/types/lifecorner-angular-ui-kit-gallery.d.ts +240 -0
- package/types/lifecorner-angular-ui-kit-gantt-chart.d.ts +133 -0
- package/types/lifecorner-angular-ui-kit-gauge.d.ts +94 -0
- package/types/lifecorner-angular-ui-kit-header.d.ts +496 -0
- package/types/lifecorner-angular-ui-kit-heatmap.d.ts +126 -0
- package/types/lifecorner-angular-ui-kit-hero.d.ts +121 -0
- package/types/lifecorner-angular-ui-kit-icon-names.d.ts +21 -0
- package/types/lifecorner-angular-ui-kit-icon.d.ts +260 -0
- package/types/lifecorner-angular-ui-kit-input.d.ts +346 -0
- package/types/lifecorner-angular-ui-kit-internal-chart.d.ts +86 -0
- package/types/lifecorner-angular-ui-kit-internal-overlay.d.ts +31 -0
- package/types/lifecorner-angular-ui-kit-internal-url.d.ts +22 -0
- package/types/lifecorner-angular-ui-kit-kanban-board.d.ts +111 -0
- package/types/lifecorner-angular-ui-kit-line-chart.d.ts +186 -0
- package/types/lifecorner-angular-ui-kit-list.d.ts +215 -0
- package/types/lifecorner-angular-ui-kit-log-viewer.d.ts +355 -0
- package/types/lifecorner-angular-ui-kit-logo.d.ts +182 -0
- package/types/lifecorner-angular-ui-kit-markdown.d.ts +278 -0
- package/types/lifecorner-angular-ui-kit-menu.d.ts +152 -0
- package/types/lifecorner-angular-ui-kit-modal.d.ts +207 -0
- package/types/lifecorner-angular-ui-kit-models.d.ts +62 -0
- package/types/lifecorner-angular-ui-kit-next-step-card.d.ts +262 -0
- package/types/lifecorner-angular-ui-kit-notification-center.d.ts +237 -0
- package/types/lifecorner-angular-ui-kit-number-input.d.ts +126 -0
- package/types/lifecorner-angular-ui-kit-page-header.d.ts +178 -0
- package/types/lifecorner-angular-ui-kit-page-layout.d.ts +61 -0
- package/types/lifecorner-angular-ui-kit-pagination.d.ts +141 -0
- package/types/lifecorner-angular-ui-kit-password-input.d.ts +361 -0
- package/types/lifecorner-angular-ui-kit-pie-chart.d.ts +58 -0
- package/types/lifecorner-angular-ui-kit-pipeline.d.ts +89 -0
- package/types/lifecorner-angular-ui-kit-popover.d.ts +104 -0
- package/types/lifecorner-angular-ui-kit-progress-bar.d.ts +116 -0
- package/types/lifecorner-angular-ui-kit-progress-ring.d.ts +67 -0
- package/types/lifecorner-angular-ui-kit-provider-button.d.ts +137 -0
- package/types/lifecorner-angular-ui-kit-radar-chart.d.ts +113 -0
- package/types/lifecorner-angular-ui-kit-radio.d.ts +297 -0
- package/types/lifecorner-angular-ui-kit-rating.d.ts +115 -0
- package/types/lifecorner-angular-ui-kit-rich-text-editor.d.ts +226 -0
- package/types/lifecorner-angular-ui-kit-scatter-plot.d.ts +190 -0
- package/types/lifecorner-angular-ui-kit-search-input.d.ts +137 -0
- package/types/lifecorner-angular-ui-kit-section.d.ts +34 -0
- package/types/lifecorner-angular-ui-kit-select.d.ts +274 -0
- package/types/lifecorner-angular-ui-kit-sidenav.d.ts +368 -0
- package/types/lifecorner-angular-ui-kit-skeleton.d.ts +61 -0
- package/types/lifecorner-angular-ui-kit-slider.d.ts +79 -0
- package/types/lifecorner-angular-ui-kit-spacer.d.ts +27 -0
- package/types/lifecorner-angular-ui-kit-sparkline.d.ts +113 -0
- package/types/lifecorner-angular-ui-kit-spinner.d.ts +50 -0
- package/types/lifecorner-angular-ui-kit-split-pane.d.ts +131 -0
- package/types/lifecorner-angular-ui-kit-stack.d.ts +49 -0
- package/types/lifecorner-angular-ui-kit-stacked-bar-chart.d.ts +171 -0
- package/types/lifecorner-angular-ui-kit-stage-list.d.ts +69 -0
- package/types/lifecorner-angular-ui-kit-stat-trend.d.ts +62 -0
- package/types/lifecorner-angular-ui-kit-status-dot.d.ts +62 -0
- package/types/lifecorner-angular-ui-kit-stepper.d.ts +113 -0
- package/types/lifecorner-angular-ui-kit-switch.d.ts +141 -0
- package/types/lifecorner-angular-ui-kit-table.d.ts +632 -0
- package/types/lifecorner-angular-ui-kit-tabs.d.ts +196 -0
- package/types/lifecorner-angular-ui-kit-tag-input.d.ts +123 -0
- package/types/lifecorner-angular-ui-kit-textarea.d.ts +225 -0
- package/types/lifecorner-angular-ui-kit-theme.d.ts +91 -0
- package/types/lifecorner-angular-ui-kit-timeline.d.ts +162 -0
- package/types/lifecorner-angular-ui-kit-toast.d.ts +204 -0
- package/types/lifecorner-angular-ui-kit-toggle-group.d.ts +100 -0
- package/types/lifecorner-angular-ui-kit-tokens.d.ts +134 -0
- package/types/lifecorner-angular-ui-kit-toolbar.d.ts +120 -0
- package/types/lifecorner-angular-ui-kit-tooltip.d.ts +120 -0
- package/types/lifecorner-angular-ui-kit-tree-view.d.ts +231 -0
- package/types/lifecorner-angular-ui-kit-typography.d.ts +126 -0
- package/types/lifecorner-angular-ui-kit-verification-code-input.d.ts +187 -0
- package/types/lifecorner-angular-ui-kit-waterfall-chart.d.ts +163 -0
- package/types/lifecorner-angular-ui-kit.d.ts +109 -17401
- package/fesm2022/lifecorner-angular-ui-kit.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-dependency-viewer.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/dependency-viewer/dependency-viewer.component.ts","../../../../libs/angular-ui-kit/src/lib/dependency-viewer/dependency-viewer.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n effect,\n inject,\n input,\n output,\n computed,\n signal,\n untracked,\n viewChild,\n HostListener,\n} from '@angular/core';\n\n// ── Public types ─────────────────────────────────────────────────────────────\n\nexport type DependencyNodeStatus = 'default' | 'active' | 'success' | 'warning' | 'error' | 'muted';\nexport type DependencyDirection = 'horizontal' | 'vertical';\nexport type DependencyRelation = 'depends' | 'blocks' | 'references' | 'requires' | 'extends' | 'implements' | 'uses';\n\n/**\n * How nodes are placed.\n *\n * - `tree` — column = depth in the `children` tree; `dependsOn` links are drawn\n * over the top as cross-references and don't move anything.\n * - `layered` — column = depth in the *dependency* graph (Sugiyama). Every link is\n * a precedence constraint, so a node always sits past everything it depends on.\n */\nexport type DependencyLayout = 'tree' | 'layered';\n\n/**\n * How the graph is scaled into the frame.\n *\n * - `none` — no fitting; the viewport is whatever the user panned/zoomed to.\n * - `contain` — shrink until all of it fits, both axes.\n * - `fit-width` — shrink to the frame's *width* only and let the viewer grow\n * taller, so the page scrolls instead of the nodes shrinking out of legibility.\n */\nexport type DependencyFitMode = 'none' | 'contain' | 'fit-width';\n\nexport interface DependencyEdgeDef {\n /** Target node id */\n id: string;\n /** Relationship type — drives edge colour and dash style */\n relation?: DependencyRelation;\n /**\n * Free-form edge label, for graphs whose relationship vocabulary is wider than\n * `DependencyRelation` (e.g. `CALLS`, `HAS_COLUMN`, `AUTHORED_BY`). Shown\n * verbatim instead of the `relation` label; colouring still follows `relation`,\n * which may be omitted for a generic look.\n */\n relationLabel?: string;\n}\n\nexport interface DependencyNode {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Optional description */\n description?: string;\n /** Optional icon name */\n icon?: string;\n /** Visual status / color */\n status?: DependencyNodeStatus;\n /**\n * Category of the node (e.g. `Class`, `Table`, `Feature`). Colours the node via\n * the `typeColors` input and drives the type legend. Takes precedence over\n * `status` for the fill; `status` still applies when no type colour resolves.\n */\n type?: string;\n /**\n * Number of neighbours that exist but aren't part of `children` — rendered as a\n * \"+N\" marker. Use when a node's neighbourhood is capped (god nodes) so the\n * truncation is visible instead of silent.\n */\n moreCount?: number;\n /** Child nodes: items this node is required for (right / bottom side) */\n children?: DependencyNode[];\n /** Dependencies: items this node depends on (shown as cross-reference edges) */\n dependsOn?: DependencyEdgeDef[];\n /**\n * Opaque payload. Never read or interpreted by the component; handed back\n * unchanged on `nodeSelect` / `nodeExpand` so callers can carry their own\n * metadata (keys, labels, file paths, …) through the viewer.\n */\n data?: Record<string, unknown>;\n}\n\n// ── Layout types ─────────────────────────────────────────────────────────────\n\ninterface LayoutNode {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n status: DependencyNodeStatus;\n type?: string;\n moreCount?: number;\n x: number;\n y: number;\n width: number;\n height: number;\n /** The label as drawn: wrapped to the box, last line ellipsised if it had to be. */\n lines: string[];\n /** `lines` don't carry the whole label — the template offers it as a tooltip. */\n truncated: boolean;\n depth: number;\n parentId: string | null;\n incomingCount: number;\n outgoingCount: number;\n}\n\ninterface LayoutEdge {\n id: string;\n path: string;\n sourceId: string;\n targetId: string;\n relation?: DependencyRelation;\n /** Resolved display label (free-form `relationLabel` wins over the relation's) */\n label?: string;\n labelX: number;\n labelY: number;\n /** How the label hangs off (labelX, labelY): centred on it, or starting/ending there. */\n labelAnchor?: LabelAnchor;\n color: string;\n dashed: boolean;\n /** Draws it as a secondary link: dimmed, and out of the layout's main flow. */\n isCrossRef: boolean;\n /** Whether to cap the edge with an arrowhead. */\n arrow: boolean;\n /** Arrow marker id suffix — always a known relation, so the marker resolves */\n marker: DependencyRelation;\n /** Set on bowed routes, so overlapping bows can be spread into lanes afterwards. */\n bow?: BowInfo;\n}\n\n// ── Constants ────────────────────────────────────────────────────────────────\n\n/**\n * Node box, in layout units. Every node in a graph shares one size: the width\n * grows with the longest label up to a cap, past which labels wrap onto a second\n * line (and the whole graph switches to the taller box); a label that still\n * doesn't fit is ellipsised, with the full text as a tooltip. Uniform boxes are\n * what keep the columns aligned — a per-node width would stagger every level\n * below a long label.\n */\nconst NODE_MIN_WIDTH = 160;\nconst NODE_MAX_WIDTH = 240;\nconst NODE_HEIGHT = 40;\nconst NODE_HEIGHT_TWO_LINE = 54;\n/** Inset between the box edge and the label, per side. */\nconst NODE_PAD_X = 12;\nconst MAX_LABEL_LINES = 2;\n/**\n * The label font, as the layout measures it. Has to match\n * `.dep-viewer__node-label` in the stylesheet, or the wrapping is computed for a\n * different font than the one that gets drawn.\n */\nconst LABEL_FONT_SIZE = 12;\nconst LABEL_FONT_WEIGHT = 500;\nconst LABEL_LINE_HEIGHT = 15;\n/**\n * Baseline offset from the box's vertical centre for one line of the label font:\n * roughly (ascent − descent) / 2. Explicit rather than `dominant-baseline`, whose\n * inheritance into `<tspan>` differs between engines.\n */\nconst LABEL_BASELINE_SHIFT = 4;\n/** Edge label font, as `.dep-viewer__edge-label` draws it — for measuring label room. */\nconst EDGE_LABEL_FONT_SIZE = 9;\n/** Gap between a bow's apex and the label that sits beside it. */\nconst EDGE_LABEL_GAP = 4;\n/**\n * Gutter between levels along the flow. The minimum: it widens for a graph whose\n * sideways bows (plus their labels) wouldn't fit it — see `requiredGap`.\n */\nconst H_GAP = 80;\nconst V_GAP = 24;\n/** How far a bowed edge's apex clears the boxes it loops around. */\nconst BOW_CLEARANCE = 28;\n/** Extra clearance per lane, when several bows share a side and overlap. */\nconst BOW_LANE_STEP = 18;\n/** Breathing room between a bow's label and the next level's boxes. */\nconst BOW_LABEL_MARGIN = 10;\n/**\n * The collapse toggle is a disc of radius 8, centred 10px off the box's mid-edge —\n * so it reaches 18px past the box. A bow along that side clears the discs, not\n * just the boxes; and an edge attaching under a disc would hide its arrowhead\n * behind it, so it attaches `TOGGLE_CLEARANCE` beside the disc instead.\n */\nconst TOGGLE_EXTENT = 18;\nconst TOGGLE_CLEARANCE = 13;\n/** Points sampled along a curve when testing it against the node boxes. */\nconst ROUTE_SAMPLES = 24;\n/** Ignore grazing the very edge of a box — only a real incursion counts. */\nconst ROUTE_INSET = 3;\n/** Breathing room around the graph's bounding box when auto-fitting, in layout units. */\nconst FIT_PADDING = 24;\n/**\n * Auto-fit shrinks to fit but never enlarges: blowing a two-node graph up to fill\n * a 600px frame reads as broken, not as \"fitted\".\n */\nconst MAX_FIT_SCALE = 1;\n/** Floor for the fit scale, so a huge graph in a tiny box stays a graph, not a smear. */\nconst MIN_FIT_SCALE = 0.05;\n\n// ── Label measurement ────────────────────────────────────────────────────────\n\ntype TextMeasure = (text: string) => number;\n\n/**\n * Advance widths in em of a Helvetica-like sans, by character class. Only the\n * fallback for environments without a canvas (SSR, jsdom); in a browser the label\n * font is measured for real. Latin letters with diacritics take their base\n * letter's width, anything unknown a mid-range default.\n */\nconst CHAR_WIDTH_CLASSES: [string, number][] = [\n ['ijl', 0.23],\n [\" !.,:;'|Ift/\\\\[]\", 0.28],\n ['-()r`', 0.33],\n ['ckszxyvJ', 0.5],\n ['abdeghnopqu0123456789$#?_L', 0.56],\n ['TZF', 0.61],\n ['ABEKPSVXY&', 0.67],\n ['CDHNRUw', 0.72],\n ['GOQ', 0.78],\n ['Mm%', 0.83],\n ['W', 0.94],\n ['@', 1.0],\n];\nconst CHAR_WIDTHS = new Map<string, number>();\nfor (const [chars, width] of CHAR_WIDTH_CLASSES) {\n for (const c of chars) CHAR_WIDTHS.set(c, width);\n}\n\nfunction estimateTextWidth(text: string, fontSize: number): number {\n let em = 0;\n for (const ch of text.normalize('NFD')) {\n if (/\\p{M}/u.test(ch)) continue; // combining mark: no advance of its own\n const code = ch.codePointAt(0) ?? 0;\n em += CHAR_WIDTHS.get(ch) ?? (code > 0x2e7f ? 1 : 0.6); // CJK & co. are full-width\n }\n // Medium weight runs a touch wider than the regular metrics above.\n return em * fontSize * 1.04;\n}\n\n/**\n * Measures text in the given font — exactly, through a canvas, where one exists,\n * and by estimate elsewhere. Wrapping and ellipsising decisions are made with the\n * result, so being right for the font actually on screen is what makes a label\n * that \"fits\" really fit.\n */\nfunction createTextMeasurer(fontFamily: string, fontSize: number, fontWeight: number): TextMeasure {\n // `CanvasRenderingContext2D` is the tell: jsdom has a canvas element whose\n // `getContext` returns nothing (and logs), but no context class.\n if (typeof document !== 'undefined' && typeof CanvasRenderingContext2D === 'function') {\n const ctx = document.createElement('canvas').getContext('2d');\n if (ctx) {\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n // A family the parser rejects leaves the default 10px font in place —\n // measure with a plain sans rather than at the wrong size.\n if (!ctx.font.includes(`${fontSize}px`)) ctx.font = `${fontWeight} ${fontSize}px sans-serif`;\n return text => ctx.measureText(text).width;\n }\n }\n return text => estimateTextWidth(text, fontSize);\n}\n\n/** The label lines a node renders, and whether they lost anything to the box. */\ninterface LabelLines {\n lines: string[];\n truncated: boolean;\n}\n\n/** Longest prefix of `text` that, with an ellipsis, fits `maxWidth`. */\nfunction ellipsize(text: string, maxWidth: number, measure: TextMeasure): string {\n let lo = 0;\n let hi = text.length;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (measure(text.slice(0, mid).trimEnd() + '…') <= maxWidth) lo = mid;\n else hi = mid - 1;\n }\n return text.slice(0, lo).trimEnd() + '…';\n}\n\n/**\n * Splits a word too long for a line. A hyphenated compound breaks after a hyphen\n * where it can; anything else breaks wherever it runs out of room. Always takes\n * at least one character, so an unbreakable word can't stall the wrap.\n */\nfunction splitWord(word: string, maxWidth: number, measure: TextMeasure): [string, string] {\n for (let i = word.length - 1; i > 0; i--) {\n if (word[i - 1] === '-' && measure(word.slice(0, i)) <= maxWidth) {\n return [word.slice(0, i), word.slice(i)];\n }\n }\n let lo = 1;\n let hi = word.length;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (measure(word.slice(0, mid)) <= maxWidth) lo = mid;\n else hi = mid - 1;\n }\n return [word.slice(0, lo), word.slice(lo)];\n}\n\n/**\n * Greedy word wrap into at most `MAX_LABEL_LINES` lines of `maxWidth`. Whatever\n * doesn't fit the last line is cut with an ellipsis, and the cut is reported so\n * the caller can offer the full text some other way.\n */\nfunction wrapLabel(text: string, maxWidth: number, measure: TextMeasure): LabelLines {\n const label = text.trim().replace(/\\s+/g, ' ');\n if (!label || measure(label) <= maxWidth) return { lines: [label], truncated: false };\n\n const lines: string[] = [];\n let rest = label.split(' ');\n while (rest.length && lines.length < MAX_LABEL_LINES - 1) {\n let take = 0;\n while (take < rest.length && measure(rest.slice(0, take + 1).join(' ')) <= maxWidth) take++;\n if (take === 0) {\n const [head, tail] = splitWord(rest[0], maxWidth, measure);\n lines.push(head);\n rest = [tail, ...rest.slice(1)];\n } else {\n lines.push(rest.slice(0, take).join(' '));\n rest = rest.slice(take);\n }\n }\n\n const last = rest.join(' ');\n if (!last) return { lines, truncated: false };\n if (measure(last) <= maxWidth) return { lines: [...lines, last], truncated: false };\n return { lines: [...lines, ellipsize(last, maxWidth, measure)], truncated: true };\n}\n\n/** One graph's node geometry, and the label lines of every node in it. */\ninterface NodeMetrics {\n width: number;\n height: number;\n /** Gutter between levels along the flow — `H_GAP`, unless the bows need more. */\n gap: number;\n labels: Map<string, LabelLines>;\n /** Width of text in the node label font — the edge label font is the same face, scaled. */\n measure: TextMeasure;\n}\n\n/** Width of an edge label as drawn — the label font scaled down to the edge label size. */\nconst edgeLabelWidth = (measure: TextMeasure, label: string | undefined): number =>\n label ? (measure(label) * EDGE_LABEL_FONT_SIZE) / LABEL_FONT_SIZE : 0;\n\n/**\n * Sizes the boxes to the labels: wide enough for the longest one, within\n * `NODE_MIN_WIDTH`..`NODE_MAX_WIDTH`, and tall enough for two lines if any label\n * needs them at that width. Sized over *all* nodes, so collapsing a subtree or\n * hiding a type doesn't resize what remains.\n */\nfunction measureNodes(nodes: Iterable<DependencyNode>, measure: TextMeasure): NodeMetrics {\n const all = [...nodes];\n let widest = 0;\n for (const node of all) widest = Math.max(widest, measure(node.label ?? ''));\n const width = Math.min(NODE_MAX_WIDTH, Math.max(NODE_MIN_WIDTH, Math.ceil(widest) + 2 * NODE_PAD_X));\n\n const labels = new Map<string, LabelLines>();\n let twoLine = false;\n for (const node of all) {\n const wrapped = wrapLabel(node.label ?? '', width - 2 * NODE_PAD_X, measure);\n labels.set(node.id, wrapped);\n if (wrapped.lines.length > 1) twoLine = true;\n }\n return { width, height: twoLine ? NODE_HEIGHT_TWO_LINE : NODE_HEIGHT, gap: H_GAP, labels, measure };\n}\n\nconst RELATION_STYLES: Record<DependencyRelation, { color: string; dashed: boolean; label: string }> = {\n depends: { color: 'var(--color-neutral-400)', dashed: false, label: 'depends on' },\n blocks: { color: 'var(--color-error-default)', dashed: false, label: 'blocks' },\n references: { color: 'var(--color-info-default, #3b82f6)', dashed: true, label: 'references' },\n requires: { color: 'var(--color-warning-default)', dashed: false, label: 'requires' },\n extends: { color: 'var(--color-primary-400)', dashed: true, label: 'extends' },\n implements: { color: 'var(--color-success-default)', dashed: true, label: 'implements' },\n uses: { color: 'var(--color-neutral-300)', dashed: true, label: 'uses' },\n};\n\n// ── Layout algorithm ─────────────────────────────────────────────────────────\n\ninterface TreeMeasure {\n node: DependencyNode;\n primary: number;\n secondary: number;\n children: TreeMeasure[];\n depth: number;\n}\n\n/** A `children` link that couldn't be laid out as a tree edge (cycle or second parent). */\ninterface BackEdge {\n from: string;\n to: string;\n}\n\n/**\n * Measures the tree, treating the input as a *graph*: `visited` guards against a\n * node being laid out twice.\n *\n * Two cases route through it, and both are normal in a graph rather than a strict\n * tree: a cycle (a → b → a), which would otherwise recurse until the stack blows,\n * and a node reachable from two parents, which would otherwise be drawn twice at\n * two positions. Either way the node already has a place in the layout, so the\n * link is recorded as a back edge and later drawn as a cross-reference arrow.\n */\nfunction measureTree(\n node: DependencyNode,\n depth: number,\n dir: DependencyDirection,\n visited: Set<string>,\n backEdges: BackEdge[],\n metrics: NodeMetrics,\n): TreeMeasure {\n visited.add(node.id);\n\n const children: TreeMeasure[] = [];\n for (const child of node.children || []) {\n if (visited.has(child.id)) {\n backEdges.push({ from: node.id, to: child.id });\n continue;\n }\n children.push(measureTree(child, depth + 1, dir, visited, backEdges, metrics));\n }\n\n const nodePrimary = dir === 'horizontal' ? metrics.width : metrics.height;\n const nodeSecondary = dir === 'horizontal' ? metrics.height : metrics.width;\n\n if (children.length === 0) {\n return { node, primary: nodePrimary, secondary: nodeSecondary, children, depth };\n }\n\n const totalChildSecondary = children.reduce((sum, c) => sum + c.secondary, 0)\n + (children.length - 1) * V_GAP;\n const maxChildPrimary = Math.max(...children.map(c => c.primary));\n\n return {\n node,\n primary: nodePrimary + metrics.gap + maxChildPrimary,\n secondary: Math.max(nodeSecondary, totalChildSecondary),\n children,\n depth,\n };\n}\n\n/**\n * A node at its place. Counts and children come from `original` — the node as the\n * caller handed it in — because `source` may be a pruned copy (a collapsed\n * subtree) that has lost its children.\n */\nfunction placeNode(\n source: DependencyNode, original: DependencyNode | undefined,\n x: number, y: number, depth: number, parentId: string | null,\n metrics: NodeMetrics,\n): LayoutNode {\n const label = metrics.labels.get(source.id);\n return {\n id: source.id, label: source.label, description: source.description,\n icon: source.icon, status: source.status || 'default',\n type: source.type, moreCount: source.moreCount,\n x, y, width: metrics.width, height: metrics.height,\n lines: label?.lines ?? [source.label], truncated: label?.truncated ?? false,\n depth, parentId,\n incomingCount: original?.dependsOn?.length ?? 0,\n outgoingCount: original?.children?.length ?? 0,\n };\n}\n\nfunction layoutTreeH(\n measure: TreeMeasure, x: number, y: number, parentId: string | null,\n nodes: LayoutNode[], edges: LayoutEdge[], allNodes: Map<string, DependencyNode>,\n nodeMap: Map<string, LayoutNode>, metrics: NodeMetrics,\n): void {\n const nodeY = y + measure.secondary / 2 - metrics.height / 2;\n const laid = placeNode(measure.node, allNodes.get(measure.node.id), x, nodeY, measure.depth, parentId, metrics);\n nodes.push(laid);\n nodeMap.set(laid.id, laid);\n\n if (parentId) {\n const parent = nodeMap.get(parentId)!;\n const sx = parent.x + parent.width;\n const sy = parent.y + parent.height / 2;\n const tx = x;\n const ty = nodeY + metrics.height / 2;\n const mx = sx + metrics.gap / 2;\n edges.push({\n id: `${parentId}→${measure.node.id}`, sourceId: parentId, targetId: measure.node.id,\n path: `M ${sx} ${sy} C ${mx} ${sy}, ${mx} ${ty}, ${tx} ${ty}`,\n labelX: mx, labelY: (sy + ty) / 2,\n color: 'var(--color-neutral-300)', dashed: false, isCrossRef: false,\n arrow: false, marker: 'depends',\n });\n }\n\n let childY = y;\n for (const child of measure.children) {\n layoutTreeH(child, x + metrics.width + metrics.gap, childY, measure.node.id, nodes, edges, allNodes, nodeMap, metrics);\n childY += child.secondary + V_GAP;\n }\n}\n\nfunction layoutTreeV(\n measure: TreeMeasure, x: number, y: number, parentId: string | null,\n nodes: LayoutNode[], edges: LayoutEdge[], allNodes: Map<string, DependencyNode>,\n nodeMap: Map<string, LayoutNode>, metrics: NodeMetrics,\n): void {\n const nodeX = x + measure.secondary / 2 - metrics.width / 2;\n const laid = placeNode(measure.node, allNodes.get(measure.node.id), nodeX, y, measure.depth, parentId, metrics);\n nodes.push(laid);\n nodeMap.set(laid.id, laid);\n\n if (parentId) {\n const parent = nodeMap.get(parentId)!;\n const sx = parent.x + parent.width / 2;\n const sy = parent.y + parent.height;\n const tx = nodeX + metrics.width / 2;\n const ty = y;\n const my = sy + metrics.gap / 2;\n edges.push({\n id: `${parentId}→${measure.node.id}`, sourceId: parentId, targetId: measure.node.id,\n path: `M ${sx} ${sy} C ${sx} ${my}, ${tx} ${my}, ${tx} ${ty}`,\n labelX: (sx + tx) / 2, labelY: my,\n color: 'var(--color-neutral-300)', dashed: false, isCrossRef: false,\n arrow: false, marker: 'depends',\n });\n }\n\n let childX = x;\n for (const child of measure.children) {\n layoutTreeV(child, childX, y + metrics.height + metrics.gap, measure.node.id, nodes, edges, allNodes, nodeMap, metrics);\n childX += child.secondary + V_GAP;\n }\n}\n\n// The `map.has` check doubles as the cycle guard: revisiting a node means the\n// graph loops back (or converges from a second parent), and there is nothing\n// left to collect from it.\nfunction collectAllNodes(node: DependencyNode, map: Map<string, DependencyNode>): void {\n if (map.has(node.id)) return;\n map.set(node.id, node);\n for (const child of node.children || []) collectAllNodes(child, map);\n}\n\ninterface Pt {\n x: number;\n y: number;\n}\ntype Cubic = [Pt, Pt, Pt, Pt];\n\nconst push = <T>(map: Map<string, T[]>, key: string, value: T): void => {\n const bucket = map.get(key);\n if (bucket) bucket.push(value);\n else map.set(key, [value]);\n};\n\ntype LabelAnchor = 'start' | 'middle' | 'end';\n\ninterface EdgeGeometry {\n path: string;\n labelX: number;\n labelY: number;\n labelAnchor: LabelAnchor;\n /** Control points, kept so the route can be tested against the node boxes. */\n points: Cubic;\n /** Present on bowed routes: what it takes to redraw the bow in another lane. */\n bow?: BowInfo;\n}\n\nconst cubicPath = (p: Cubic) =>\n `M ${p[0].x} ${p[0].y} C ${p[1].x} ${p[1].y}, ${p[2].x} ${p[2].y}, ${p[3].x} ${p[3].y}`;\n\nfunction cubicAt(p: Cubic, t: number): Pt {\n const m = 1 - t;\n return {\n x: m * m * m * p[0].x + 3 * m * m * t * p[1].x + 3 * m * t * t * p[2].x + t * t * t * p[3].x,\n y: m * m * m * p[0].y + 3 * m * m * t * p[1].y + 3 * m * t * t * p[2].y + t * t * t * p[3].y,\n };\n}\n\n/**\n * Nodes the curve passes through, ignoring its own endpoints — a path necessarily\n * touches those, and counting them would make every edge look like a crossing.\n */\nfunction crossedNodes(points: Cubic, nodes: LayoutNode[], exclude: Set<string>): LayoutNode[] {\n const hit = new Map<string, LayoutNode>();\n for (let i = 0; i <= ROUTE_SAMPLES; i++) {\n const p = cubicAt(points, i / ROUTE_SAMPLES);\n for (const n of nodes) {\n if (exclude.has(n.id) || hit.has(n.id)) continue;\n if (\n p.x > n.x + ROUTE_INSET &&\n p.x < n.x + n.width - ROUTE_INSET &&\n p.y > n.y + ROUTE_INSET &&\n p.y < n.y + n.height - ROUTE_INSET\n ) {\n hit.set(n.id, n);\n }\n }\n }\n return [...hit.values()];\n}\n\n/** The straight-ish curve between two nodes, following the layout flow. */\nfunction directGeometry(source: LayoutNode, target: LayoutNode, dir: DependencyDirection): EdgeGeometry {\n if (dir === 'horizontal') {\n const p0 = { x: source.x + source.width, y: source.y + source.height / 2 };\n const p3 = { x: target.x, y: target.y + target.height / 2 };\n const mx = (p0.x + p3.x) / 2;\n const points: Cubic = [p0, { x: mx, y: p0.y }, { x: mx, y: p3.y }, p3];\n // labelY is the curve midpoint, not a baseline offset: the template centres the\n // text on it via `dominant-baseline`. Nudging it up instead (as this did) pushes\n // the label out of a 24px gutter and into the node above it.\n return { path: cubicPath(points), labelX: mx, labelY: (p0.y + p3.y) / 2, labelAnchor: 'middle', points };\n }\n const p0 = { x: source.x + source.width / 2, y: source.y + source.height };\n const p3 = { x: target.x + target.width / 2, y: target.y };\n const my = (p0.y + p3.y) / 2;\n const points: Cubic = [p0, { x: p0.x, y: my }, { x: p3.x, y: my }, p3];\n return { path: cubicPath(points), labelX: (p0.x + p3.x) / 2, labelY: my, labelAnchor: 'middle', points };\n}\n\ntype BowSide = 'below' | 'above' | 'right' | 'left';\n\n/**\n * A bowed route, described well enough to draw it again further out. `column` is\n * the outermost box edge on the bow's side — the line that identifies which bows\n * share a gutter — and `base` the line the bow actually clears (the boxes, or\n * their toggle discs); `lo`/`hi` is the span it covers along that line. Together\n * that is what lane assignment needs to know which bows collide.\n */\ninterface BowInfo {\n side: BowSide;\n column: number;\n base: number;\n /** Where the bow peaks, on the axis it bows along. */\n apex: number;\n lo: number;\n hi: number;\n source: LayoutNode;\n target: LayoutNode;\n obstacles: LayoutNode[];\n dir: DependencyDirection;\n}\n\n/**\n * Where on a box's side an edge attaches. Normally the side's midpoint — but a\n * node with children carries its collapse toggle right there (on the right side\n * in a horizontal layout, at the bottom in a vertical one), and an arrowhead under\n * the toggle disc is an arrowhead nobody sees. Those attach beside the disc, on\n * the side facing the other endpoint.\n */\nfunction sideAttach(node: LayoutNode, other: LayoutNode, side: BowSide, dir: DependencyDirection): Pt {\n const underToggle =\n node.outgoingCount > 0 &&\n ((dir === 'horizontal' && side === 'right') || (dir === 'vertical' && side === 'below'));\n if (side === 'right' || side === 'left') {\n const x = side === 'right' ? node.x + node.width : node.x;\n let y = node.y + node.height / 2;\n if (underToggle) y += Math.sign(other.y - node.y || 1) * TOGGLE_CLEARANCE;\n return { x, y };\n }\n const y = side === 'below' ? node.y + node.height : node.y;\n let x = node.x + node.width / 2;\n if (underToggle) x += Math.sign(other.x - node.x || 1) * TOGGLE_CLEARANCE;\n return { x, y };\n}\n\n/**\n * Leaves from one side of both boxes and bows clear of everything in `obstacles`,\n * so the edge travels through empty space instead of disappearing behind the nodes\n * between its endpoints.\n *\n * The side matters: bowing *below* clears an obstacle sitting beside the endpoints,\n * but drives straight through one stacked underneath them. Callers try several.\n *\n * `lane` pushes the bow out by a step per lane, and `base` overrides the line it\n * clears — both for bows that would otherwise lie on top of each other, see\n * `spreadBows`.\n */\nfunction bowedGeometry(\n source: LayoutNode,\n target: LayoutNode,\n obstacles: LayoutNode[],\n side: BowSide,\n dir: DependencyDirection,\n lane = 0,\n baseOverride?: number,\n): EdgeGeometry {\n const all = [source, target, ...obstacles];\n const clearance = BOW_CLEARANCE + lane * BOW_LANE_STEP;\n // A cubic whose two control points sit at the same offset peaks at ¾ of it, so\n // the control points go out by 4/3 of the clearance the apex should reach.\n const control = clearance / 0.75;\n const p0 = sideAttach(source, target, side, dir);\n const p3 = sideAttach(target, source, side, dir);\n // On the toggle side, a box with children reaches as far as its disc.\n const toggleSide = dir === 'horizontal' ? 'right' : 'below';\n const extent = (n: LayoutNode) => (side === toggleSide && n.outgoingCount > 0 ? TOGGLE_EXTENT : 0);\n const outward = side === 'below' || side === 'right' ? 1 : -1;\n\n let column: number;\n let base: number;\n switch (side) {\n case 'below':\n column = Math.max(...all.map(n => n.y + n.height));\n base = Math.max(...all.map(n => n.y + n.height + extent(n)));\n break;\n case 'above':\n column = base = Math.min(...all.map(n => n.y));\n break;\n case 'right':\n column = Math.max(...all.map(n => n.x + n.width));\n base = Math.max(...all.map(n => n.x + n.width + extent(n)));\n break;\n case 'left':\n column = base = Math.min(...all.map(n => n.x));\n break;\n }\n if (baseOverride !== undefined) base = baseOverride;\n\n const reach = base + outward * control;\n const points: Cubic = side === 'right' || side === 'left'\n ? [p0, { x: reach, y: p0.y }, { x: reach, y: p3.y }, p3]\n : [p0, { x: p0.x, y: reach }, { x: p3.x, y: reach }, p3];\n\n // The label sits just outside the apex — the one stretch of the bow that's out\n // in the open — and hangs *away* from it, so it neither covers its own arc nor\n // the box edges (and arrowheads) the arc leaves from. Sideways bows anchor the\n // label's near end at the apex; bows over the rows centre it a line below/above.\n const apex = cubicAt(points, 0.5);\n const sideways = side === 'right' || side === 'left';\n const labelX = sideways ? apex.x + outward * EDGE_LABEL_GAP : apex.x;\n const labelY = sideways ? apex.y : apex.y + outward * (EDGE_LABEL_GAP + EDGE_LABEL_FONT_SIZE / 2);\n const along = sideways ? [p0.y, p3.y] : [p0.x, p3.x];\n return {\n path: cubicPath(points),\n labelX,\n labelY,\n labelAnchor: sideways ? (outward > 0 ? 'start' : 'end') : 'middle',\n points,\n bow: {\n side, column, base,\n apex: side === 'right' || side === 'left' ? apex.x : apex.y,\n lo: Math.min(...along), hi: Math.max(...along),\n source, target, obstacles, dir,\n },\n };\n}\n\n/**\n * The gutter the sideways bows need. A bow beside an inner level swings into the\n * gutter to the next one, and past a lane or two it — and its label — reaches the\n * next level's boxes. Widening every gutter to what the widest bow needs is what\n * keeps them out; the outermost level's bows have open space and don't count.\n * Returns the current gap when nothing needs more.\n */\nfunction requiredGap(\n nodes: LayoutNode[],\n edges: LayoutEdge[],\n dir: DependencyDirection,\n metrics: NodeMetrics,\n labelsShown: boolean,\n): number {\n const along = dir === 'horizontal'\n ? { start: (n: LayoutNode) => n.x, end: (n: LayoutNode) => n.x + n.width, out: 'right', back: 'left' }\n : { start: (n: LayoutNode) => n.y, end: (n: LayoutNode) => n.y + n.height, out: 'below', back: 'above' };\n const first = Math.min(...nodes.map(along.start));\n const last = Math.max(...nodes.map(along.end));\n\n let need = metrics.gap;\n for (const { bow, label } of edges) {\n if (!bow) continue;\n // Sideways labels run on from the apex; labels over the rows sit a line beyond it.\n const shown = labelsShown && label;\n const room = dir === 'horizontal'\n ? (shown ? EDGE_LABEL_GAP + edgeLabelWidth(metrics.measure, label) : 0)\n : (shown ? EDGE_LABEL_GAP + EDGE_LABEL_FONT_SIZE : 0);\n if (bow.side === along.out && bow.column < last) {\n need = Math.max(need, bow.apex - bow.column + room + BOW_LABEL_MARGIN);\n } else if (bow.side === along.back && bow.column > first) {\n need = Math.max(need, bow.column - bow.apex + room + BOW_LABEL_MARGIN);\n }\n }\n return Math.ceil(need);\n}\n\n/** Sides perpendicular to the flow — the row/column gutters a bow can travel along. */\nconst acrossSides = (dir: DependencyDirection): BowSide[] =>\n dir === 'horizontal' ? ['below', 'above'] : ['right', 'left'];\n\n/** Sides along the flow — where two nodes level with each other have free space. */\nconst alongSides = (dir: DependencyDirection): BowSide[] =>\n dir === 'horizontal' ? ['right', 'left'] : ['below', 'above'];\n\n/**\n * Cross-references connect arbitrary pairs, so unlike parent→child edges (which\n * always run down the gutter between two levels) they can cut straight across\n * unrelated nodes. Pick the cleanest of a handful of candidate routes.\n *\n * Which routes are candidates depends on where the target sits relative to the\n * source along the flow:\n *\n * - *ahead* (a later column): the direct S-curve down the gutter, unless something\n * sits in its way — then a bow over the rows, or failing that beside them.\n * - *behind* (an earlier column, a return edge): never direct — it would double\n * back through its own columns — but the same bows.\n * - *level* (the same column, i.e. siblings): only the sideways bows. Neither the\n * direct curve nor a bow over the rows can work here: both would run through the\n * two endpoints themselves, and hide behind them.\n *\n * This is a small fixed search, not obstacle-avoiding routing: it clears the\n * common cases cheaply, but a dense enough graph can leave every candidate\n * crossing something. Then the least-bad one wins, and `direct` wins ties — a\n * pointless detour reads worse than a short hop behind one box.\n */\nfunction routeCrossRef(\n source: LayoutNode,\n target: LayoutNode,\n dir: DependencyDirection,\n nodes: LayoutNode[],\n): EdgeGeometry {\n const exclude = new Set([source.id, target.id]);\n const [s0, s1] = dir === 'horizontal' ? [source.x, source.x + source.width] : [source.y, source.y + source.height];\n const [t0, t1] = dir === 'horizontal' ? [target.x, target.x + target.width] : [target.y, target.y + target.height];\n const ahead = t0 >= s1;\n const behind = t1 <= s0;\n\n let best: EdgeGeometry | null = null;\n let bestCount = Infinity;\n let obstacles: LayoutNode[];\n let sides: BowSide[];\n\n if (ahead) {\n const direct = directGeometry(source, target, dir);\n obstacles = crossedNodes(direct.points, nodes, exclude);\n if (!obstacles.length) return direct;\n best = direct;\n bestCount = obstacles.length;\n sides = [...acrossSides(dir), ...alongSides(dir)];\n } else {\n // What lies between them, for the bow to clear: whatever the straight line\n // from centre to centre would cross.\n const c0 = { x: source.x + source.width / 2, y: source.y + source.height / 2 };\n const c1 = { x: target.x + target.width / 2, y: target.y + target.height / 2 };\n obstacles = crossedNodes([c0, c0, c1, c1], nodes, exclude);\n sides = behind ? [...acrossSides(dir), ...alongSides(dir)] : alongSides(dir);\n }\n\n for (const side of sides) {\n const candidate = bowedGeometry(source, target, obstacles, side, dir);\n const count = crossedNodes(candidate.points, nodes, exclude).length;\n if (count < bestCount) {\n best = candidate;\n bestCount = count;\n if (count === 0) break;\n }\n }\n return best ?? bowedGeometry(source, target, obstacles, sides[0], dir);\n}\n\n/**\n * Bows that share a side and overlap along it — three siblings all depending on\n * the same fourth, say — would otherwise be drawn one on top of the other, and\n * read as a single edge with several arrowheads. This spreads them into lanes:\n * the shorter span nests inside the longer, and each lane clears the last by\n * `BOW_LANE_STEP`, so every arc stays its own line.\n *\n * Grouped by side *and* column, so bows in different gutters don't take lanes\n * from each other. A group shares one base line — the furthest any of its bows\n * had to clear — or lanes measured from different bases could land on top of\n * each other. Within a group it's greedy interval colouring, shortest span first;\n * enough for the handful of bows a readable graph has.\n */\nfunction spreadBows(edges: LayoutEdge[]): void {\n const groups = new Map<string, { edge: LayoutEdge; bow: BowInfo }[]>();\n for (const edge of edges) {\n if (edge.bow) push(groups, `${edge.bow.side}@${Math.round(edge.bow.column)}`, { edge, bow: edge.bow });\n }\n\n for (const group of groups.values()) {\n if (group.length < 2) continue;\n group.sort((a, b) => (a.bow.hi - a.bow.lo) - (b.bow.hi - b.bow.lo));\n const side = group[0].bow.side;\n const base = side === 'below' || side === 'right'\n ? Math.max(...group.map(g => g.bow.base))\n : Math.min(...group.map(g => g.bow.base));\n\n const placed: { lo: number; hi: number; lane: number }[] = [];\n for (const { edge, bow } of group) {\n // Strict overlap: bows that only meet at a shared endpoint can chain in one\n // lane, and read as one continuous line through it.\n const taken = new Set(placed.filter(p => p.lo < bow.hi && bow.lo < p.hi).map(p => p.lane));\n let lane = 0;\n while (taken.has(lane)) lane++;\n placed.push({ lo: bow.lo, hi: bow.hi, lane });\n if (lane === 0 && base === bow.base) continue;\n\n const geo = bowedGeometry(bow.source, bow.target, bow.obstacles, bow.side, bow.dir, lane, base);\n edge.path = geo.path;\n edge.labelX = geo.labelX;\n edge.labelY = geo.labelY;\n edge.labelAnchor = geo.labelAnchor;\n edge.bow = geo.bow;\n }\n }\n}\n\n/**\n * Falls back to `depends` for anything not in the style table. Callers may pass a\n * relation that only carries a free-form `relationLabel`, and untyped callers can\n * pass an unknown string — neither may end up with an undefined style or an\n * arrow marker id that doesn't exist in the template's `<defs>`.\n */\nfunction resolveRelation(relation: DependencyRelation | undefined): DependencyRelation {\n return relation && RELATION_STYLES[relation] ? relation : 'depends';\n}\n\nfunction createCrossRefEdges(\n nodeMap: Map<string, LayoutNode>, allOriginal: Map<string, DependencyNode>,\n dir: DependencyDirection, backEdges: BackEdge[],\n): LayoutEdge[] {\n const edges: LayoutEdge[] = [];\n const nodes = [...nodeMap.values()];\n\n for (const [, orig] of allOriginal) {\n if (!orig.dependsOn?.length) continue;\n const target = nodeMap.get(orig.id);\n if (!target) continue;\n\n for (const dep of orig.dependsOn) {\n const source = nodeMap.get(dep.id);\n if (!source) continue;\n\n const relation = resolveRelation(dep.relation);\n const style = RELATION_STYLES[relation];\n const geo = routeCrossRef(source, target, dir, nodes);\n\n edges.push({\n id: `${dep.id}⇢${orig.id}`, sourceId: dep.id, targetId: orig.id,\n path: geo.path, relation: dep.relation,\n label: dep.relationLabel ?? style.label,\n labelX: geo.labelX, labelY: geo.labelY, labelAnchor: geo.labelAnchor,\n color: style.color, dashed: style.dashed, isCrossRef: true,\n arrow: true, marker: relation, bow: geo.bow,\n });\n }\n }\n\n // Links the tree layout couldn't follow (cycle, or a node reached from a second\n // parent). The relationship is real, so draw it as a cross-reference rather than\n // dropping it silently. The router bows them where they point against the flow\n // (a cycle) and takes the gutter where they don't (a second parent one column\n // back from a shared child).\n for (const back of backEdges) {\n const source = nodeMap.get(back.from);\n const target = nodeMap.get(back.to);\n if (!source || !target) continue;\n\n const style = RELATION_STYLES.depends;\n const geo = routeCrossRef(source, target, dir, nodes);\n edges.push({\n id: `${back.from}↺${back.to}`, sourceId: back.from, targetId: back.to,\n path: geo.path, labelX: geo.labelX, labelY: geo.labelY, labelAnchor: geo.labelAnchor,\n color: style.color, dashed: true, isCrossRef: true,\n arrow: true, marker: 'depends', bow: geo.bow,\n });\n }\n\n spreadBows(edges);\n return edges;\n}\n\n// ── Layered (DAG) layout ─────────────────────────────────────────────────────\n\n/** A link as the layered layout sees it: a precedence constraint plus its styling. */\ninterface GraphEdge {\n /** Predecessor — placed in an earlier layer (left / above). */\n from: string;\n /** Dependent — placed in a later layer. */\n to: string;\n relation?: DependencyRelation;\n label?: string;\n /** A `children` link. Keeps the tree edge's neutral styling and carries no label. */\n structural: boolean;\n /** Points against the topological flow. Excluded from layering, drawn bowed. */\n back: boolean;\n}\n\n/**\n * Flattens the input into the node set and the precedence links the layered\n * layout works on.\n *\n * Both link kinds are precedence: `dependsOn` says \"this comes after that\", and a\n * `children` link says the same of a parent and its child. Layering over their\n * union is what keeps a `children` edge pointing *with* the flow instead of\n * doubling back across the graph, and means nothing in the input goes undrawn.\n * A pair joined both ways is one edge, styled by its `dependsOn` relation.\n *\n * A self-link is dropped: it constrains a node to sit after itself, which no\n * layering can satisfy, and it has nowhere to be drawn.\n */\nfunction collectGraph(roots: DependencyNode[]): {\n order: string[];\n nodes: Map<string, DependencyNode>;\n edges: GraphEdge[];\n} {\n const nodes = new Map<string, DependencyNode>();\n const order: string[] = [];\n const edges = new Map<string, GraphEdge>();\n\n const walk = (node: DependencyNode): void => {\n if (!nodes.has(node.id)) {\n nodes.set(node.id, node);\n order.push(node.id);\n }\n for (const child of node.children || []) {\n const fresh = !nodes.has(child.id);\n if (node.id !== child.id) {\n edges.set(`${node.id}→${child.id}`, {\n from: node.id, to: child.id, structural: true, back: false,\n });\n }\n // Guards the recursion: a cycle or a second parent revisits a node that is\n // already collected, and there is nothing left to collect from it.\n if (fresh) walk(child);\n }\n };\n for (const root of roots) walk(root);\n\n for (const id of order) {\n for (const dep of nodes.get(id)?.dependsOn || []) {\n if (dep.id === id || !nodes.has(dep.id)) continue;\n const style = RELATION_STYLES[resolveRelation(dep.relation)];\n edges.set(`${dep.id}→${id}`, {\n from: dep.id, to: id, relation: dep.relation,\n label: dep.relationLabel ?? style.label,\n structural: false, back: false,\n });\n }\n }\n\n return { order, nodes, edges: [...edges.values()] };\n}\n\n/**\n * Longest-path layering: a node sits one layer past the deepest thing it depends\n * on, so every forward edge points strictly onwards and a node with several\n * predecessors clears *all* of them. Nodes with no predecessor land in layer 0.\n *\n * A cycle can't be layered — some link in the loop has to point backwards. A DFS\n * picks those out (a link to a node still on the stack) and marks them `back`;\n * the layering then runs on what's left, which is acyclic by construction. So a\n * cyclic input lays out fine, with the loop-closing links drawn as return edges.\n */\nfunction assignLayers(order: string[], edges: GraphEdge[]): Map<string, number> {\n const out = new Map<string, GraphEdge[]>();\n for (const edge of edges) push(out, edge.from, edge);\n\n // Iterative DFS: a recursive one overflows the stack on a long chain, and a\n // process-order graph is mostly chain.\n const UNSEEN = 0, ON_STACK = 1, DONE = 2;\n const state = new Map<string, number>();\n for (const start of order) {\n if (state.get(start)) continue;\n state.set(start, ON_STACK);\n const stack: { id: string; next: number }[] = [{ id: start, next: 0 }];\n while (stack.length) {\n const frame = stack[stack.length - 1];\n const outgoing = out.get(frame.id) ?? [];\n if (frame.next >= outgoing.length) {\n state.set(frame.id, DONE);\n stack.pop();\n continue;\n }\n const edge = outgoing[frame.next++];\n const seen = state.get(edge.to) ?? UNSEEN;\n if (seen === ON_STACK) edge.back = true; // closes a loop\n if (seen !== UNSEEN) continue;\n state.set(edge.to, ON_STACK);\n stack.push({ id: edge.to, next: 0 });\n }\n }\n\n // Longest path over what's left, walked in topological order.\n const indegree = new Map<string, number>(order.map(id => [id, 0]));\n for (const edge of edges) {\n if (!edge.back) indegree.set(edge.to, (indegree.get(edge.to) ?? 0) + 1);\n }\n\n const layer = new Map<string, number>(order.map(id => [id, 0]));\n const queue = order.filter(id => !indegree.get(id));\n for (let i = 0; i < queue.length; i++) {\n for (const edge of out.get(queue[i]) ?? []) {\n if (edge.back) continue;\n layer.set(edge.to, Math.max(layer.get(edge.to) ?? 0, (layer.get(queue[i]) ?? 0) + 1));\n const remaining = (indegree.get(edge.to) ?? 0) - 1;\n indegree.set(edge.to, remaining);\n if (!remaining) queue.push(edge.to);\n }\n }\n return layer;\n}\n\n/** Median of the neighbour positions, or -1 when a node has no neighbours to follow. */\nfunction median(values: number[]): number {\n if (!values.length) return -1;\n const sorted = [...values].sort((a, b) => a - b);\n const mid = sorted.length >> 1;\n return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;\n}\n\n/** Row index of every node within its own layer. */\nfunction positionIndex(layers: string[][]): Map<string, number> {\n const index = new Map<string, number>();\n for (const layer of layers) layer.forEach((id, i) => index.set(id, i));\n return index;\n}\n\n/**\n * Edges cross when their endpoints are ordered oppositely in the two layers they\n * span. Counted per layer *pair* rather than per adjacent layer, so an edge\n * skipping a layer is scored too — this layout has no dummy nodes, and in a\n * dependency graph the long edges are exactly the ones that tangle.\n */\nfunction countCrossings(layers: string[][], edges: GraphEdge[], layerOf: Map<string, number>): number {\n const index = positionIndex(layers);\n const groups = new Map<string, [number, number][]>();\n for (const edge of edges) {\n if (edge.back) continue;\n const from = index.get(edge.from);\n const to = index.get(edge.to);\n if (from === undefined || to === undefined) continue;\n push(groups, `${layerOf.get(edge.from)}:${layerOf.get(edge.to)}`, [from, to]);\n }\n\n let crossings = 0;\n for (const pairs of groups.values()) {\n for (let i = 0; i < pairs.length; i++) {\n for (let j = i + 1; j < pairs.length; j++) {\n if ((pairs[i][0] - pairs[j][0]) * (pairs[i][1] - pairs[j][1]) < 0) crossings++;\n }\n }\n }\n return crossings;\n}\n\n/** Sweeps to run over the layers; each one reorders against the previous result. */\nconst ORDER_SWEEPS = 8;\n\n/**\n * Crossing minimisation, median heuristic (Sugiyama's second phase): a node wants\n * to sit level with the middle of its neighbours, and ordering every layer that\n * way repeatedly untangles the edges between them.\n *\n * Sweeps alternate direction — downward passes order a layer by its predecessors,\n * upward passes by its successors — because settling one side alone just moves the\n * tangle to the other. The heuristic isn't monotonic, so the best ordering seen is\n * kept rather than the last one.\n */\nfunction orderLayers(layers: string[][], edges: GraphEdge[], layerOf: Map<string, number>): string[][] {\n const predecessors = new Map<string, string[]>();\n const successors = new Map<string, string[]>();\n for (const edge of edges) {\n if (edge.back) continue;\n push(predecessors, edge.to, edge.from);\n push(successors, edge.from, edge.to);\n }\n\n const current = layers.map(layer => [...layer]);\n let best = current.map(layer => [...layer]);\n let bestCrossings = countCrossings(current, edges, layerOf);\n\n for (let sweep = 0; sweep < ORDER_SWEEPS && bestCrossings > 0; sweep++) {\n const downward = sweep % 2 === 0;\n const reference = downward ? predecessors : successors;\n const index = positionIndex(current);\n\n // The first layer of a downward sweep (and the last of an upward one) has no\n // reference layer, so it stays as it is and anchors the sweep.\n const targets = current.map((_, i) => i);\n for (const i of downward ? targets.slice(1) : targets.slice(0, -1).reverse()) {\n current[i] = [...current[i]]\n .map((id, row) => {\n const neighbours = (reference.get(id) ?? [])\n .map(n => index.get(n))\n .filter((p): p is number => p !== undefined);\n const m = median(neighbours);\n // No neighbours to follow: hold the current row, so a free node doesn't\n // get swept to the top of the layer on every pass.\n return { id, row, key: m < 0 ? row : m };\n })\n .sort((a, b) => a.key - b.key || a.row - b.row)\n .map(entry => entry.id);\n }\n\n const crossings = countCrossings(current, edges, layerOf);\n if (crossings < bestCrossings) {\n bestCrossings = crossings;\n best = current.map(layer => [...layer]);\n }\n }\n return best;\n}\n\n/** Alignment passes run after ordering, to straighten the edges it left behind. */\nconst ALIGN_PASSES = 4;\n\n/**\n * Secondary-axis coordinates: with the row *order* fixed, slide each node towards\n * the middle of its neighbours so chains run straight instead of stair-stepping.\n *\n * Order and spacing are invariants here — the ordering phase chose them, and this\n * must not undo its work. So each layer is placed by a forward cascade that can\n * only push nodes further along, then shifted back by the average push: a uniform\n * shift keeps every gap and every relative position, and cancels the drift the\n * cascade would otherwise accumulate down the layer.\n */\nfunction alignSecondary(\n layers: string[][],\n edges: GraphEdge[],\n step: number,\n): Map<string, number> {\n const predecessors = new Map<string, string[]>();\n const successors = new Map<string, string[]>();\n for (const edge of edges) {\n if (edge.back) continue;\n push(predecessors, edge.to, edge.from);\n push(successors, edge.from, edge.to);\n }\n\n const pos = new Map<string, number>();\n for (const layer of layers) layer.forEach((id, i) => pos.set(id, i * step));\n\n for (let pass = 0; pass < ALIGN_PASSES; pass++) {\n const downward = pass % 2 === 0;\n const reference = downward ? predecessors : successors;\n const indices = layers.map((_, i) => i);\n\n for (const i of downward ? indices.slice(1) : indices.slice(0, -1).reverse()) {\n const layer = layers[i];\n if (!layer.length) continue;\n\n const wanted = layer.map(id => {\n const neighbours = (reference.get(id) ?? [])\n .map(n => pos.get(n))\n .filter((p): p is number => p !== undefined);\n return neighbours.length ? median(neighbours) : (pos.get(id) ?? 0);\n });\n\n const placed: number[] = [];\n for (let k = 0; k < layer.length; k++) {\n placed[k] = k === 0 ? wanted[k] : Math.max(wanted[k], placed[k - 1] + step);\n }\n const drift = placed.reduce((sum, p, k) => sum + (p - wanted[k]), 0) / placed.length;\n layer.forEach((id, k) => pos.set(id, placed[k] - drift));\n }\n }\n\n // Normalise so the graph starts at the origin, like the tree layout does.\n const min = Math.min(...pos.values());\n for (const [id, value] of pos) pos.set(id, value - min);\n return pos;\n}\n\n/**\n * Places the nodes of a dependency graph in layers running left→right\n * (`horizontal`) or top→bottom (`vertical`).\n *\n * Unlike the tree layout, the column a node lands in is decided by the *graph*, not\n * by the shape of the `children` nesting it happened to arrive in: layer = longest\n * dependency path to it. Every link is drawn, including the ones a tree layout has\n * to discard to keep a single parent per node.\n */\nfunction layoutLayered(\n roots: DependencyNode[],\n dir: DependencyDirection,\n allNodes: Map<string, DependencyNode>,\n metrics: NodeMetrics,\n): { nodes: LayoutNode[]; edges: LayoutEdge[]; nodeMap: Map<string, LayoutNode>; width: number; height: number } {\n const { order, nodes: originals, edges } = collectGraph(roots);\n if (!order.length) {\n return { nodes: [], edges: [], nodeMap: new Map(), width: 0, height: 0 };\n }\n\n const layerOf = assignLayers(order, edges);\n const depth = Math.max(...layerOf.values());\n const layers: string[][] = Array.from({ length: depth + 1 }, () => []);\n for (const id of order) layers[layerOf.get(id) ?? 0].push(id);\n\n const ordered = orderLayers(layers, edges, layerOf);\n\n const primarySize = dir === 'horizontal' ? metrics.width : metrics.height;\n const secondarySize = dir === 'horizontal' ? metrics.height : metrics.width;\n const secondary = alignSecondary(ordered, edges, secondarySize + V_GAP);\n\n const nodes: LayoutNode[] = [];\n const nodeMap = new Map<string, LayoutNode>();\n for (const layer of ordered) {\n for (const id of layer) {\n const source = originals.get(id);\n if (!source) continue;\n const primary = (layerOf.get(id) ?? 0) * (primarySize + metrics.gap);\n const across = secondary.get(id) ?? 0;\n\n // Layers come from the whole graph, not from one parent — there is no\n // single node this one hangs off, so nothing to report as its parent.\n const laid = placeNode(\n source, allNodes.get(id),\n dir === 'horizontal' ? primary : across,\n dir === 'horizontal' ? across : primary,\n layerOf.get(id) ?? 0, null, metrics,\n );\n nodes.push(laid);\n nodeMap.set(id, laid);\n }\n }\n\n const laidOut = [...nodeMap.values()];\n const layoutEdges: LayoutEdge[] = [];\n for (const edge of edges) {\n const source = nodeMap.get(edge.from);\n const target = nodeMap.get(edge.to);\n if (!source || !target) continue;\n\n const relation = resolveRelation(edge.relation);\n const style = RELATION_STYLES[relation];\n // A back edge runs against the flow by definition — its target sits in an\n // earlier layer — so the router bows it clear rather than doubling back\n // through its own layers.\n const geo = routeCrossRef(source, target, dir, laidOut);\n\n layoutEdges.push({\n id: `${edge.from}${edge.back ? '↺' : '⇢'}${edge.to}`,\n sourceId: edge.from, targetId: edge.to,\n path: geo.path, relation: edge.relation, label: edge.label,\n labelX: geo.labelX, labelY: geo.labelY, labelAnchor: geo.labelAnchor,\n color: edge.structural ? 'var(--color-neutral-400)' : style.color,\n dashed: edge.back || (!edge.structural && style.dashed),\n // Everything here is a real dependency, so nothing is dimmed as secondary\n // except the return edges — which the layering had to break to lay out.\n isCrossRef: edge.back,\n arrow: true,\n marker: relation,\n bow: geo.bow,\n });\n }\n spreadBows(layoutEdges);\n\n const width = (depth + 1) * primarySize + depth * metrics.gap;\n const across = Math.max(...laidOut.map(n => (dir === 'horizontal' ? n.y : n.x))) + secondarySize;\n\n return {\n nodes,\n edges: layoutEdges,\n nodeMap,\n width: dir === 'horizontal' ? width : across,\n height: dir === 'horizontal' ? across : width,\n };\n}\n\n// ── Status colors ────────────────────────────────────────────────────────────\n\n// Labels read from the theme's semantic ink, not from a `--color-<status>-700`.\n// Those resolve to dark ink in both themes (error-700 is #6b0909), which on the\n// dark theme's translucent tint over #14222e is dark-on-dark. The status is\n// carried by the border and tint; the label just has to be readable, and\n// --color-text-* is the one pair that flips with the theme.\nconst STATUS_COLORS: Record<DependencyNodeStatus, { bg: string; border: string; text: string }> = {\n default: { bg: 'var(--color-neutral-50)', border: 'var(--color-neutral-300)', text: 'var(--color-text-primary)' },\n active: { bg: 'var(--color-primary-50)', border: 'var(--color-primary-400)', text: 'var(--color-text-primary)' },\n success: { bg: 'var(--color-success-50, #f0fdf4)', border: 'var(--color-success-default)', text: 'var(--color-text-primary)' },\n warning: { bg: 'var(--color-warning-50, #fffbeb)', border: 'var(--color-warning-default)', text: 'var(--color-text-primary)' },\n error: { bg: 'var(--color-error-50, #fef2f2)', border: 'var(--color-error-default)', text: 'var(--color-text-primary)' },\n muted: { bg: 'var(--color-neutral-100)', border: 'var(--color-neutral-200)', text: 'var(--color-text-tertiary)' },\n};\n\n/** Parses `#rgb`, `#rrggbb`, `rgb()` and `rgba()`. Anything else → null. */\nfunction parseRgb(color: string): [number, number, number] | null {\n const hex = color.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);\n if (hex) {\n const h = hex[1];\n const full = h.length === 3 ? h.split('').map(c => c + c).join('') : h;\n return [0, 2, 4].map(i => parseInt(full.slice(i, i + 2), 16)) as [number, number, number];\n }\n const rgb = color.match(/^rgba?\\(([^)]+)\\)/i);\n if (rgb) {\n const p = rgb[1].split(',').map(s => parseFloat(s));\n if (p.length >= 3 && p.every(n => !Number.isNaN(n))) return [p[0], p[1], p[2]];\n }\n return null;\n}\n\n/**\n * Ink that stays readable on an arbitrary caller-supplied `typeColors` value.\n *\n * No theme token can do this job: a type colour is chosen by the consumer, so it\n * may be light while the theme is dark (or the reverse). `--color-neutral-900`\n * looks like \"dark ink\" but the dark theme inverts the neutral scale and resolves\n * it to #f9fafb — white label on a pale tile. Derive the ink from the colour's own\n * luminance instead, and fall back to the theme when it can't be parsed.\n */\nfunction readableInk(color: string): string {\n const rgb = parseRgb(color);\n if (!rgb) return 'var(--color-text-primary)';\n const [r, g, b] = rgb.map(c => {\n const s = c / 255;\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\n });\n const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n return luminance > 0.4 ? '#111827' : '#f9fafb';\n}\n\n/**\n * Dependency viewer component for visualizing hierarchical and cross-cutting relationships.\n *\n * Features:\n * - Tree layout (depth in the `children` nesting) and layered/DAG layout (depth in\n * the dependency graph), via `layout`\n * - Horizontal (left-to-right) and vertical (top-to-bottom) layout directions\n * - Boxes sized to their labels: one width per graph (160–240px), labels wrapping\n * onto a second line past the cap and ellipsised (with a tooltip) past that\n * - Bidirectional dependencies: children (right/down) and dependsOn (cross-references)\n * - Cross-references routed clear of the boxes: down the gutter to a later level,\n * beside the level for siblings, in nested lanes where several overlap\n * - Relationship types: depends, blocks, references, requires, extends, implements, uses\n * - Edge labels showing relationship type\n * - Dashed vs solid edges per relationship category\n * - Color-coded edges per relationship type\n * - Node status colors (default, active, success, warning, error, muted)\n * - Pan and zoom controls with mouse wheel support\n * - Fitting (`fitMode` / `autoFit`, `minNodeSize`) and a static, non-navigable\n * mode (`interactive: false`)\n * - Collapsible sub-trees\n * - Interactive node selection with detail panel\n * - Legend showing active relationship types\n * - SVG arrowhead markers on cross-reference edges\n * - Dark/light theme support\n *\n * ## Feeding it a graph\n *\n * `root` takes a single node (a tree) or an array (a forest — the shape to use for\n * a flat set of items related only by `dependsOn`). Either way the input is treated\n * as a graph: a link back to a node that already has a place in the layout — a\n * cycle, or a node reached from a second parent — is drawn as a cross-reference\n * arrow instead of being followed. Every node is laid out exactly once, and no\n * input can make the layout recurse forever.\n *\n * ## Picking a layout\n *\n * `tree` (default) answers \"what contains what\": the column is the depth in the\n * `children` nesting, and `dependsOn` links are drawn over the top without moving\n * anything.\n *\n * `layered` answers \"what has to happen first\": the column is the depth in the\n * dependency graph, so a node always sits past everything it depends on. Reach for\n * it whenever the question is about order or impact rather than containment —\n * a tree layout can only approximate that by first reducing the graph to a\n * spanning tree, which throws away every link that doesn't fit one parent per node.\n *\n * For incremental exploration, hand in a wider `root` per step and let\n * `nodeExpand` drive the loading. Pan, zoom, collapse state and selection all\n * survive a `root` swap, and `anchorNodeId` (defaulting to the selected node)\n * keeps the viewport pinned while the graph grows around it.\n *\n * @example\n * ```html\n * <lc-dependency-viewer [root]=\"specTree\" direction=\"horizontal\" />\n * ```\n *\n * @example Order of work — a flat set of items, laid out by their dependencies\n * ```html\n * <lc-dependency-viewer\n * [root]=\"items()\"\n * layout=\"layered\"\n * direction=\"horizontal\"\n * fitMode=\"fit-width\"\n * (nodeSelect)=\"openItem($event)\"\n * />\n * ```\n *\n * @example Static overview — the whole graph at a glance, click-through only\n * ```html\n * <lc-dependency-viewer\n * [root]=\"graph()\"\n * [autoFit]=\"true\"\n * [interactive]=\"false\"\n * height=\"360px\"\n * (nodeSelect)=\"openDetail($event)\"\n * />\n * ```\n *\n * @example Incremental graph exploration\n * ```html\n * <lc-dependency-viewer\n * [root]=\"graph()\"\n * [anchorNodeId]=\"anchor()\"\n * [typeColors]=\"{ Alpha: '#c1e3e9' }\"\n * (nodeSelect)=\"showDetails($event)\"\n * (nodeExpand)=\"loadNeighbours($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-dependency-viewer',\n standalone: true,\n templateUrl: './dependency-viewer.component.html',\n styleUrls: ['./dependency-viewer.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { '[class]': '\"dep-viewer\"', '[style.height]': 'hostHeight()' },\n})\nexport class DependencyViewerComponent {\n /**\n * The graph to draw. A single node is the root of a tree; an array is a forest,\n * which is how you feed a flat set of items that has no natural root — e.g. the\n * specs of a plan, related only by `dependsOn`.\n */\n readonly root = input.required<DependencyNode | DependencyNode[]>();\n readonly direction = input<DependencyDirection>('horizontal');\n readonly height = input('500px');\n\n /**\n * `tree` (default) places nodes by their depth in the `children` nesting, and\n * draws `dependsOn` links over the top as cross-references.\n *\n * `layered` places them by their depth in the *dependency* graph: a node always\n * sits past everything it depends on, transitively, and nodes that depend on\n * nothing start the first layer. That makes `direction=\"horizontal\"` read as an\n * order of work — left to right — which a tree layout can only approximate by\n * first throwing away every link that doesn't fit a single-parent hierarchy.\n *\n * Use `layered` for process, sequencing and impact views; `tree` for containment\n * hierarchies, where the nesting *is* the structure.\n */\n readonly layout = input<DependencyLayout>('tree');\n readonly showToolbar = input(true);\n readonly showEdgeLabels = input(true);\n readonly edgeWidth = input(1.5);\n\n /**\n * Scales and centres the graph so that all of it fits the canvas, and re-fits\n * whenever the container or the graph changes size. Turns the viewer into an\n * overview: nothing to pan or zoom to, everything visible at once.\n *\n * Shrinks only — the fit never enlarges past 100%, so a two-node graph keeps its\n * natural size instead of ballooning to fill the frame.\n *\n * Pair with `interactive: false` for a purely static display.\n *\n * Shorthand for `fitMode=\"contain\"`, which supersedes it.\n */\n readonly autoFit = input(false);\n\n /**\n * How the graph is scaled into the frame. Defaults to `autoFit`'s setting —\n * `contain` when it is on, `none` when it isn't — and overrides it when set.\n *\n * `contain` fits both axes, so everything is visible at once but a big graph\n * shrinks to get there. `fit-width` fits the width only and lets the viewer grow\n * as tall as the graph needs, so the nodes keep a readable size and the *page*\n * scrolls; the graph itself never scrolls internally. Past roughly 20 nodes a\n * process view generally wants `fit-width`.\n */\n readonly fitMode = input<DependencyFitMode | null>(null);\n\n /**\n * Smallest node width, in px, that fitting may shrink to. Below it the fit stops\n * scaling down and lets the graph overflow instead — which `fit-width` turns into\n * page scroll, and `contain` into clipping. Pair it with `fit-width`.\n *\n * Nodes are 160px wide unscaled (wider — up to 240px — when the graph's labels\n * need it), so e.g. `80` allows shrinking to half size.\n */\n readonly minNodeSize = input<number | null>(null);\n\n /**\n * Viewport navigation: drag-to-pan, wheel-zoom and the toolbar's zoom buttons.\n * `false` freezes the viewport — node selection, expansion and collapse keep\n * working, so `nodeSelect` still fires in a static viewer.\n */\n readonly interactive = input(true);\n\n /**\n * Node the viewport holds still across `root` updates. Defaults to the node the\n * user last selected, which keeps click-to-expand steady without any wiring.\n * Set it explicitly to anchor somewhere else (e.g. a deep-linked node).\n */\n readonly anchorNodeId = input<string | null>(null);\n\n /** Fill colour per `DependencyNode.type`, e.g. `{ Class: '#8ea475' }`. */\n readonly typeColors = input<Record<string, string>>({});\n\n /** Relations to hide. Cross-reference edges of these types aren't rendered. */\n readonly hiddenRelations = input<readonly DependencyRelation[]>([]);\n\n /** Node types to hide, matched against `DependencyNode.type`. */\n readonly hiddenTypes = input<readonly string[]>([]);\n\n /** Tooltip and accessible name of the zoom-in button. */\n readonly zoomInLabel = input('Zoom in');\n\n /** Tooltip and accessible name of the zoom-out button. */\n readonly zoomOutLabel = input('Zoom out');\n\n /** Tooltip and accessible name of the reset-zoom button. */\n readonly resetZoomLabel = input('Reset');\n\n /** Prefix of the depth in the detail panel. */\n readonly depthLabel = input('Depth:');\n\n /** Prefix of the child count in the detail panel. */\n readonly childrenLabel = input('Children:');\n\n /** Prefix of the dependency count in the detail panel. */\n readonly dependsOnLabel = input('Depends on:');\n\n /** Heading of the dependency list in the detail panel. */\n readonly dependenciesLabel = input('Dependencies:');\n\n /** Fires when a node is selected (not on deselect), with the original node incl. `data`. */\n readonly nodeSelect = output<DependencyNode>();\n\n /** Fires on double-click — the hook for \"expand this node's neighbourhood\". */\n readonly nodeExpand = output<DependencyNode>();\n\n protected zoom = signal(100);\n protected panX = signal(40);\n protected panY = signal(40);\n protected selectedNodeId = signal<string | null>(null);\n protected collapsedIds = signal<Set<string>>(new Set());\n\n private isPanning = false;\n private lastMouseX = 0;\n private lastMouseY = 0;\n\n private readonly hostEl = inject(ElementRef<HTMLElement>);\n private readonly canvasRef = viewChild<ElementRef<HTMLElement>>('canvas');\n\n /** Last known layout position of the anchor, to compensate pan after a relayout. */\n private anchorPos: { id: string; x: number; y: number } | null = null;\n\n /** Template constants for laying out the label lines. */\n protected readonly lineHeight = LABEL_LINE_HEIGHT;\n protected readonly baselineShift = LABEL_BASELINE_SHIFT;\n\n /**\n * Measures label text in the font the labels are drawn in. Built once, on first\n * use — the host's font is what the SVG text inherits, and it isn't known until\n * the component is in the document.\n */\n private textMeasure: TextMeasure | null = null;\n\n private measureText(): TextMeasure {\n if (!this.textMeasure) {\n let family = '';\n if (typeof getComputedStyle === 'function') {\n family = getComputedStyle(this.hostEl.nativeElement).fontFamily;\n }\n this.textMeasure = createTextMeasurer(family || 'sans-serif', LABEL_FONT_SIZE, LABEL_FONT_WEIGHT);\n }\n return this.textMeasure;\n }\n\n private roots = computed<DependencyNode[]>(() => {\n const root = this.root();\n return Array.isArray(root) ? root : [root];\n });\n\n protected effectiveRoots = computed<DependencyNode[]>(() => {\n const collapsed = this.collapsedIds();\n // One `visited` set across the whole forest: a node reachable from two roots\n // is the same node, and must be pruned identically wherever it turns up.\n const visited = new Set<string>();\n return this.roots().map(root => this.pruneCollapsed(root, collapsed, visited));\n });\n\n private allOriginalNodes = computed(() => {\n const map = new Map<string, DependencyNode>();\n for (const root of this.roots()) collectAllNodes(root, map);\n return map;\n });\n\n /** Box size and label lines, sized over the whole input — see `measureNodes`. */\n private nodeMetrics = computed(() => measureNodes(this.allOriginalNodes().values(), this.measureText()));\n\n /**\n * The laid-out graph. Named `graph` rather than `layout` because `layout` is the\n * input that picks *how* it gets laid out.\n */\n protected graph = computed(() => {\n const dir = this.direction();\n const hiddenTypes = new Set(this.hiddenTypes());\n const hiddenRelations = new Set(this.hiddenRelations());\n const allNodes = this.allOriginalNodes();\n\n const place = (metrics: NodeMetrics) =>\n this.layout() === 'layered'\n ? layoutLayered(this.effectiveRoots(), dir, allNodes, metrics)\n : this.layoutTree(dir, allNodes, metrics);\n\n // Lay out, and if the bows between siblings need more gutter than the levels\n // got, lay out again with that gutter. Once is enough: the wider gutter\n // changes where the levels sit, not which pairs are level with each other.\n const metrics = this.nodeMetrics();\n let placed = place(metrics);\n const gap = requiredGap(placed.nodes, placed.edges, dir, metrics, this.showEdgeLabels());\n if (gap > metrics.gap) placed = place({ ...metrics, gap });\n\n const edges = placed.edges.filter(e => !(e.relation && hiddenRelations.has(e.relation)));\n\n // Type filtering hides nodes and anything still pointing at them. It runs\n // after layout so the remaining nodes keep the positions they'd have anyway —\n // toggling a filter must not reshuffle the whole graph.\n const visibleNodes = hiddenTypes.size\n ? placed.nodes.filter(n => !(n.type && hiddenTypes.has(n.type)))\n : placed.nodes;\n const visibleIds = new Set(visibleNodes.map(n => n.id));\n const visibleEdges = hiddenTypes.size\n ? edges.filter(e => visibleIds.has(e.sourceId) && visibleIds.has(e.targetId))\n : edges;\n\n return {\n nodes: visibleNodes,\n edges: visibleEdges,\n nodeMap: placed.nodeMap,\n width: placed.width,\n height: placed.height,\n };\n });\n\n /**\n * Tree layout over the forest: each root gets its own band along the secondary\n * axis. A `visited` set shared by all of them keeps a node that hangs off two\n * roots from being laid out twice — the second link becomes a cross-reference,\n * exactly as a second parent within one tree does.\n */\n private layoutTree(dir: DependencyDirection, allNodes: Map<string, DependencyNode>, metrics: NodeMetrics) {\n const backEdges: BackEdge[] = [];\n const visited = new Set<string>();\n const measured = this.effectiveRoots().map(root => measureTree(root, 0, dir, visited, backEdges, metrics));\n\n const nodes: LayoutNode[] = [];\n const nodeMap = new Map<string, LayoutNode>();\n const treeEdges: LayoutEdge[] = [];\n\n let offset = 0;\n for (const measure of measured) {\n if (dir === 'horizontal') {\n layoutTreeH(measure, 0, offset, null, nodes, treeEdges, allNodes, nodeMap, metrics);\n } else {\n layoutTreeV(measure, offset, 0, null, nodes, treeEdges, allNodes, nodeMap, metrics);\n }\n offset += measure.secondary + V_GAP;\n }\n\n const primary = measured.length ? Math.max(...measured.map(m => m.primary)) : 0;\n const secondary = Math.max(0, offset - V_GAP);\n\n return {\n nodes,\n edges: [...treeEdges, ...createCrossRefEdges(nodeMap, allNodes, dir, backEdges)],\n nodeMap,\n width: dir === 'horizontal' ? primary : secondary,\n height: dir === 'horizontal' ? secondary : primary,\n };\n }\n\n /**\n * Height `fit-width` derived from the graph, or `null` under any other mode.\n *\n * `fit-width` scales to the frame's width and lets the height follow the graph,\n * so a tall graph runs past the frame and the *page* scrolls instead of the nodes\n * shrinking out of legibility. The height is therefore always the graph's, never\n * the frame's — including when the graph is the shorter of the two. Deriving it\n * unconditionally is also what keeps the fit stable: this height becomes the\n * canvas's, so a fit that consulted the canvas height would be reading back its\n * own last output and could flip between two answers forever.\n */\n protected contentHeight = signal<number | null>(null);\n\n protected effectiveFitMode = computed<DependencyFitMode>(() =>\n this.fitMode() ?? (this.autoFit() ? 'contain' : 'none'),\n );\n\n /** The host only gives up its configured height when the fit made it grow. */\n protected hostHeight = computed(() => (this.contentHeight() === null ? this.height() : 'auto'));\n\n /** `minNodeSize` expressed as the scale it forbids fitting to go below. */\n private minFitScale = computed(() => {\n const min = this.minNodeSize();\n if (!min || min <= 0) return MIN_FIT_SCALE;\n return Math.min(MAX_FIT_SCALE, Math.max(MIN_FIT_SCALE, min / this.nodeMetrics().width));\n });\n\n constructor() {\n // Keep the anchor node pinned to its screen position across relayouts. A new\n // `root` (an expand step) re-runs the tree layout from scratch, which recentres\n // subtrees and shifts nodes that didn't change — the camera stays put while the\n // graph slides underneath it. Compensating the pan by the anchor's own delta is\n // what makes incremental expansion feel stable.\n effect(() => {\n const nodeMap = this.graph().nodeMap;\n const anchorId = this.anchorNodeId() ?? this.selectedNodeId();\n\n // Fitting recentres the whole graph on every relayout, which subsumes\n // holding one node still. Running both would have them fight over the pan.\n if (this.effectiveFitMode() !== 'none' || !anchorId) {\n this.anchorPos = null;\n return;\n }\n const node = nodeMap.get(anchorId);\n if (!node) {\n this.anchorPos = null;\n return;\n }\n\n const prev = this.anchorPos;\n if (prev && prev.id === anchorId && (prev.x !== node.x || prev.y !== node.y)) {\n const dx = node.x - prev.x;\n const dy = node.y - prev.y;\n // `transform: translate(pan px) scale(z)` with `transform-origin: 0 0`, so\n // screen = pan + z * layout — a layout delta moves the node by z * delta.\n untracked(() => {\n const z = this.zoom() / 100;\n this.panX.set(this.panX() - dx * z);\n this.panY.set(this.panY() - dy * z);\n });\n }\n this.anchorPos = { id: anchorId, x: node.x, y: node.y };\n });\n\n // Re-fit when the graph changes shape. Reading `canvasRef` here (rather than\n // only inside `fit`) is what gets the *first* fit to run: the view child\n // resolves after the initial render, which re-triggers this effect at the\n // point the canvas finally has a measurable size.\n effect(() => {\n if (this.effectiveFitMode() === 'none') {\n // Leaving fit-width behind: the grown height was this fit's doing, so it\n // goes with it, or the host keeps a size nothing is maintaining any more.\n untracked(() => this.contentHeight.set(null));\n return;\n }\n if (!this.canvasRef()) return;\n this.graph();\n this.minFitScale();\n untracked(() => this.fit());\n });\n\n // …and when the container changes size. ResizeObserver delivers an initial\n // callback on observe, so this covers the first fit in a browser too.\n effect(onCleanup => {\n const el = this.canvasRef()?.nativeElement;\n if (this.effectiveFitMode() === 'none' || !el || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => this.fit());\n observer.observe(el);\n onCleanup(() => observer.disconnect());\n });\n }\n\n protected svgWidth = computed(() => this.graph().width + 80);\n protected svgHeight = computed(() => this.graph().height + 80);\n protected viewBox = computed(() => `0 0 ${this.svgWidth()} ${this.svgHeight()}`);\n protected transform = computed(() => {\n const z = this.zoom() / 100;\n return `translate(${this.panX()}px, ${this.panY()}px) scale(${z})`;\n });\n\n // A fitted scale is an arbitrary fraction; the readout is not the source of\n // truth, so it rounds rather than printing \"63.41999999%\".\n protected zoomLabel = computed(() => Math.round(this.zoom()));\n\n protected selectedNode = computed<LayoutNode | null>(() => {\n const id = this.selectedNodeId();\n if (!id) return null;\n return this.graph().nodes.find(n => n.id === id) ?? null;\n });\n\n protected selectedDependsOn = computed<DependencyEdgeDef[]>(() => {\n const id = this.selectedNodeId();\n if (!id) return [];\n return this.allOriginalNodes().get(id)?.dependsOn ?? [];\n });\n\n // Grouped by label rather than relation, so free-form `relationLabel`s (CALLS,\n // HAS_COLUMN, …) each get their own entry instead of collapsing into the handful\n // of built-in relation types they borrow their colour from.\n protected legendItems = computed(() => {\n const seen = new Map<string, { label: string; color: string; dashed: boolean }>();\n for (const edge of this.graph().edges) {\n // Keyed off the label, not `isCrossRef`: in the layered layout the labelled\n // dependency edges are the main flow, not cross-references.\n if (!edge.label || seen.has(edge.label)) continue;\n seen.set(edge.label, { label: edge.label, color: edge.color, dashed: edge.dashed });\n }\n return Array.from(seen.values());\n });\n\n protected typeLegendItems = computed(() => {\n const colors = this.typeColors();\n const seen = new Map<string, { type: string; color: string }>();\n for (const node of this.graph().nodes) {\n if (!node.type || seen.has(node.type) || !colors[node.type]) continue;\n seen.set(node.type, { type: node.type, color: colors[node.type] });\n }\n return Array.from(seen.values());\n });\n\n // O(1) against the collected map. Deliberately keyed off the *original* tree, so\n // a collapsed node keeps its \"+\" toggle even though it has no children in the\n // pruned tree that gets laid out.\n protected hasChildren(nodeId: string): boolean {\n return !!this.allOriginalNodes().get(nodeId)?.children?.length;\n }\n\n protected isCollapsed(nodeId: string): boolean {\n return this.collapsedIds().has(nodeId);\n }\n\n protected getRelationLabel(relation: DependencyRelation): string {\n return RELATION_STYLES[relation]?.label ?? relation;\n }\n\n // `visited` keeps a cyclic graph from recursing forever here too — this runs\n // before the layout's own guard sees the tree.\n private pruneCollapsed(\n node: DependencyNode,\n collapsed: Set<string>,\n visited: Set<string>,\n ): DependencyNode {\n if (visited.has(node.id) || collapsed.has(node.id) || !node.children?.length) {\n return { ...node, children: [] };\n }\n visited.add(node.id);\n return {\n ...node,\n children: node.children.map(c => this.pruneCollapsed(c, collapsed, visited)),\n };\n }\n\n protected selectNode(id: string, event: Event): void {\n event.stopPropagation();\n const next = this.selectedNodeId() === id ? null : id;\n this.selectedNodeId.set(next);\n if (!next) return;\n const original = this.allOriginalNodes().get(id);\n if (original) this.nodeSelect.emit(original);\n }\n\n protected expandNode(id: string, event: Event): void {\n event.stopPropagation();\n // A double-click also delivers two clicks, which would toggle the selection\n // straight back off. Re-assert it so the expanded node stays selected — and\n // stays the anchor the viewport holds onto.\n this.selectedNodeId.set(id);\n const original = this.allOriginalNodes().get(id);\n if (original) this.nodeExpand.emit(original);\n }\n\n protected toggleCollapse(id: string, event: Event): void {\n event.stopPropagation();\n this.collapsedIds.update(set => {\n const next = new Set(set);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n protected deselectNode(): void { this.selectedNodeId.set(null); }\n protected zoomIn(): void { this.zoom.update(z => Math.min(z + 25, 300)); }\n protected zoomOut(): void { this.zoom.update(z => Math.max(z - 25, 25)); }\n protected resetZoom(): void { this.resetView(); }\n\n // ── Imperative API ─────────────────────────────────────────────────────────\n // For deep links (?anchor=<key> → centre on that node) and programmatic\n // expand/collapse. Mirrors lc-tree-view's expandAll()/collapseAll() surface.\n\n /** Centres the viewport on a node. No-op for an id that isn't laid out. */\n focusNode(id: string): void {\n const node = this.graph().nodeMap.get(id);\n if (!node) return;\n const z = this.zoom() / 100;\n const el = this.canvasEl();\n const viewW = el?.clientWidth ?? 0;\n const viewH = el?.clientHeight ?? 0;\n // Invert screen = pan + z * layout for the node's centre.\n this.panX.set(viewW / 2 - (node.x + node.width / 2) * z);\n this.panY.set(viewH / 2 - (node.y + node.height / 2) * z);\n this.anchorPos = { id, x: node.x, y: node.y };\n }\n\n /**\n * Scales and centres the graph to fit the canvas, per `fitMode`. Called for you\n * when fitting is on; public so a caller can fit on demand without it.\n *\n * No-op while the canvas has no size (before the first render, or in a detached\n * / `display: none` container) — the fit observers re-run once it does.\n */\n fit(): void {\n const mode = this.effectiveFitMode();\n if (mode === 'none') return;\n\n const el = this.canvasEl();\n const viewW = el?.clientWidth ?? 0;\n const viewH = el?.clientHeight ?? 0;\n if (!viewW || !viewH) return;\n\n const box = this.contentBox();\n if (box.width <= 0 || box.height <= 0) return;\n\n // `fit-width` deliberately ignores the height: it is the mode that lets the\n // graph be taller than the frame. That is also what keeps it stable — the\n // height it produces feeds back in as the canvas's own height, and a scale\n // derived from that height would chase itself.\n const natural = mode === 'fit-width'\n ? viewW / box.width\n : Math.min(viewW / box.width, viewH / box.height);\n const scale = Math.min(MAX_FIT_SCALE, Math.max(this.minFitScale(), natural));\n\n this.zoom.set(scale * 100);\n // Invert screen = pan + scale * layout for the box's top-left corner, so the\n // box lands centred in the canvas.\n this.panX.set((viewW - box.width * scale) / 2 - box.x * scale);\n\n const scaledHeight = box.height * scale;\n if (mode === 'fit-width') {\n // The viewer takes the graph's height and pins it to the top. Past the frame\n // that means the page scrolls through a readable graph rather than the frame\n // clipping one that was shrunk to fit.\n this.contentHeight.set(Math.ceil(scaledHeight));\n this.panY.set(-box.y * scale);\n } else {\n this.contentHeight.set(null);\n this.panY.set((viewH - scaledHeight) / 2 - box.y * scale);\n }\n // The camera just moved deliberately; a stale anchor baseline would have the\n // next relayout \"correct\" a position this fit had already chosen.\n this.anchorPos = null;\n }\n\n /**\n * Restores the initial view — the fitted one under `autoFit`, otherwise the\n * default zoom and pan.\n */\n resetView(): void {\n if (this.effectiveFitMode() !== 'none') {\n this.fit();\n return;\n }\n this.zoom.set(100);\n this.panX.set(40);\n this.panY.set(40);\n }\n\n /** Expands a collapsed node. */\n expand(id: string): void {\n this.collapsedIds.update(set => {\n if (!set.has(id)) return set;\n const next = new Set(set);\n next.delete(id);\n return next;\n });\n }\n\n /** Collapses a node's sub-tree. */\n collapse(id: string): void {\n this.collapsedIds.update(set => {\n if (set.has(id)) return set;\n const next = new Set(set);\n next.add(id);\n return next;\n });\n }\n\n /** Expands every collapsed node. */\n expandAll(): void {\n this.collapsedIds.set(new Set());\n }\n\n /** Collapses every node that has children. */\n collapseAll(): void {\n const ids = new Set<string>();\n for (const [id, node] of this.allOriginalNodes()) {\n if (node.children?.length) ids.add(id);\n }\n this.collapsedIds.set(ids);\n }\n\n // ── Viewport measurement ───────────────────────────────────────────────────\n\n private canvasEl(): HTMLElement | null {\n return (\n this.canvasRef()?.nativeElement ??\n this.hostEl.nativeElement.querySelector('.dep-viewer__canvas')\n );\n }\n\n /**\n * Bounding box of everything drawn, in layout units.\n *\n * Edge labels stand in for the edges themselves. A parent→child edge stays\n * inside the node boxes anyway, and a bowed cross-reference puts its label just\n * outside the apex of the bow — the only part of it that reaches past them. The\n * label's own extent counts, as it hangs off its anchor point on one side.\n */\n private contentBox(): { x: number; y: number; width: number; height: number } {\n const { nodes, edges } = this.graph();\n if (!nodes.length) return { x: 0, y: 0, width: 0, height: 0 };\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const n of nodes) {\n minX = Math.min(minX, n.x);\n minY = Math.min(minY, n.y);\n maxX = Math.max(maxX, n.x + n.width);\n maxY = Math.max(maxY, n.y + n.height);\n }\n const measure = this.nodeMetrics().measure;\n const labelsShown = this.showEdgeLabels();\n for (const e of edges) {\n const w = labelsShown ? edgeLabelWidth(measure, e.label) : 0;\n const before = e.labelAnchor === 'start' ? 0 : e.labelAnchor === 'end' ? w : w / 2;\n minX = Math.min(minX, e.labelX - before);\n maxX = Math.max(maxX, e.labelX - before + w);\n minY = Math.min(minY, e.labelY - EDGE_LABEL_FONT_SIZE / 2);\n maxY = Math.max(maxY, e.labelY + EDGE_LABEL_FONT_SIZE / 2);\n }\n\n return {\n x: minX - FIT_PADDING,\n y: minY - FIT_PADDING,\n width: maxX - minX + FIT_PADDING * 2,\n height: maxY - minY + FIT_PADDING * 2,\n };\n }\n\n protected onMouseDown(event: MouseEvent): void {\n if (!this.interactive() || event.button !== 0) return;\n this.isPanning = true;\n this.lastMouseX = event.clientX;\n this.lastMouseY = event.clientY;\n }\n\n @HostListener('document:mousemove', ['$event'])\n protected onMouseMove(event: MouseEvent): void {\n if (!this.isPanning) return;\n this.panX.update(x => x + event.clientX - this.lastMouseX);\n this.panY.update(y => y + event.clientY - this.lastMouseY);\n this.lastMouseX = event.clientX;\n this.lastMouseY = event.clientY;\n }\n\n @HostListener('document:mouseup')\n protected onMouseUp(): void { this.isPanning = false; }\n\n protected onWheel(event: WheelEvent): void {\n // Return *before* preventDefault: a static viewer must not swallow the wheel\n // event, or the page can't be scrolled past it.\n if (!this.interactive()) return;\n event.preventDefault();\n this.zoom.update(z => event.deltaY < 0 ? Math.min(z + 10, 300) : Math.max(z - 10, 25));\n }\n\n // `type` is the category axis (Class/Table/Feature/…), `status` the semantic one\n // (error/warning/…). A resolved type colour wins for the fill; everything else\n // falls back to the status palette, so consumers that only use `status` are\n // unaffected.\n protected getNodeBg(node: LayoutNode): string {\n const typeColor = node.type ? this.typeColors()[node.type] : undefined;\n return typeColor ?? STATUS_COLORS[node.status].bg;\n }\n\n protected getNodeBorder(node: LayoutNode): string {\n const typeColor = node.type ? this.typeColors()[node.type] : undefined;\n return typeColor ?? STATUS_COLORS[node.status].border;\n }\n\n protected getNodeText(node: LayoutNode): string {\n const typeColor = node.type ? this.typeColors()[node.type] : undefined;\n return typeColor ? readableInk(typeColor) : STATUS_COLORS[node.status].text;\n }\n}\n","<!-- Toolbar. The zoom cluster is navigation, so it goes with `interactive`; the\n direction indicator is a read-out and stays. -->\n@if (showToolbar()) {\n <div class=\"dep-viewer__toolbar\">\n @if (interactive()) {\n <button class=\"dep-viewer__btn\" (click)=\"zoomIn()\" [attr.title]=\"zoomInLabel()\" [attr.aria-label]=\"zoomInLabel()\">+</button>\n <span class=\"dep-viewer__zoom\">{{ zoomLabel() }}%</span>\n <button class=\"dep-viewer__btn\" (click)=\"zoomOut()\" [attr.title]=\"zoomOutLabel()\" [attr.aria-label]=\"zoomOutLabel()\">−</button>\n <button class=\"dep-viewer__btn dep-viewer__btn--reset\" (click)=\"resetZoom()\" [attr.title]=\"resetZoomLabel()\" [attr.aria-label]=\"resetZoomLabel()\">⟲</button>\n }\n <span class=\"dep-viewer__direction-label\">{{ direction() === 'horizontal' ? '→' : '↓' }}</span>\n </div>\n}\n\n<!-- Canvas -->\n<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- background click clears the pointer selection; node selection is pointer-only in this component (known gap) -->\n<div\n #canvas\n class=\"dep-viewer__canvas\"\n [class.dep-viewer__canvas--static]=\"!interactive()\"\n [class.dep-viewer__canvas--sized]=\"contentHeight() !== null\"\n [style.height.px]=\"contentHeight()\"\n (mousedown)=\"onMouseDown($event)\"\n (wheel)=\"onWheel($event)\"\n (click)=\"deselectNode()\"\n>\n <svg\n [attr.width]=\"svgWidth()\"\n [attr.height]=\"svgHeight()\"\n [attr.viewBox]=\"viewBox()\"\n [style.transform]=\"transform()\"\n class=\"dep-viewer__svg\"\n >\n <!-- Arrow markers for cross-reference edges -->\n <defs>\n <marker id=\"arrow-default\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-neutral-400)\"/></marker>\n <marker id=\"arrow-blocks\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-error-default)\"/></marker>\n <marker id=\"arrow-references\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-info-default, #3b82f6)\"/></marker>\n <marker id=\"arrow-requires\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-warning-default)\"/></marker>\n <marker id=\"arrow-extends\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-primary-400)\"/></marker>\n <marker id=\"arrow-implements\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-success-default)\"/></marker>\n <marker id=\"arrow-uses\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-neutral-300)\"/></marker>\n <marker id=\"arrow-depends\" markerWidth=\"8\" markerHeight=\"6\" refX=\"8\" refY=\"3\" orient=\"auto\"><path d=\"M0,0 L8,3 L0,6 Z\" fill=\"var(--color-neutral-400)\"/></marker>\n </defs>\n\n <!-- Edges. Their labels are deliberately NOT drawn here — see below. -->\n @for (edge of graph().edges; track edge.id) {\n <path\n [attr.d]=\"edge.path\"\n [attr.stroke]=\"edge.color\"\n [attr.stroke-width]=\"edgeWidth()\"\n [attr.stroke-dasharray]=\"edge.dashed ? '6 3' : 'none'\"\n [attr.marker-end]=\"edge.arrow ? 'url(#arrow-' + edge.marker + ')' : ''\"\n fill=\"none\"\n class=\"dep-viewer__edge\"\n [class.dep-viewer__edge--cross-ref]=\"edge.isCrossRef\"\n />\n }\n\n <!-- Nodes -->\n @for (node of graph().nodes; track node.id) {\n <g\n class=\"dep-viewer__node\"\n [class.dep-viewer__node--selected]=\"selectedNodeId() === node.id\"\n (click)=\"selectNode(node.id, $event)\"\n (dblclick)=\"expandNode(node.id, $event)\"\n >\n <!-- A label the box couldn't hold in full is offered whole as a tooltip. -->\n @if (node.truncated) {\n <title>{{ node.label }}</title>\n }\n <!-- Opaque backdrop. The status fills are translucent tints (in the dark\n theme --color-success-50 & co. resolve to rgba(…, 0.18)), so without\n something solid beneath them the edges routed under a node show\n straight through it. This keeps the tint compositing against the\n viewer's own surface instead of against whatever passes behind. -->\n <rect\n [attr.x]=\"node.x\"\n [attr.y]=\"node.y\"\n [attr.width]=\"node.width\"\n [attr.height]=\"node.height\"\n rx=\"6\" ry=\"6\"\n class=\"dep-viewer__node-backdrop\"\n />\n <rect\n class=\"dep-viewer__node-fill\"\n [attr.x]=\"node.x\"\n [attr.y]=\"node.y\"\n [attr.width]=\"node.width\"\n [attr.height]=\"node.height\"\n rx=\"6\" ry=\"6\"\n [attr.fill]=\"getNodeBg(node)\"\n [attr.stroke]=\"selectedNodeId() === node.id ? 'var(--color-primary-500)' : getNodeBorder(node)\"\n stroke-width=\"1.5\"\n />\n <!-- One <tspan> per wrapped line, each restarting at the box's centre; the\n block of lines is centred on the box vertically. No whitespace between\n the spans — it would end up in the text. -->\n <text\n [attr.x]=\"node.x + node.width / 2\"\n [attr.y]=\"node.y + node.height / 2 + baselineShift - ((node.lines.length - 1) * lineHeight) / 2\"\n text-anchor=\"middle\"\n [attr.fill]=\"getNodeText(node)\"\n class=\"dep-viewer__node-label\"\n >@for (line of node.lines; track $index) {<tspan [attr.x]=\"node.x + node.width / 2\" [attr.dy]=\"$first ? 0 : lineHeight\">{{ line }}</tspan>}</text>\n\n <!-- \"+N\" marker: this node has more neighbours than are shown -->\n @if (node.moreCount) {\n <g class=\"dep-viewer__more\">\n <rect\n [attr.x]=\"node.x + node.width - 26\"\n [attr.y]=\"node.y - 8\"\n width=\"32\" height=\"16\" rx=\"8\" ry=\"8\"\n />\n <text\n [attr.x]=\"node.x + node.width - 10\"\n [attr.y]=\"node.y + 3\"\n text-anchor=\"middle\"\n >+{{ node.moreCount }}</text>\n </g>\n }\n\n <!-- Collapse/expand toggle -->\n @if (hasChildren(node.id)) {\n <g\n class=\"dep-viewer__toggle\"\n (click)=\"toggleCollapse(node.id, $event)\"\n >\n @if (direction() === 'horizontal') {\n <circle\n [attr.cx]=\"node.x + node.width + 10\"\n [attr.cy]=\"node.y + node.height / 2\"\n r=\"8\"\n fill=\"var(--color-neutral-100)\" stroke=\"var(--color-neutral-300)\" stroke-width=\"1\"\n />\n <text\n [attr.x]=\"node.x + node.width + 10\"\n [attr.y]=\"node.y + node.height / 2 + 4\"\n text-anchor=\"middle\"\n class=\"dep-viewer__toggle-text\"\n >{{ isCollapsed(node.id) ? '+' : '−' }}</text>\n } @else {\n <circle\n [attr.cx]=\"node.x + node.width / 2\"\n [attr.cy]=\"node.y + node.height + 10\"\n r=\"8\"\n fill=\"var(--color-neutral-100)\" stroke=\"var(--color-neutral-300)\" stroke-width=\"1\"\n />\n <text\n [attr.x]=\"node.x + node.width / 2\"\n [attr.y]=\"node.y + node.height + 14\"\n text-anchor=\"middle\"\n class=\"dep-viewer__toggle-text\"\n >{{ isCollapsed(node.id) ? '+' : '−' }}</text>\n }\n </g>\n }\n </g>\n }\n\n <!-- Edge labels last: SVG paints in document order, so anything drawn before\n the nodes is covered by them. A label sits at the midpoint of its edge,\n which frequently lands on a node — it has to come after. The halo (see\n the stylesheet) keeps it legible over whatever it lands on. -->\n @if (showEdgeLabels()) {\n @for (edge of graph().edges; track edge.id) {\n @if (edge.label) {\n <text\n [attr.x]=\"edge.labelX\"\n [attr.y]=\"edge.labelY\"\n class=\"dep-viewer__edge-label\"\n [attr.fill]=\"edge.color\"\n [attr.text-anchor]=\"edge.labelAnchor ?? 'middle'\"\n >{{ edge.label }}</text>\n }\n }\n }\n </svg>\n</div>\n\n<!-- Legend -->\n@if (legendItems().length || typeLegendItems().length) {\n <div class=\"dep-viewer__legend\">\n @for (item of legendItems(); track item.label) {\n <span class=\"dep-viewer__legend-item\">\n <svg width=\"24\" height=\"10\">\n <line\n x1=\"0\" y1=\"5\" x2=\"24\" y2=\"5\"\n [attr.stroke]=\"item.color\"\n stroke-width=\"2\"\n [attr.stroke-dasharray]=\"item.dashed ? '4 2' : 'none'\"\n />\n </svg>\n <span class=\"dep-viewer__legend-text\">{{ item.label }}</span>\n </span>\n }\n @for (item of typeLegendItems(); track item.type) {\n <span class=\"dep-viewer__legend-item\">\n <svg width=\"10\" height=\"10\">\n <rect width=\"10\" height=\"10\" rx=\"2\" ry=\"2\" [attr.fill]=\"item.color\" />\n </svg>\n <span class=\"dep-viewer__legend-text\">{{ item.type }}</span>\n </span>\n }\n </div>\n}\n\n<!-- Detail panel -->\n@if (selectedNode(); as node) {\n <div class=\"dep-viewer__detail\">\n <div class=\"dep-viewer__detail-header\">\n <span class=\"dep-viewer__detail-status dep-viewer__detail-status--{{ node.status }}\">●</span>\n <strong>{{ node.label }}</strong>\n @if (node.type) {\n <span class=\"dep-viewer__detail-type\">{{ node.type }}</span>\n }\n </div>\n @if (node.description) {\n <p class=\"dep-viewer__detail-desc\">{{ node.description }}</p>\n }\n <div class=\"dep-viewer__detail-meta\">\n <span>{{ depthLabel() }} {{ node.depth }}</span>\n <span>{{ childrenLabel() }} {{ node.outgoingCount }}</span>\n <span>{{ dependsOnLabel() }} {{ node.incomingCount }}</span>\n </div>\n @if (selectedDependsOn().length) {\n <div class=\"dep-viewer__detail-deps\">\n <strong>{{ dependenciesLabel() }}</strong>\n <ul>\n @for (dep of selectedDependsOn(); track dep.id) {\n <li>\n <span class=\"dep-viewer__dep-relation\">{{\n dep.relationLabel || getRelationLabel(dep.relation || 'depends')\n }}</span>\n → {{ dep.id }}\n </li>\n }\n </ul>\n </div>\n }\n </div>\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, computed, input, output } from "@angular/core";
|
|
3
|
+
var DescriptionListComponent = class DescriptionListComponent {
|
|
4
|
+
items = input.required(...ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []);
|
|
5
|
+
layout = input("rows", ...ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []);
|
|
6
|
+
leaders = input(false, ...ngDevMode ? [{ debugName: "leaders" }] : /* istanbul ignore next */ []);
|
|
7
|
+
size = input("md", ...ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []);
|
|
8
|
+
separator = input("line", ...ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []);
|
|
9
|
+
clickable = input(false, ...ngDevMode ? [{ debugName: "clickable" }] : /* istanbul ignore next */ []);
|
|
10
|
+
itemClick = output();
|
|
11
|
+
hostClasses = computed(() => [
|
|
12
|
+
"lc-dl",
|
|
13
|
+
`lc-dl--${this.layout()}`,
|
|
14
|
+
`lc-dl--${this.size()}`,
|
|
15
|
+
`lc-dl--sep-${this.separator()}`,
|
|
16
|
+
this.leaders() && this.layout() === "rows" ? "lc-dl--leaders" : ""
|
|
17
|
+
].filter(Boolean).join(" "), ...ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []);
|
|
18
|
+
valueClass(item) {
|
|
19
|
+
return `lc-dl__value lc-dl__value--${item.emphasis ?? "default"}`;
|
|
20
|
+
}
|
|
21
|
+
onRowKeydown(event, item) {
|
|
22
|
+
if (event.target !== event.currentTarget) return;
|
|
23
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
24
|
+
event.preventDefault();
|
|
25
|
+
this.itemClick.emit(item);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
29
|
+
minVersion: "12.0.0",
|
|
30
|
+
version: "22.2.2",
|
|
31
|
+
ngImport: i0,
|
|
32
|
+
type: DescriptionListComponent,
|
|
33
|
+
deps: [],
|
|
34
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
35
|
+
});
|
|
36
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
37
|
+
minVersion: "17.0.0",
|
|
38
|
+
version: "22.2.2",
|
|
39
|
+
type: DescriptionListComponent,
|
|
40
|
+
isStandalone: true,
|
|
41
|
+
selector: "lc-description-list",
|
|
42
|
+
inputs: {
|
|
43
|
+
items: {
|
|
44
|
+
classPropertyName: "items",
|
|
45
|
+
publicName: "items",
|
|
46
|
+
isSignal: true,
|
|
47
|
+
isRequired: true,
|
|
48
|
+
transformFunction: null
|
|
49
|
+
},
|
|
50
|
+
layout: {
|
|
51
|
+
classPropertyName: "layout",
|
|
52
|
+
publicName: "layout",
|
|
53
|
+
isSignal: true,
|
|
54
|
+
isRequired: false,
|
|
55
|
+
transformFunction: null
|
|
56
|
+
},
|
|
57
|
+
leaders: {
|
|
58
|
+
classPropertyName: "leaders",
|
|
59
|
+
publicName: "leaders",
|
|
60
|
+
isSignal: true,
|
|
61
|
+
isRequired: false,
|
|
62
|
+
transformFunction: null
|
|
63
|
+
},
|
|
64
|
+
size: {
|
|
65
|
+
classPropertyName: "size",
|
|
66
|
+
publicName: "size",
|
|
67
|
+
isSignal: true,
|
|
68
|
+
isRequired: false,
|
|
69
|
+
transformFunction: null
|
|
70
|
+
},
|
|
71
|
+
separator: {
|
|
72
|
+
classPropertyName: "separator",
|
|
73
|
+
publicName: "separator",
|
|
74
|
+
isSignal: true,
|
|
75
|
+
isRequired: false,
|
|
76
|
+
transformFunction: null
|
|
77
|
+
},
|
|
78
|
+
clickable: {
|
|
79
|
+
classPropertyName: "clickable",
|
|
80
|
+
publicName: "clickable",
|
|
81
|
+
isSignal: true,
|
|
82
|
+
isRequired: false,
|
|
83
|
+
transformFunction: null
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
outputs: { itemClick: "itemClick" },
|
|
87
|
+
ngImport: i0,
|
|
88
|
+
template: "<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term) {\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [attr.role]=\"clickable() ? 'button' : null\"\n [attr.tabindex]=\"clickable() ? 0 : null\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <dt class=\"lc-dl__term\">{{ item.term }}</dt>\n <span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>\n <dd [class]=\"valueClass(item)\">\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n </dd>\n </div>\n }\n</dl>\n",
|
|
89
|
+
styles: [":host{display:block}.lc-dl{margin:0}.lc-dl__row{display:flex;align-items:baseline;gap:var(--spacing-2)}.lc-dl__row--clickable{cursor:pointer;border-radius:var(--border-radius-sm)}.lc-dl__row--clickable:hover{background:var(--color-surface-hover)}.lc-dl__row--clickable:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-dl__term{flex-shrink:0;color:var(--color-text-secondary);font-weight:var(--font-weight-medium)}.lc-dl__leader{flex:1 1 auto;align-self:center;min-width:var(--spacing-4)}.lc-dl__value{flex:0 1 auto;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--color-text-primary);font-weight:var(--font-weight-medium);font-variant-numeric:tabular-nums}.lc-dl__value--muted{color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__value--strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__value--primary{color:var(--color-primary-500);font-weight:var(--font-weight-semibold)}.lc-dl__value--mono{font-family:var(--font-family-mono);font-variant-numeric:normal}.lc-dl__value-suffix{margin-left:.375rem;color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__link{color:var(--color-primary-500);text-decoration:none}.lc-dl__link:hover{text-decoration:underline}.lc-dl--rows .lc-dl__row{padding-block:var(--spacing-2)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom:1px solid var(--color-divider)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row:last-child,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row:last-child{border-bottom:0}.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom-style:dashed}.lc-dl--leaders .lc-dl__leader{border-bottom:1px dotted var(--color-border-strong);transform:translateY(-.15em)}.lc-dl--stacked .lc-dl__row{flex-direction:column;align-items:stretch;gap:var(--spacing-1);padding-block:var(--spacing-2)}.lc-dl--stacked .lc-dl__leader{display:none}.lc-dl--stacked .lc-dl__value{text-align:left}.lc-dl--sm{font-size:var(--font-size-xs)}.lc-dl--sm .lc-dl__row{padding-block:var(--spacing-1)}.lc-dl--md{font-size:var(--font-size-sm)}\n"],
|
|
90
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
94
|
+
minVersion: "12.0.0",
|
|
95
|
+
version: "22.2.2",
|
|
96
|
+
ngImport: i0,
|
|
97
|
+
type: DescriptionListComponent,
|
|
98
|
+
decorators: [{
|
|
99
|
+
type: Component,
|
|
100
|
+
args: [{
|
|
101
|
+
selector: "lc-description-list",
|
|
102
|
+
standalone: true,
|
|
103
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
104
|
+
template: "<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term) {\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [attr.role]=\"clickable() ? 'button' : null\"\n [attr.tabindex]=\"clickable() ? 0 : null\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <dt class=\"lc-dl__term\">{{ item.term }}</dt>\n <span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>\n <dd [class]=\"valueClass(item)\">\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n </dd>\n </div>\n }\n</dl>\n",
|
|
105
|
+
styles: [":host{display:block}.lc-dl{margin:0}.lc-dl__row{display:flex;align-items:baseline;gap:var(--spacing-2)}.lc-dl__row--clickable{cursor:pointer;border-radius:var(--border-radius-sm)}.lc-dl__row--clickable:hover{background:var(--color-surface-hover)}.lc-dl__row--clickable:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-dl__term{flex-shrink:0;color:var(--color-text-secondary);font-weight:var(--font-weight-medium)}.lc-dl__leader{flex:1 1 auto;align-self:center;min-width:var(--spacing-4)}.lc-dl__value{flex:0 1 auto;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--color-text-primary);font-weight:var(--font-weight-medium);font-variant-numeric:tabular-nums}.lc-dl__value--muted{color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__value--strong{color:var(--color-text-primary);font-weight:var(--font-weight-semibold)}.lc-dl__value--primary{color:var(--color-primary-500);font-weight:var(--font-weight-semibold)}.lc-dl__value--mono{font-family:var(--font-family-mono);font-variant-numeric:normal}.lc-dl__value-suffix{margin-left:.375rem;color:var(--color-text-tertiary);font-weight:var(--font-weight-normal)}.lc-dl__link{color:var(--color-primary-500);text-decoration:none}.lc-dl__link:hover{text-decoration:underline}.lc-dl--rows .lc-dl__row{padding-block:var(--spacing-2)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom:1px solid var(--color-divider)}.lc-dl--rows.lc-dl--sep-line .lc-dl__row:last-child,.lc-dl--rows.lc-dl--sep-divider .lc-dl__row:last-child{border-bottom:0}.lc-dl--rows.lc-dl--sep-divider .lc-dl__row{border-bottom-style:dashed}.lc-dl--leaders .lc-dl__leader{border-bottom:1px dotted var(--color-border-strong);transform:translateY(-.15em)}.lc-dl--stacked .lc-dl__row{flex-direction:column;align-items:stretch;gap:var(--spacing-1);padding-block:var(--spacing-2)}.lc-dl--stacked .lc-dl__leader{display:none}.lc-dl--stacked .lc-dl__value{text-align:left}.lc-dl--sm{font-size:var(--font-size-xs)}.lc-dl--sm .lc-dl__row{padding-block:var(--spacing-1)}.lc-dl--md{font-size:var(--font-size-sm)}\n"]
|
|
106
|
+
}]
|
|
107
|
+
}],
|
|
108
|
+
propDecorators: {
|
|
109
|
+
items: [{
|
|
110
|
+
type: i0.Input,
|
|
111
|
+
args: [{
|
|
112
|
+
isSignal: true,
|
|
113
|
+
alias: "items",
|
|
114
|
+
required: true
|
|
115
|
+
}]
|
|
116
|
+
}],
|
|
117
|
+
layout: [{
|
|
118
|
+
type: i0.Input,
|
|
119
|
+
args: [{
|
|
120
|
+
isSignal: true,
|
|
121
|
+
alias: "layout",
|
|
122
|
+
required: false
|
|
123
|
+
}]
|
|
124
|
+
}],
|
|
125
|
+
leaders: [{
|
|
126
|
+
type: i0.Input,
|
|
127
|
+
args: [{
|
|
128
|
+
isSignal: true,
|
|
129
|
+
alias: "leaders",
|
|
130
|
+
required: false
|
|
131
|
+
}]
|
|
132
|
+
}],
|
|
133
|
+
size: [{
|
|
134
|
+
type: i0.Input,
|
|
135
|
+
args: [{
|
|
136
|
+
isSignal: true,
|
|
137
|
+
alias: "size",
|
|
138
|
+
required: false
|
|
139
|
+
}]
|
|
140
|
+
}],
|
|
141
|
+
separator: [{
|
|
142
|
+
type: i0.Input,
|
|
143
|
+
args: [{
|
|
144
|
+
isSignal: true,
|
|
145
|
+
alias: "separator",
|
|
146
|
+
required: false
|
|
147
|
+
}]
|
|
148
|
+
}],
|
|
149
|
+
clickable: [{
|
|
150
|
+
type: i0.Input,
|
|
151
|
+
args: [{
|
|
152
|
+
isSignal: true,
|
|
153
|
+
alias: "clickable",
|
|
154
|
+
required: false
|
|
155
|
+
}]
|
|
156
|
+
}],
|
|
157
|
+
itemClick: [{
|
|
158
|
+
type: i0.Output,
|
|
159
|
+
args: ["itemClick"]
|
|
160
|
+
}]
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
export { DescriptionListComponent };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=lifecorner-angular-ui-kit-description-list.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-description-list.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/description-list/description-list.component.ts","../../../../libs/angular-ui-kit/src/lib/description-list/description-list.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n output,\n computed,\n} from '@angular/core';\n\n/**\n * Emphasis treatment applied to a row's value.\n * - `mono` renders the value in the monospace font (paths, URLs, hashes).\n */\nexport type DescriptionListEmphasis =\n | 'default'\n | 'strong'\n | 'muted'\n | 'primary'\n | 'mono';\n\nexport interface DescriptionListItem {\n /** Label shown on the term side of the row. */\n term: string;\n /** Value shown on the description side of the row. */\n value: string;\n /**\n * Optional qualifying suffix appended after the value on the same line and\n * rendered muted (e.g. a rating grade or \"last checked\" hint). Wraps if the\n * combined value + suffix exceed the available width.\n */\n valueSuffix?: string;\n /** Optional link — renders the value as an anchor. */\n href?: string;\n /**\n * Machine-readable date or time of the value (ISO 8601, e.g.\n * `2026-10-12T18:05:00+02:00`): renders the value inside\n * `<time datetime>`, so assistive tech and parsers get the exact moment\n * behind „heute 18:05“. Ignored together with `href`.\n */\n datetime?: string;\n /** Optional visual emphasis for the value. @default 'default' */\n emphasis?: DescriptionListEmphasis;\n /** Optional opaque payload echoed back in `itemClick`. */\n id?: string;\n}\n\nexport type DescriptionListLayout = 'rows' | 'stacked';\nexport type DescriptionListSize = 'sm' | 'md';\n\n/**\n * Per-row separator style (applies to the `rows` layout).\n * - `line` solid hairline under each row (default — unchanged look)\n * - `divider` subtle dashed line, for the dense card look\n * - `none` no row separator\n *\n * Orthogonal to `leaders`, which draws dotted leaders *between* term and value.\n */\nexport type DescriptionListSeparator = 'line' | 'divider' | 'none';\n\n/**\n * Description list for key/value metadata (a styled `<dl>`).\n *\n * Features:\n * - `rows` layout: term on the left, value on the right, with an optional\n * dotted leader line connecting them (the DS2.0 \"spec sheet\" look).\n * - `stacked` layout: term above value, for narrow columns.\n * - Per-row value emphasis and optional links.\n * - Semantic markup (`<dl>`/`<dt>`/`<dd>`) for accessibility; `clickable`\n * rows are focusable and keyboard-activatable.\n *\n * @example\n * ```html\n * <lc-description-list\n * [items]=\"[\n * { term: 'Repository', value: 'example/project', href: '#', emphasis: 'primary' },\n * { term: 'Access', value: 'Token stored · read only' },\n * { term: 'Status', value: 'Maintained', emphasis: 'strong' }\n * ]\"\n * [leaders]=\"true\" />\n * ```\n */\n@Component({\n selector: 'lc-description-list',\n standalone: true,\n templateUrl: './description-list.component.html',\n styleUrls: ['./description-list.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DescriptionListComponent {\n /** Rows to render. */\n readonly items = input.required<readonly DescriptionListItem[]>();\n\n /**\n * Row layout.\n * - rows: term left / value right (default)\n * - stacked: term above value\n * @default 'rows'\n */\n readonly layout = input<DescriptionListLayout>('rows');\n\n /**\n * Draw a dotted leader line between term and value. Only applies to the\n * `rows` layout.\n * @default false\n */\n readonly leaders = input<boolean>(false);\n\n /** Density of the rows. @default 'md' */\n readonly size = input<DescriptionListSize>('md');\n\n /**\n * Per-row separator style for the `rows` layout. Defaults to `line`, which is\n * identical to the previous behavior. Orthogonal to `leaders`.\n * @default 'line'\n */\n readonly separator = input<DescriptionListSeparator>('line');\n\n /**\n * Whether rows are interactive. When set, each row is focusable and\n * Enter / Space emit `itemClick`, so the click handler is reachable from\n * the keyboard. Set this whenever you handle `itemClick`.\n * @default false\n */\n readonly clickable = input<boolean>(false);\n\n /** Emitted when a row is clicked (or activated via keyboard when `clickable`). */\n readonly itemClick = output<DescriptionListItem>();\n\n protected readonly hostClasses = computed(() =>\n [\n 'lc-dl',\n `lc-dl--${this.layout()}`,\n `lc-dl--${this.size()}`,\n `lc-dl--sep-${this.separator()}`,\n this.leaders() && this.layout() === 'rows' ? 'lc-dl--leaders' : '',\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n protected valueClass(item: DescriptionListItem): string {\n return `lc-dl__value lc-dl__value--${item.emphasis ?? 'default'}`;\n }\n\n /** Keyboard activation of a clickable row (only from the row itself, not a nested link). */\n protected onRowKeydown(event: KeyboardEvent, item: DescriptionListItem): void {\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.itemClick.emit(item);\n }\n }\n}\n","<dl [class]=\"hostClasses()\">\n @for (item of items(); track item.term) {\n <div\n class=\"lc-dl__row\"\n [class.lc-dl__row--clickable]=\"clickable()\"\n [attr.role]=\"clickable() ? 'button' : null\"\n [attr.tabindex]=\"clickable() ? 0 : null\"\n (click)=\"itemClick.emit(item)\"\n (keydown)=\"onRowKeydown($event, item)\"\n >\n <dt class=\"lc-dl__term\">{{ item.term }}</dt>\n <span class=\"lc-dl__leader\" aria-hidden=\"true\"></span>\n <dd [class]=\"valueClass(item)\">\n @if (item.href) {\n <a class=\"lc-dl__link\" [href]=\"item.href\">{{ item.value }}</a>\n } @else if (item.datetime) {\n <time [attr.datetime]=\"item.datetime\">{{ item.value }}</time>\n } @else {\n {{ item.value }}\n }\n @if (item.valueSuffix) {\n <span class=\"lc-dl__value-suffix\">{{ item.valueSuffix }}</span>\n }\n </dd>\n </div>\n }\n</dl>\n"],"mappings":";;AAuFA,IAAa,2BAAb,MAAa,yBAAwB;CAE1B,QAAQ,MAAM,SAA0C,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAQxD,SAAS,MAA6B,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAO7C,UAAU,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAG/B,OAAO,MAA2B,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAOvC,YAAY,MAAgC,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAQnD,YAAY,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAGjC,YAAY,OAAM;CAER,cAAc,eAC/B;EACE;EACA,UAAU,KAAK,OAAM;EACrB,UAAU,KAAK,KAAI;EACnB,cAAc,KAAK,UAAS;EAC5B,KAAK,QAAO,KAAM,KAAK,OAAM,MAAO,SAAS,mBAAmB;CACjE,CAAA,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,GACZ,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAES,WAAW,MAAyB;EAC5C,OAAO,8BAA8B,KAAK,YAAY;CACxD;CAGU,aAAa,OAAsB,MAAyB;EACpE,IAAI,MAAM,WAAW,MAAM,eAAe;EAC1C,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;GAC9C,MAAM,eAAc;GACpB,KAAK,UAAU,KAAK,IAAI;EAC1B;CACF;CA/DW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAwB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAxB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAwB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA,EAAA,WAAA,YAAA;EAAA,UAAA;EAAA,UCvFrC;EA2BA,QAAA,CAAA,onEAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AD4Da,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAwB,YAAA,CAAA;EAPpC,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAqB,YACnB;GAAI,iBAGC,wBAAwB;GAAM,UAAA;GAAA,QAAA,CAAA,onEAAA;EAAA,CAAA"}
|