@nexterajs/ui 0.0.1 → 0.0.2
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/fesm2022/nexterajs-ui-core.mjs +189 -5
- package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-dropdowns.mjs +314 -50
- package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-file-uploader.mjs +6 -3
- package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-forms.mjs +729 -370
- package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-grid.mjs +1188 -208
- package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-intl.mjs +15 -5
- package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-notify.mjs +351 -0
- package/fesm2022/nexterajs-ui-notify.mjs.map +1 -0
- package/fesm2022/nexterajs-ui-pivot.mjs +146 -116
- package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-styling.mjs +568 -3
- package/fesm2022/nexterajs-ui-styling.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-tree-view.mjs +147 -18
- package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
- package/fesm2022/nexterajs-ui-validation.mjs +247 -92
- package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
- package/fesm2022/nexterajs-ui.mjs +1 -0
- package/fesm2022/nexterajs-ui.mjs.map +1 -1
- package/package.json +5 -1
- package/styles/_dropdown.scss +149 -0
- package/styles/_editor.scss +23 -4
- package/styles/_icons.scss +92 -0
- package/styles/_mixins.scss +104 -1
- package/styles/_scrollbar.scss +134 -0
- package/styles/_toast.scss +243 -0
- package/styles/_tokens.scss +48 -0
- package/styles/index.scss +4 -0
- package/types/nexterajs-ui-core.d.ts +142 -22
- package/types/nexterajs-ui-dropdowns.d.ts +145 -27
- package/types/nexterajs-ui-file-uploader.d.ts +4 -1
- package/types/nexterajs-ui-forms.d.ts +103 -19
- package/types/nexterajs-ui-grid.d.ts +445 -57
- package/types/nexterajs-ui-notify.d.ts +147 -0
- package/types/nexterajs-ui-pivot.d.ts +35 -22
- package/types/nexterajs-ui-styling.d.ts +163 -3
- package/types/nexterajs-ui-tree-view.d.ts +50 -1
- package/types/nexterajs-ui-validation.d.ts +94 -15
- package/types/nexterajs-ui.d.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nexterajs-ui-styling.mjs","sources":["../../../projects/nextera-ui/styling/src/lib/styling/nxe-overlay.ts","../../../projects/nextera-ui/styling/src/public-api.ts","../../../projects/nextera-ui/styling/src/nexterajs-ui-styling.ts"],"sourcesContent":["import { ConnectedOverlayPositionChange, FlexibleConnectedPositionStrategy, OverlayRef } from '@angular/cdk/overlay';\r\nimport { Subscription } from 'rxjs';\r\n\r\n/**\r\n * Marker class carried by every nxe surface — component hosts and CDK overlay panes alike.\r\n *\r\n * It is the nxe counterpart of DevExtreme's `.dx-widget` base and is what gives a surface its\r\n * font family/size/weight/line-height (see styling/_widget.scss).\r\n *\r\n * It matters most on overlays: a CDK pane is appended to `<body>`, so a portaled dropdown\r\n * inherits the page, not the editor that opened it. Without this class a panel silently falls\r\n * back to the host app's body font — which is how the select-box list ended up rendering 14px in\r\n * an app whose every other text surface is 12.24px.\r\n */\r\nexport const NXE_WIDGET_CLASS = 'nxe-widget';\r\n\r\n/** Set on the pane while the overlay is rendered ABOVE its origin instead of below. */\r\nexport const NXE_PANE_FLIPPED_CLASS = 'nxe-pane-flipped';\r\n\r\n/**\r\n * Build the `panelClass` for a library-created overlay, guaranteeing the widget contract.\r\n *\r\n * panelClass: nxePane('nxe-select-pane')\r\n * panelClass: nxePane('nxe-dropdownbox-pane', ...wrapperClass.split(/\\s+/))\r\n *\r\n * Blank/undefined entries are dropped so callers can splat user-supplied class strings directly.\r\n */\r\nexport function nxePane(...extra: (string | null | undefined)[]): string[] {\r\n return [NXE_WIDGET_CLASS, ...extra.filter((c): c is string => !!c && c.trim().length > 0)];\r\n}\r\n\r\n/**\r\n * Track whether a connected overlay has flipped above its origin, exposing it as\r\n * {@link NXE_PANE_FLIPPED_CLASS} on the pane.\r\n *\r\n * DevExtreme drew dropdowns flush against the editor — no border on the shared edge — and moved\r\n * that seam to the other side when the popup flipped up\r\n * (`.dx-overlay-content.dx-dropdowneditor-overlay-flipped { border-top-width:1px; border-bottom-width:0 }`).\r\n * CDK does not emit any equivalent hook, so panels need this to reproduce it.\r\n *\r\n * Returns the subscription; callers dispose it with the overlay.\r\n */\r\nexport function trackPaneFlip(overlayRef: OverlayRef): Subscription | undefined {\r\n const strategy = overlayRef.getConfig().positionStrategy;\r\n if (!(strategy instanceof FlexibleConnectedPositionStrategy)) {\r\n return undefined;\r\n }\r\n return strategy.positionChanges.subscribe((change: ConnectedOverlayPositionChange) => {\r\n // Flipped == the overlay's TOP edge is anchored to the origin's top, i.e. it grew upward.\r\n const flipped = change.connectionPair.overlayY === 'bottom';\r\n const pane = overlayRef.overlayElement;\r\n pane?.classList.toggle(NXE_PANE_FLIPPED_CLASS, flipped);\r\n });\r\n}\r\n","// @nexterajs/ui/styling — public API.\r\nexport * from './lib/styling/nxe-overlay';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAGA;;;;;;;;;;AAUG;AACI,MAAM,gBAAgB,GAAG;AAEhC;AACO,MAAM,sBAAsB,GAAG;AAEtC;;;;;;;AAOG;AACG,SAAU,OAAO,CAAC,GAAG,KAAoC,EAAA;IAC3D,OAAO,CAAC,gBAAgB,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC9F;AAEA;;;;;;;;;;AAUG;AACG,SAAU,aAAa,CAAC,UAAsB,EAAA;IAChD,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,gBAAgB;AACxD,IAAA,IAAI,EAAE,QAAQ,YAAY,iCAAiC,CAAC,EAAE;AAC1D,QAAA,OAAO,SAAS;IACpB;IACA,OAAO,QAAQ,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,MAAsC,KAAI;;QAEjF,MAAM,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC,QAAQ,KAAK,QAAQ;AAC3D,QAAA,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc;QACtC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,sBAAsB,EAAE,OAAO,CAAC;AAC3D,IAAA,CAAC,CAAC;AACN;;ACrDA;;ACAA;;AAEG;;"}
|
|
1
|
+
{"version":3,"file":"nexterajs-ui-styling.mjs","sources":["../../../projects/nextera-ui/styling/src/lib/styling/nxe-overlay.ts","../../../projects/nextera-ui/styling/src/lib/styling/nxe-dx-compat.ts","../../../projects/nextera-ui/styling/src/lib/styling/nxe-scrollbar.directive.ts","../../../projects/nextera-ui/styling/src/public-api.ts","../../../projects/nextera-ui/styling/src/nexterajs-ui-styling.ts"],"sourcesContent":["import { ConnectedOverlayPositionChange, FlexibleConnectedPositionStrategy, OverlayRef } from '@angular/cdk/overlay';\r\nimport { Subscription } from 'rxjs';\r\n\r\n/**\r\n * Marker class carried by every nxe surface — component hosts and CDK overlay panes alike.\r\n *\r\n * It is the nxe counterpart of DevExtreme's `.nxe-widget` base and is what gives a surface its\r\n * font family/size/weight/line-height (see styling/_widget.scss).\r\n *\r\n * It matters most on overlays: a CDK pane is appended to `<body>`, so a portaled dropdown\r\n * inherits the page, not the editor that opened it. Without this class a panel silently falls\r\n * back to the host app's body font — which is how the select-box list ended up rendering 14px in\r\n * an app whose every other text surface is 12.24px.\r\n */\r\nexport const NXE_WIDGET_CLASS = 'nxe-widget';\r\n\r\n/** Set on the pane while the overlay is rendered ABOVE its origin instead of below. */\r\nexport const NXE_PANE_FLIPPED_CLASS = 'nxe-pane-flipped';\r\n\r\n/**\r\n * Build the `panelClass` for a library-created overlay, guaranteeing the widget contract.\r\n *\r\n * panelClass: nxePane('nxe-select-pane')\r\n * panelClass: nxePane('nxe-dropdownbox-pane', ...wrapperClass.split(/\\s+/))\r\n *\r\n * Blank/undefined entries are dropped so callers can splat user-supplied class strings directly.\r\n */\r\nexport function nxePane(...extra: (string | null | undefined)[]): string[] {\r\n return [NXE_WIDGET_CLASS, ...extra.filter((c): c is string => !!c && c.trim().length > 0)];\r\n}\r\n\r\n/**\r\n * Track whether a connected overlay has flipped above its origin, exposing it as\r\n * {@link NXE_PANE_FLIPPED_CLASS} on the pane.\r\n *\r\n * DevExtreme drew dropdowns flush against the editor — no border on the shared edge — and moved\r\n * that seam to the other side when the popup flipped up\r\n * (`.nxe-overlay-content.nxe-dropdowneditor-overlay-flipped { border-top-width:1px; border-bottom-width:0 }`).\r\n * CDK does not emit any equivalent hook, so panels need this to reproduce it.\r\n *\r\n * Returns the subscription; callers dispose it with the overlay.\r\n */\r\nexport function trackPaneFlip(overlayRef: OverlayRef): Subscription | undefined {\r\n const strategy = overlayRef.getConfig().positionStrategy;\r\n if (!(strategy instanceof FlexibleConnectedPositionStrategy)) {\r\n return undefined;\r\n }\r\n return strategy.positionChanges.subscribe((change: ConnectedOverlayPositionChange) => {\r\n // Flipped == the overlay's TOP edge is anchored to the origin's top, i.e. it grew upward.\r\n const flipped = change.connectionPair.overlayY === 'bottom';\r\n const pane = overlayRef.overlayElement;\r\n pane?.classList.toggle(NXE_PANE_FLIPPED_CLASS, flipped);\r\n });\r\n}\r\n","import { DOCUMENT } from '@angular/common';\r\nimport {\r\n EnvironmentProviders,\r\n inject,\r\n Injectable,\r\n makeEnvironmentProviders,\r\n NgZone,\r\n provideEnvironmentInitializer,\r\n} from '@angular/core';\r\n\r\n/**\r\n * Migration aid: re-emit the old `dx-*` class names alongside the library's `nxe-*` ones.\r\n *\r\n * The library dropped the `dx-` prefix from its DOM. Applications that still style themselves\r\n * with rules like `.dx-datagrid .dx-row > td { padding: 4px }` would silently lose that styling,\r\n * and no stylesheet can fix it: CSS cannot alias a class, so a rule keyed on `.dx-datagrid` will\r\n * never match an element that only says `nxe-datagrid`. The class has to be back on the element.\r\n *\r\n * So this mirrors them at runtime. Provide it once and unmigrated stylesheets keep working\r\n * unchanged; provide nothing and the library costs nothing, which is the point of it being\r\n * opt-in. `tools/dx-compat/rewrite-styles.mjs` rewrites an application's own stylesheets when it\r\n * is ready to drop the flag — this is a bridge, not a destination.\r\n *\r\n * ```ts\r\n * bootstrapApplication(AppComponent, { providers: [provideNxeDxCompat()] });\r\n * ```\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class NxeDxCompatService {\r\n private readonly document = inject(DOCUMENT);\r\n private readonly ngZone = inject(NgZone);\r\n private observer?: MutationObserver;\r\n /** Our own writes retrigger the observer; this stops it chasing its own tail. */\r\n private mirroring = false;\r\n\r\n start(): void {\r\n if (this.observer || typeof MutationObserver === 'undefined' || !this.document.body) {\r\n return;\r\n }\r\n this.mirrorSubtree(this.document.body);\r\n // Outside Angular: this reacts to the DOM the framework just wrote, and must not itself\r\n // schedule change detection.\r\n this.ngZone.runOutsideAngular(() => {\r\n this.observer = new MutationObserver((records) => this.onMutations(records));\r\n this.observer.observe(this.document.body, {\r\n subtree: true,\r\n childList: true,\r\n attributes: true,\r\n attributeFilter: ['class'],\r\n });\r\n });\r\n }\r\n\r\n stop(): void {\r\n this.observer?.disconnect();\r\n this.observer = undefined;\r\n }\r\n\r\n private onMutations(records: MutationRecord[]): void {\r\n if (this.mirroring) {\r\n return;\r\n }\r\n this.mirroring = true;\r\n try {\r\n for (const record of records) {\r\n if (record.type === 'attributes' && record.target instanceof Element) {\r\n this.mirrorElement(record.target);\r\n }\r\n record.addedNodes.forEach((node) => {\r\n if (node instanceof Element) {\r\n this.mirrorSubtree(node);\r\n }\r\n });\r\n }\r\n } finally {\r\n this.mirroring = false;\r\n }\r\n }\r\n\r\n private mirrorSubtree(root: Element): void {\r\n const wasMirroring = this.mirroring;\r\n this.mirroring = true;\r\n try {\r\n this.mirrorElement(root);\r\n root.querySelectorAll('*').forEach((el) => this.mirrorElement(el));\r\n } finally {\r\n this.mirroring = wasMirroring;\r\n }\r\n }\r\n\r\n /** Keep `dx-x` present exactly while `nxe-x` is, so a removed state class is removed here too. */\r\n private mirrorElement(el: Element): void {\r\n const list = el.classList;\r\n const wanted = new Set<string>();\r\n for (const cls of Array.from(list)) {\r\n if (cls.startsWith('nxe-')) {\r\n wanted.add(`dx-${cls.slice(4)}`);\r\n }\r\n }\r\n if (!wanted.size && !Array.from(list).some((c) => c.startsWith('dx-'))) {\r\n return;\r\n }\r\n for (const cls of Array.from(list)) {\r\n if (cls.startsWith('dx-') && !wanted.has(cls)) {\r\n list.remove(cls);\r\n }\r\n }\r\n for (const cls of wanted) {\r\n if (!list.contains(cls)) {\r\n list.add(cls);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Opt into the `dx-*` compatibility classes. See {@link NxeDxCompatService} for why this is a\r\n * runtime mirror rather than a stylesheet.\r\n */\r\nexport function provideNxeDxCompat(): EnvironmentProviders {\r\n return makeEnvironmentProviders([\r\n provideEnvironmentInitializer(() => inject(NxeDxCompatService).start()),\r\n ]);\r\n}\r\n","import {\r\n DestroyRef,\r\n Directive,\r\n ElementRef,\r\n Input,\r\n NgZone,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n SimpleChanges,\r\n inject,\r\n} from '@angular/core';\r\n\r\n/** Where the scroll position sits on each axis: -1 at the start, 1 at the end, 0 in between. */\r\nexport interface NxeScrollbarPosition {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/** Scroll geometry of the host element. */\r\nexport interface NxeScrollbarGeometry {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n}\r\n\r\n/**\r\n * The options that map onto this implementation.\r\n *\r\n * `wheelPropagation` is accepted and ignored: it existed because the original took the wheel over\r\n * from the browser and had to decide when to hand it back. Scrolling here is native, so the\r\n * browser makes that decision itself — which is what the option was trying to restore.\r\n */\r\nexport interface NxeScrollbarOptions {\r\n suppressScrollX?: boolean;\r\n suppressScrollY?: boolean;\r\n wheelPropagation?: boolean;\r\n /** Rail is hidden below this content overflow, in px. Matches the original's default. */\r\n minScrollbarLength?: number;\r\n maxScrollbarLength?: number;\r\n}\r\n\r\nconst CLASS = {\r\n host: 'nxe-scrollbar',\r\n activeX: 'nxe-scrollbar--active-x',\r\n activeY: 'nxe-scrollbar--active-y',\r\n scrollingX: 'nxe-scrollbar--scrolling-x',\r\n scrollingY: 'nxe-scrollbar--scrolling-y',\r\n focus: 'nxe-scrollbar--focus',\r\n clicking: 'nxe-scrollbar--clicking',\r\n railX: 'nxe-scrollbar__rail-x',\r\n railY: 'nxe-scrollbar__rail-y',\r\n thumbX: 'nxe-scrollbar__thumb-x',\r\n thumbY: 'nxe-scrollbar__thumb-y',\r\n};\r\n\r\n/** How long the `--scrolling-*` class lingers after the last scroll event, as the original did. */\r\nconst SCROLLING_CLASS_LINGER_MS = 1000;\r\n\r\n/**\r\n * `[nxeScrollbar]` — a container with custom overlay scrollbars.\r\n *\r\n * This replaces a Perfect Scrollbar wrapper, and reproduces its DOM and its rendering exactly:\r\n * two absolutely-positioned rails, each holding a thumb, sized and offset from the host's own\r\n * scroll geometry. The stylesheet (`@nexterajs/ui/styles/_scrollbar.scss`) is a value-for-value\r\n * port, so applications that restyle the rails keep their appearance unchanged.\r\n *\r\n * **What is different, deliberately:** the original set `overflow: hidden` and reimplemented\r\n * wheel, touch, keyboard and momentum scrolling in JavaScript. Here the element scrolls natively\r\n * and only the native scrollbar is hidden — the rails are painted from the `scroll` event. That is\r\n * less code and better behaviour on touch and trackpads, and it is invisible: a hidden native\r\n * scrollbar takes no layout width, exactly like the overlay rails it replaces.\r\n *\r\n * The host carries `nxe-scrollbar` while enabled, which is the marker callers branch on.\r\n */\r\n@Directive({\r\n selector: '[nxeScrollbar]',\r\n exportAs: 'nxeScrollbar',\r\n})\r\nexport class NxeScrollbarDirective implements OnInit, OnChanges, OnDestroy {\r\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly zone = inject(NgZone);\r\n private readonly destroyRef = inject(DestroyRef);\r\n\r\n @Input({ transform: coerceEnabled }) nxeScrollbar = true;\r\n @Input() nxeScrollbarOptions: NxeScrollbarOptions | null = null;\r\n\r\n private options: NxeScrollbarOptions = {};\r\n private animation: number | null = null;\r\n\r\n private railX?: HTMLElement;\r\n private railY?: HTMLElement;\r\n private thumbX?: HTMLElement;\r\n private thumbY?: HTMLElement;\r\n\r\n private resizeObserver?: ResizeObserver;\r\n private mutationObserver?: MutationObserver;\r\n private scrollingXTimer: ReturnType<typeof setTimeout> | null = null;\r\n private scrollingYTimer: ReturnType<typeof setTimeout> | null = null;\r\n private teardown: (() => void)[] = [];\r\n private initialised = false;\r\n\r\n get element(): HTMLElement {\r\n return this.elementRef.nativeElement;\r\n }\r\n\r\n ngOnInit(): void {\r\n if (this.nxeScrollbar) this.init();\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('nxeScrollbarOptions' in changes) {\r\n // A spread, not a deep merge: every option on this interface is a flat scalar.\r\n this.options = { ...this.options, ...(changes['nxeScrollbarOptions'].currentValue ?? {}) };\r\n if (this.initialised) this.update();\r\n }\r\n\r\n if ('nxeScrollbar' in changes && !changes['nxeScrollbar'].firstChange) {\r\n if (this.nxeScrollbar) this.init();\r\n else this.dispose();\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.dispose();\r\n }\r\n\r\n isEnabled(): boolean {\r\n return this.nxeScrollbar;\r\n }\r\n\r\n /**\r\n * Recompute rail and thumb geometry. Call after changing content the directive cannot observe.\r\n *\r\n * This reproduces the original's arithmetic exactly, down to how it rounds — the requirement was\r\n * no visual difference, and each of these is worth a pixel:\r\n * - the container is measured from `getBoundingClientRect()` rounded, not from `clientHeight`;\r\n * - sizes and offsets are **truncated** (the original ran them through `parseInt`), not rounded;\r\n * - `scrollTop` is floored before it is used;\r\n * - the thumb offset is clamped so it cannot overhang the end of the rail.\r\n */\r\n update(): void {\r\n if (!this.initialised) return;\r\n\r\n const el = this.element;\r\n const rect = el.getBoundingClientRect();\r\n const containerWidth = Math.round(rect.width);\r\n const containerHeight = Math.round(rect.height);\r\n const contentWidth = el.scrollWidth;\r\n const contentHeight = el.scrollHeight;\r\n const roundedScrollTop = Math.floor(el.scrollTop);\r\n\r\n const activeX = this.options.suppressScrollX !== true && containerWidth < contentWidth;\r\n const activeY = this.options.suppressScrollY !== true && containerHeight < contentHeight;\r\n\r\n el.classList.toggle(CLASS.activeX, activeX);\r\n el.classList.toggle(CLASS.activeY, activeY);\r\n\r\n if (activeX && this.railX && this.thumbX) {\r\n const railWidth = containerWidth;\r\n const thumbWidth = this.clampThumb(trunc((railWidth * containerWidth) / contentWidth));\r\n let left = trunc((el.scrollLeft * (railWidth - thumbWidth)) / (contentWidth - containerWidth));\r\n if (left >= railWidth - thumbWidth) left = railWidth - thumbWidth;\r\n\r\n // The rails follow the scroll offset so they stay pinned to the visible edge: the host is\r\n // the scrolling box, so an absolutely-positioned child would otherwise travel with content.\r\n this.railX.style.left = `${el.scrollLeft}px`;\r\n this.railX.style.bottom = `${-roundedScrollTop}px`;\r\n this.railX.style.width = `${railWidth}px`;\r\n this.thumbX.style.left = `${left}px`;\r\n this.thumbX.style.width = `${thumbWidth}px`;\r\n }\r\n\r\n if (activeY && this.railY && this.thumbY) {\r\n const railHeight = containerHeight;\r\n const thumbHeight = this.clampThumb(trunc((railHeight * containerHeight) / contentHeight));\r\n let top = trunc(\r\n (roundedScrollTop * (railHeight - thumbHeight)) / (contentHeight - containerHeight),\r\n );\r\n if (top >= railHeight - thumbHeight) top = railHeight - thumbHeight;\r\n\r\n this.railY.style.top = `${roundedScrollTop}px`;\r\n this.railY.style.right = `${-el.scrollLeft}px`;\r\n this.railY.style.height = `${railHeight}px`;\r\n this.thumbY.style.top = `${top}px`;\r\n this.thumbY.style.height = `${thumbHeight}px`;\r\n }\r\n }\r\n\r\n /** Kept for parity with the wrapper this replaces; teardown also happens in ngOnDestroy. */\r\n destroy(): void {\r\n this.dispose();\r\n }\r\n\r\n isScrollableX(): boolean {\r\n return this.element.classList.contains(CLASS.activeX);\r\n }\r\n\r\n isScrollableY(): boolean {\r\n return this.element.classList.contains(CLASS.activeY);\r\n }\r\n\r\n geometry(prefix: 'scroll' | 'client' | 'offset' = 'scroll'): NxeScrollbarGeometry {\r\n const el = this.element as unknown as Record<string, number>;\r\n return {\r\n x: el[`${prefix}Left`],\r\n y: el[`${prefix}Top`],\r\n w: el[`${prefix}Width`],\r\n h: el[`${prefix}Height`],\r\n };\r\n }\r\n\r\n /** -1 at the start of an axis, 1 at its end, 0 anywhere between. */\r\n position(absolute = false): NxeScrollbarPosition {\r\n const el = this.element;\r\n if (absolute) return { x: el.scrollLeft, y: el.scrollTop };\r\n\r\n return {\r\n x: reach(el.scrollLeft, el.scrollWidth - el.clientWidth),\r\n y: reach(el.scrollTop, el.scrollHeight - el.clientHeight),\r\n };\r\n }\r\n\r\n scrollTo(x: number, y?: number, speed?: number): void {\r\n if (y == null && speed == null) {\r\n this.animateScrolling('scrollTop', x, speed);\r\n return;\r\n }\r\n if (x != null) this.animateScrolling('scrollLeft', x, speed);\r\n if (y != null) this.animateScrolling('scrollTop', y, speed);\r\n }\r\n\r\n scrollToX(x: number, speed?: number): void {\r\n this.animateScrolling('scrollLeft', x, speed);\r\n }\r\n\r\n scrollToY(y: number, speed?: number): void {\r\n this.animateScrolling('scrollTop', y, speed);\r\n }\r\n\r\n scrollToTop(offset = 0, speed?: number): void {\r\n this.animateScrolling('scrollTop', offset, speed);\r\n }\r\n\r\n scrollToBottom(offset = 0, speed?: number): void {\r\n const top = this.element.scrollHeight - this.element.clientHeight;\r\n this.animateScrolling('scrollTop', top - offset, speed);\r\n }\r\n\r\n scrollToLeft(offset = 0, speed?: number): void {\r\n this.animateScrolling('scrollLeft', offset, speed);\r\n }\r\n\r\n scrollToRight(offset = 0, speed?: number): void {\r\n const left = this.element.scrollWidth - this.element.clientWidth;\r\n this.animateScrolling('scrollLeft', left - offset, speed);\r\n }\r\n\r\n /**\r\n * Bring the first descendant matching `selector` into view.\r\n *\r\n * `ignoreVisible` skips the scroll when the target already sits inside the viewport less the\r\n * offset, so an item that is merely low on screen is not yanked to the top on every change.\r\n */\r\n scrollToElement(selector: string, offset = 0, ignoreVisible = false, speed?: number): void {\r\n const target = this.element.querySelector(selector);\r\n if (!target) return;\r\n\r\n const targetRect = target.getBoundingClientRect();\r\n const hostRect = this.element.getBoundingClientRect();\r\n\r\n if (this.isScrollableX()) {\r\n const visible = ignoreVisible && targetRect.right <= hostRect.right - Math.abs(offset);\r\n if (!visible) {\r\n const position = targetRect.left - hostRect.left + this.element.scrollLeft;\r\n this.animateScrolling('scrollLeft', position + offset, speed);\r\n }\r\n }\r\n\r\n if (this.isScrollableY()) {\r\n const visible = ignoreVisible && targetRect.bottom <= hostRect.bottom - Math.abs(offset);\r\n if (!visible) {\r\n const position = targetRect.top - hostRect.top + this.element.scrollTop;\r\n this.animateScrolling('scrollTop', position + offset, speed);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Move one axis to `value`, easing over `speed` ms when one is given.\r\n *\r\n * The easing bails as soon as the position stops matching what it last wrote, so a user who\r\n * grabs the wheel mid-flight takes over instead of fighting the animation.\r\n */\r\n animateScrolling(axis: 'scrollTop' | 'scrollLeft', value: number, speed?: number): void {\r\n this.cancelAnimation();\r\n\r\n const el = this.element;\r\n if (!speed || typeof window === 'undefined') {\r\n el[axis] = value;\r\n this.update();\r\n return;\r\n }\r\n if (value === el[axis]) return;\r\n\r\n let scrollCount = 0;\r\n let previousTimestamp = performance.now();\r\n let previousValue = el[axis];\r\n const half = (previousValue - value) / 2;\r\n\r\n const step = (timestamp: number): void => {\r\n scrollCount += Math.PI / (speed / (timestamp - previousTimestamp));\r\n\r\n if (el[axis] !== previousValue) {\r\n this.animation = null;\r\n return;\r\n }\r\n\r\n if (scrollCount >= Math.PI) {\r\n el[axis] = value;\r\n this.animation = null;\r\n this.update();\r\n return;\r\n }\r\n\r\n el[axis] = Math.round(value + half + half * Math.cos(scrollCount));\r\n previousValue = el[axis];\r\n previousTimestamp = timestamp;\r\n this.animation = window.requestAnimationFrame(step);\r\n };\r\n\r\n this.animation = window.requestAnimationFrame(step);\r\n }\r\n\r\n // ---------------------------------------------------------------------------------------------\r\n\r\n private init(): void {\r\n if (this.initialised) return;\r\n const el = this.element;\r\n el.classList.add(CLASS.host);\r\n\r\n this.railX = this.buildRail(CLASS.railX, CLASS.thumbX);\r\n this.thumbX = this.railX.firstElementChild as HTMLElement;\r\n this.railY = this.buildRail(CLASS.railY, CLASS.thumbY);\r\n this.thumbY = this.railY.firstElementChild as HTMLElement;\r\n el.appendChild(this.railX);\r\n el.appendChild(this.railY);\r\n\r\n // Scroll and resize fire far too often to be worth a change-detection pass each: nothing here\r\n // touches component state, only inline styles on elements the directive owns.\r\n this.zone.runOutsideAngular(() => {\r\n this.on(el, 'scroll', () => this.onScroll());\r\n this.on(el, 'focus', () => el.classList.add(CLASS.focus), true);\r\n this.on(el, 'blur', () => el.classList.remove(CLASS.focus), true);\r\n\r\n this.bindThumbDrag(this.thumbX!, this.railX!, 'x');\r\n this.bindThumbDrag(this.thumbY!, this.railY!, 'y');\r\n\r\n if (typeof ResizeObserver !== 'undefined') {\r\n this.resizeObserver = new ResizeObserver(() => this.update());\r\n this.resizeObserver.observe(el);\r\n // Observing the first child catches content growing taller inside a fixed-height host,\r\n // which resizing the host alone never reports.\r\n if (el.firstElementChild) this.resizeObserver.observe(el.firstElementChild);\r\n }\r\n\r\n if (typeof MutationObserver !== 'undefined') {\r\n this.mutationObserver = new MutationObserver(() => this.update());\r\n this.mutationObserver.observe(el, { childList: true, subtree: true, characterData: true });\r\n }\r\n });\r\n\r\n this.initialised = true;\r\n this.update();\r\n this.destroyRef.onDestroy(() => this.dispose());\r\n }\r\n\r\n private buildRail(railClass: string, thumbClass: string): HTMLElement {\r\n const rail = document.createElement('div');\r\n rail.className = railClass;\r\n const thumb = document.createElement('div');\r\n thumb.className = thumbClass;\r\n rail.appendChild(thumb);\r\n return rail;\r\n }\r\n\r\n private onScroll(): void {\r\n this.update();\r\n\r\n const el = this.element;\r\n if (this.isScrollableX()) {\r\n el.classList.add(CLASS.scrollingX);\r\n if (this.scrollingXTimer) clearTimeout(this.scrollingXTimer);\r\n this.scrollingXTimer = setTimeout(\r\n () => el.classList.remove(CLASS.scrollingX),\r\n SCROLLING_CLASS_LINGER_MS,\r\n );\r\n }\r\n if (this.isScrollableY()) {\r\n el.classList.add(CLASS.scrollingY);\r\n if (this.scrollingYTimer) clearTimeout(this.scrollingYTimer);\r\n this.scrollingYTimer = setTimeout(\r\n () => el.classList.remove(CLASS.scrollingY),\r\n SCROLLING_CLASS_LINGER_MS,\r\n );\r\n }\r\n }\r\n\r\n private bindThumbDrag(thumb: HTMLElement, rail: HTMLElement, axis: 'x' | 'y'): void {\r\n this.on(thumb, 'pointerdown', (event) => {\r\n const pointerEvent = event as PointerEvent;\r\n pointerEvent.stopPropagation();\r\n pointerEvent.preventDefault();\r\n\r\n const el = this.element;\r\n rail.classList.add(CLASS.clicking);\r\n thumb.setPointerCapture(pointerEvent.pointerId);\r\n\r\n const startPointer = axis === 'x' ? pointerEvent.clientX : pointerEvent.clientY;\r\n const startScroll = axis === 'x' ? el.scrollLeft : el.scrollTop;\r\n const railSize = axis === 'x' ? el.clientWidth : el.clientHeight;\r\n const thumbSize = axis === 'x' ? thumb.offsetWidth : thumb.offsetHeight;\r\n const travel =\r\n axis === 'x' ? el.scrollWidth - el.clientWidth : el.scrollHeight - el.clientHeight;\r\n\r\n const onMove = (moveEvent: PointerEvent): void => {\r\n const delta = (axis === 'x' ? moveEvent.clientX : moveEvent.clientY) - startPointer;\r\n const trackable = railSize - thumbSize;\r\n if (trackable <= 0) return;\r\n const next = startScroll + (delta * travel) / trackable;\r\n if (axis === 'x') el.scrollLeft = next;\r\n else el.scrollTop = next;\r\n };\r\n\r\n const onUp = (upEvent: PointerEvent): void => {\r\n rail.classList.remove(CLASS.clicking);\r\n thumb.releasePointerCapture(upEvent.pointerId);\r\n thumb.removeEventListener('pointermove', onMove);\r\n thumb.removeEventListener('pointerup', onUp);\r\n thumb.removeEventListener('pointercancel', onUp);\r\n };\r\n\r\n thumb.addEventListener('pointermove', onMove);\r\n thumb.addEventListener('pointerup', onUp);\r\n thumb.addEventListener('pointercancel', onUp);\r\n });\r\n\r\n // A click on the rail itself jumps the thumb to that point, as the original did.\r\n this.on(rail, 'pointerdown', (event) => {\r\n const pointerEvent = event as PointerEvent;\r\n if (pointerEvent.target !== rail) return;\r\n\r\n const el = this.element;\r\n const railRect = rail.getBoundingClientRect();\r\n const thumbSize = axis === 'x' ? thumb.offsetWidth : thumb.offsetHeight;\r\n const offset =\r\n axis === 'x'\r\n ? pointerEvent.clientX - railRect.left\r\n : pointerEvent.clientY - railRect.top;\r\n const railSize = axis === 'x' ? railRect.width : railRect.height;\r\n const travel =\r\n axis === 'x' ? el.scrollWidth - el.clientWidth : el.scrollHeight - el.clientHeight;\r\n const trackable = railSize - thumbSize;\r\n if (trackable <= 0) return;\r\n\r\n const next = ((offset - thumbSize / 2) * travel) / trackable;\r\n if (axis === 'x') el.scrollLeft = next;\r\n else el.scrollTop = next;\r\n });\r\n }\r\n\r\n /** Only the configured bounds, and only when set — the same shape the original's clamp had. */\r\n private clampThumb(size: number): number {\r\n const min = this.options.minScrollbarLength;\r\n const max = this.options.maxScrollbarLength;\r\n let result = size;\r\n if (min) result = Math.max(result, min);\r\n if (max) result = Math.min(result, max);\r\n return result;\r\n }\r\n\r\n private on(\r\n target: EventTarget,\r\n type: string,\r\n handler: (event: Event) => void,\r\n capture = false,\r\n ): void {\r\n target.addEventListener(type, handler, capture);\r\n this.teardown.push(() => target.removeEventListener(type, handler, capture));\r\n }\r\n\r\n private dispose(): void {\r\n if (!this.initialised) return;\r\n this.initialised = false;\r\n\r\n this.cancelAnimation();\r\n for (const off of this.teardown) off();\r\n this.teardown = [];\r\n\r\n this.resizeObserver?.disconnect();\r\n this.mutationObserver?.disconnect();\r\n this.resizeObserver = undefined;\r\n this.mutationObserver = undefined;\r\n\r\n if (this.scrollingXTimer) clearTimeout(this.scrollingXTimer);\r\n if (this.scrollingYTimer) clearTimeout(this.scrollingYTimer);\r\n\r\n this.railX?.remove();\r\n this.railY?.remove();\r\n this.railX = this.railY = this.thumbX = this.thumbY = undefined;\r\n\r\n this.element.classList.remove(\r\n CLASS.host,\r\n CLASS.activeX,\r\n CLASS.activeY,\r\n CLASS.scrollingX,\r\n CLASS.scrollingY,\r\n CLASS.focus,\r\n );\r\n }\r\n\r\n private cancelAnimation(): void {\r\n if (this.animation !== null) {\r\n window.cancelAnimationFrame(this.animation);\r\n this.animation = null;\r\n }\r\n }\r\n}\r\n\r\n/** `<div nxeScrollbar>` sets the empty string; treat that as on, like any boolean attribute. */\r\nfunction coerceEnabled(value: boolean | string | null | undefined): boolean {\r\n return value !== false && value !== 'false' && value != null;\r\n}\r\n\r\n/** `parseInt`-style truncation toward zero, with NaN folded to 0 — what the original used. */\r\nfunction trunc(value: number): number {\r\n return Math.trunc(value) || 0;\r\n}\r\n\r\nfunction reach(offset: number, max: number): number {\r\n if (max <= 0) return 0;\r\n if (offset <= 0) return -1;\r\n if (offset >= max) return 1;\r\n return 0;\r\n}\r\n","// @nexterajs/ui/styling — public API.\r\nexport * from './lib/styling/nxe-overlay';\r\nexport * from './lib/styling/nxe-dx-compat';\r\nexport * from './lib/styling/nxe-scrollbar.directive';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, signal, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, input, output, signal, viewChild, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `nxe-tree-view` — drop-in replacement for DevExtreme `dx-tree-view`.
|
|
@@ -12,6 +12,7 @@ import { input, output, signal, computed, ViewEncapsulation, ChangeDetectionStra
|
|
|
12
12
|
* keeps reading `event.itemData.url/urlParams/objectName`.
|
|
13
13
|
*/
|
|
14
14
|
class NxeTreeViewComponent {
|
|
15
|
+
elementRef = inject(ElementRef);
|
|
15
16
|
dataSource = input([], /* @ts-ignore */
|
|
16
17
|
...(ngDevMode ? [{ debugName: "dataSource" }] : /* istanbul ignore next */ []));
|
|
17
18
|
/** Accepted for parity; this component always assembles a tree from the flat list. */
|
|
@@ -48,6 +49,8 @@ class NxeTreeViewComponent {
|
|
|
48
49
|
...(ngDevMode ? [{ debugName: "selectedKey" }] : /* istanbul ignore next */ []));
|
|
49
50
|
searchText = signal('', /* @ts-ignore */
|
|
50
51
|
...(ngDevMode ? [{ debugName: "searchText" }] : /* istanbul ignore next */ []));
|
|
52
|
+
searchInput = viewChild('searchInput', /* @ts-ignore */
|
|
53
|
+
...(ngDevMode ? [{ debugName: "searchInput" }] : /* istanbul ignore next */ []));
|
|
51
54
|
/** DevExtreme `.instance` facade — `expandAll()` is the only method used. */
|
|
52
55
|
get instance() {
|
|
53
56
|
return this;
|
|
@@ -97,8 +100,17 @@ class NxeTreeViewComponent {
|
|
|
97
100
|
return roots;
|
|
98
101
|
}, /* @ts-ignore */
|
|
99
102
|
...(ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []));
|
|
100
|
-
/**
|
|
101
|
-
|
|
103
|
+
/**
|
|
104
|
+
* The visible nodes, each with its position among its siblings.
|
|
105
|
+
*
|
|
106
|
+
* The tree renders as one flat `<ul>` with indentation rather than nested lists, so a screen
|
|
107
|
+
* reader cannot infer depth or sibling counts from the DOM. `aria-level`, `aria-setsize` and
|
|
108
|
+
* `aria-posinset` are what carry that, which makes them required for a flattened tree rather
|
|
109
|
+
* than optional extras. They are computed during the walk, where the sibling array is already
|
|
110
|
+
* in hand — reconstructing them from the flat list afterwards is possible but much harder to
|
|
111
|
+
* read for no gain.
|
|
112
|
+
*/
|
|
113
|
+
visibleRows = computed(() => {
|
|
102
114
|
const out = [];
|
|
103
115
|
const query = this.searchText().trim().toLowerCase();
|
|
104
116
|
if (query) {
|
|
@@ -113,30 +125,35 @@ class NxeTreeViewComponent {
|
|
|
113
125
|
return t.includes(query);
|
|
114
126
|
}
|
|
115
127
|
};
|
|
128
|
+
const matches = [];
|
|
116
129
|
const walkAll = (nodes) => {
|
|
117
130
|
for (const n of nodes) {
|
|
118
131
|
if (match(n.text)) {
|
|
119
|
-
|
|
132
|
+
matches.push(n);
|
|
120
133
|
}
|
|
121
134
|
walkAll(n.children);
|
|
122
135
|
}
|
|
123
136
|
};
|
|
124
137
|
walkAll(this.tree());
|
|
138
|
+
// Search flattens the hierarchy, so the results ARE the set: reporting each match
|
|
139
|
+
// with its original sibling count would describe a structure that is not on screen.
|
|
140
|
+
return matches.map((node, i) => ({ node, posInSet: i + 1, setSize: matches.length }));
|
|
125
141
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
walk(n.children);
|
|
133
|
-
}
|
|
142
|
+
const expanded = this.expanded();
|
|
143
|
+
const walk = (nodes) => {
|
|
144
|
+
nodes.forEach((n, i) => {
|
|
145
|
+
out.push({ node: n, posInSet: i + 1, setSize: nodes.length });
|
|
146
|
+
if (n.hasChildren && expanded.has(n.key)) {
|
|
147
|
+
walk(n.children);
|
|
134
148
|
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
walk(this.tree());
|
|
138
152
|
return out;
|
|
139
153
|
}, /* @ts-ignore */
|
|
154
|
+
...(ngDevMode ? [{ debugName: "visibleRows" }] : /* istanbul ignore next */ []));
|
|
155
|
+
/** Flattened list of currently-visible nodes (respects expand state + search). */
|
|
156
|
+
visibleNodes = computed(() => this.visibleRows().map((row) => row.node), /* @ts-ignore */
|
|
140
157
|
...(ngDevMode ? [{ debugName: "visibleNodes" }] : /* istanbul ignore next */ []));
|
|
141
158
|
expandAll() {
|
|
142
159
|
const keys = new Set();
|
|
@@ -180,8 +197,120 @@ class NxeTreeViewComponent {
|
|
|
180
197
|
onSearch(event) {
|
|
181
198
|
this.searchText.set(event.target.value);
|
|
182
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* The search box's clear button. dx empties the value and leaves the caret in the box (its
|
|
202
|
+
* clear button swallows the mouse-down so the input never loses focus); refocusing here covers
|
|
203
|
+
* the case where focus had already left the input.
|
|
204
|
+
*/
|
|
205
|
+
clearSearch() {
|
|
206
|
+
this.searchText.set('');
|
|
207
|
+
this.searchInput()?.nativeElement.focus();
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* The node holding the tree's single tab stop.
|
|
211
|
+
*
|
|
212
|
+
* A tree is one stop in the tab order, not one per node, so a roving tabindex is part of the
|
|
213
|
+
* role rather than an extra: `role="tree"` on a list nothing can focus would announce a
|
|
214
|
+
* structure a keyboard user cannot reach.
|
|
215
|
+
*/
|
|
216
|
+
focusedKey = signal(null, /* @ts-ignore */
|
|
217
|
+
...(ngDevMode ? [{ debugName: "focusedKey" }] : /* istanbul ignore next */ []));
|
|
218
|
+
isTabStop(node, index) {
|
|
219
|
+
const focused = this.focusedKey();
|
|
220
|
+
return focused === null ? index === 0 : focused === node.key;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The node that holds DOM focus right now, or `null` while focus is anywhere else.
|
|
224
|
+
*
|
|
225
|
+
* Deliberately not `focusedKey`: that is the roving tab stop and has to outlive a blur, so Tab
|
|
226
|
+
* comes back to the same node. dx drops `dx-state-focused` the moment focus leaves the node,
|
|
227
|
+
* and the focused look goes with it — the row colour, and the toggle, which follows the row's
|
|
228
|
+
* colour only while focused (`color: unset`, dx.light.css). Keyed off focusin/focusout so the
|
|
229
|
+
* class means exactly what it says.
|
|
230
|
+
*/
|
|
231
|
+
focusedNode = signal(null, /* @ts-ignore */
|
|
232
|
+
...(ngDevMode ? [{ debugName: "focusedNode" }] : /* istanbul ignore next */ []));
|
|
233
|
+
isFocused(node) {
|
|
234
|
+
const focused = this.focusedNode();
|
|
235
|
+
return focused !== null && focused.key === node.key;
|
|
236
|
+
}
|
|
237
|
+
onNodeFocus(node) {
|
|
238
|
+
this.focusedKey.set(node.key);
|
|
239
|
+
this.focusedNode.set(node);
|
|
240
|
+
}
|
|
241
|
+
onNodeBlur(node) {
|
|
242
|
+
// focusout on the old node fires before focusin on the new one, so this only ever clears
|
|
243
|
+
// the node that is actually losing focus.
|
|
244
|
+
if (this.isFocused(node)) {
|
|
245
|
+
this.focusedNode.set(null);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** Arrow-key navigation, per the WAI-ARIA tree pattern. */
|
|
249
|
+
onKeydown(event) {
|
|
250
|
+
const rows = this.visibleRows();
|
|
251
|
+
if (!rows.length) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const current = Math.max(0, rows.findIndex((r) => r.node.key === this.focusedKey()));
|
|
255
|
+
const node = rows[current].node;
|
|
256
|
+
const expanded = this.isExpanded(node);
|
|
257
|
+
const focusAt = (index) => {
|
|
258
|
+
const target = rows[Math.max(0, Math.min(index, rows.length - 1))];
|
|
259
|
+
this.focusedKey.set(target.node.key);
|
|
260
|
+
const items = this.elementRef.nativeElement.querySelectorAll('[role="treeitem"]');
|
|
261
|
+
items[rows.indexOf(target)]?.focus();
|
|
262
|
+
};
|
|
263
|
+
switch (event.key) {
|
|
264
|
+
case 'ArrowDown':
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
focusAt(current + 1);
|
|
267
|
+
break;
|
|
268
|
+
case 'ArrowUp':
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
focusAt(current - 1);
|
|
271
|
+
break;
|
|
272
|
+
case 'ArrowRight':
|
|
273
|
+
event.preventDefault();
|
|
274
|
+
if (node.hasChildren && !expanded) {
|
|
275
|
+
this.toggle(node, event);
|
|
276
|
+
}
|
|
277
|
+
else if (node.hasChildren) {
|
|
278
|
+
focusAt(current + 1);
|
|
279
|
+
}
|
|
280
|
+
break;
|
|
281
|
+
case 'ArrowLeft':
|
|
282
|
+
event.preventDefault();
|
|
283
|
+
if (node.hasChildren && expanded) {
|
|
284
|
+
this.toggle(node, event);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// to the parent: the nearest earlier row one level up
|
|
288
|
+
for (let i = current - 1; i >= 0; i--) {
|
|
289
|
+
if (rows[i].node.level < node.level) {
|
|
290
|
+
focusAt(i);
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
case 'Home':
|
|
297
|
+
event.preventDefault();
|
|
298
|
+
focusAt(0);
|
|
299
|
+
break;
|
|
300
|
+
case 'End':
|
|
301
|
+
event.preventDefault();
|
|
302
|
+
focusAt(rows.length - 1);
|
|
303
|
+
break;
|
|
304
|
+
case 'Enter':
|
|
305
|
+
case ' ':
|
|
306
|
+
event.preventDefault();
|
|
307
|
+
this.onNodeClick(node, event);
|
|
308
|
+
break;
|
|
309
|
+
default:
|
|
310
|
+
}
|
|
311
|
+
}
|
|
183
312
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTreeViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
184
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeTreeViewComponent, isStandalone: true, selector: "nxe-tree-view", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, dataStructure: { classPropertyName: "dataStructure", publicName: "dataStructure", isSignal: true, isRequired: false, transformFunction: null }, keyExpr: { classPropertyName: "keyExpr", publicName: "keyExpr", isSignal: true, isRequired: false, transformFunction: null }, displayExpr: { classPropertyName: "displayExpr", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, parentIdExpr: { classPropertyName: "parentIdExpr", publicName: "parentIdExpr", isSignal: true, isRequired: false, transformFunction: null }, rootValue: { classPropertyName: "rootValue", publicName: "rootValue", isSignal: true, isRequired: false, transformFunction: null }, expandedExpr: { classPropertyName: "expandedExpr", publicName: "expandedExpr", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, searchEnabled: { classPropertyName: "searchEnabled", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, searchMode: { classPropertyName: "searchMode", publicName: "searchMode", isSignal: true, isRequired: false, transformFunction: null }, useNativeScrolling: { classPropertyName: "useNativeScrolling", publicName: "useNativeScrolling", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick" }, host: { properties: { "class.nxe-treeview-with-search": "searchEnabled()", "style.width": "widthStyle()" }, classAttribute: "nxe-widget nxe-tree-view" }, ngImport: i0, template: "@if (searchEnabled()) {\r\n <div class=\"nxe-treeview-search\">\r\n <input\r\n class=\"nxe-treeview-search-input\"\r\n type=\"text\"\r\n placeholder=\"Search\"\r\n [value]=\"searchText()\"\r\n (input)=\"onSearch($event)\" />\r\n </div>\r\n}\r\n\r\n<ul class=\"nxe-treeview-node-container nxe-treeview-node-container-opened\">\r\n @for (node of visibleNodes(); track node.key) {\r\n <li\r\n class=\"nxe-treeview-node\"\r\n [class.nxe-treeview-node-is-leaf]=\"!node.hasChildren\"\r\n [class.nxe-state-selected]=\"selectionMode() !== 'none' && node.key === selectedKey()\"\r\n [style.padding-left.px]=\"node.level * 15\">\r\n <div class=\"nxe-treeview-item\" (click)=\"onNodeClick(node, $event)\">\r\n @if (node.hasChildren) {\r\n <span\r\n class=\"nxe-treeview-toggle-item-visibility\"\r\n [class.nxe-treeview-toggle-item-visibility-opened]=\"isExpanded(node)\"\r\n (click)=\"toggle(node, $event)\">\r\n </span>\r\n } @else {\r\n <span class=\"nxe-treeview-expander-icon-stub\"></span>\r\n }\r\n <div class=\"nxe-treeview-item-content\">\r\n <span>{{ node.text }}</span>\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n</ul>\r\n", styles: ["nxe-tree-view{display:block;height:100%;overflow-y:auto;border:1px solid #ddd;border-radius:4px}nxe-tree-view .nxe-treeview-search{padding:4px 6px}nxe-tree-view .nxe-treeview-search .nxe-treeview-search-input{width:100%;box-sizing:border-box;padding:5px 8px;border:1px solid #ddd;border-radius:4px;font-size:1em;outline:none}nxe-tree-view .nxe-treeview-search .nxe-treeview-search-input:focus{border-color:#30374c}nxe-tree-view .nxe-treeview-node-container{list-style:none;margin:0;padding:0}nxe-tree-view .nxe-treeview-node{list-style:none}nxe-tree-view .nxe-treeview-item{display:flex;align-items:center;gap:4px;height:32px;box-sizing:border-box;padding:5px 8px 5px 10px;cursor:pointer;border-radius:4px}nxe-tree-view .nxe-treeview-item:hover{background-color:#0000000a}nxe-tree-view .nxe-treeview-node.nxe-state-selected>.nxe-treeview-item{background-color:#30374c1f;font-weight:500}nxe-tree-view .nxe-treeview-item-content{flex:1 1 auto;min-width:0}nxe-tree-view .nxe-treeview-item-content span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tree-view .nxe-treeview-expander-icon-stub{display:inline-block;width:16px;height:16px;flex:0 0 16px}nxe-tree-view .nxe-treeview-toggle-item-visibility{display:inline-block;position:relative;width:16px;height:16px;flex:0 0 16px;cursor:pointer}nxe-tree-view .nxe-treeview-toggle-item-visibility:before{content:\"\";position:absolute;left:5px;top:4px;width:0;height:0;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:5px solid #444;transition:transform .15s ease;transform-origin:40% 50%}nxe-tree-view .nxe-treeview-toggle-item-visibility.nxe-treeview-toggle-item-visibility-opened:before{transform:rotate(90deg)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
313
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.5", type: NxeTreeViewComponent, isStandalone: true, selector: "nxe-tree-view", inputs: { dataSource: { classPropertyName: "dataSource", publicName: "dataSource", isSignal: true, isRequired: false, transformFunction: null }, dataStructure: { classPropertyName: "dataStructure", publicName: "dataStructure", isSignal: true, isRequired: false, transformFunction: null }, keyExpr: { classPropertyName: "keyExpr", publicName: "keyExpr", isSignal: true, isRequired: false, transformFunction: null }, displayExpr: { classPropertyName: "displayExpr", publicName: "displayExpr", isSignal: true, isRequired: false, transformFunction: null }, parentIdExpr: { classPropertyName: "parentIdExpr", publicName: "parentIdExpr", isSignal: true, isRequired: false, transformFunction: null }, rootValue: { classPropertyName: "rootValue", publicName: "rootValue", isSignal: true, isRequired: false, transformFunction: null }, expandedExpr: { classPropertyName: "expandedExpr", publicName: "expandedExpr", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectByClick: { classPropertyName: "selectByClick", publicName: "selectByClick", isSignal: true, isRequired: false, transformFunction: null }, searchEnabled: { classPropertyName: "searchEnabled", publicName: "searchEnabled", isSignal: true, isRequired: false, transformFunction: null }, searchMode: { classPropertyName: "searchMode", publicName: "searchMode", isSignal: true, isRequired: false, transformFunction: null }, useNativeScrolling: { classPropertyName: "useNativeScrolling", publicName: "useNativeScrolling", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick" }, host: { properties: { "class.nxe-treeview-with-search": "searchEnabled()", "style.width": "widthStyle()" }, classAttribute: "nxe-widget nxe-tree-view" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (searchEnabled()) {\r\n <!-- dx builds this as a dxTextBox in mode 'search' (ui.search_box_mixin.js), which forces\r\n showClearButton: a magnifier in a 34px slot inside the left border, and a clear button in\r\n a 34px area inside the right border that only exists while there is text to clear. Both\r\n glyphs are drawn here from primitives; the DXIcons font is not used. -->\r\n <div class=\"nxe-treeview-search\">\r\n <!-- The magnifier both search boxes share (dx draws them with one rule,\r\n .dx-searchbox .dx-icon-search): a r4.75 ring and a 45deg handle, 1.9px strokes. Keep\r\n it identical to the header filter's (nxe-header-filter-panel.component.html). -->\r\n <svg class=\"nxe-treeview-search-icon\" viewBox=\"0 0 34 34\" aria-hidden=\"true\" focusable=\"false\">\r\n <circle cx=\"15\" cy=\"15\" r=\"4.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" />\r\n <path d=\"M18.5 18.5 23.5 23.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" />\r\n </svg>\r\n <input\r\n #searchInput\r\n class=\"nxe-treeview-search-input\"\r\n type=\"text\"\r\n placeholder=\"Search\"\r\n aria-label=\"Search\"\r\n [value]=\"searchText()\"\r\n (input)=\"onSearch($event)\" />\r\n @if (searchText()) {\r\n <button\r\n class=\"nxe-treeview-search-clear\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n aria-label=\"Clear\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"clearSearch()\">\r\n <!-- The editors' clear glyph: a 16px disc with a 2px x cut out, two 2px bars\r\n each running corner to corner of the 8px square centred on the disc, drawn as\r\n a plus and turned 45deg. -->\r\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\" focusable=\"false\">\r\n <path\r\n fill=\"currentColor\"\r\n fill-rule=\"evenodd\"\r\n transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n}\r\n\r\n<ul\r\n class=\"nxe-treeview-node-container nxe-treeview-node-container-opened\"\r\n role=\"tree\"\r\n [attr.aria-multiselectable]=\"selectionMode() === 'multiple' ? true : null\"\r\n (keydown)=\"onKeydown($event)\">\r\n @for (row of visibleRows(); track row.node.key; let i = $index) {\r\n @let node = row.node;\r\n <li\r\n class=\"nxe-treeview-node nxe-treeview-item-without-checkbox\"\r\n role=\"treeitem\"\r\n [attr.aria-level]=\"node.level + 1\"\r\n [attr.aria-posinset]=\"row.posInSet\"\r\n [attr.aria-setsize]=\"row.setSize\"\r\n [attr.aria-expanded]=\"node.hasChildren ? isExpanded(node) : null\"\r\n [attr.aria-selected]=\"selectionMode() === 'none' ? null : node.key === selectedKey()\"\r\n [attr.tabindex]=\"isTabStop(node, i) ? 0 : -1\"\r\n (focusin)=\"onNodeFocus(node)\"\r\n (focusout)=\"onNodeBlur(node)\"\r\n [class.nxe-treeview-node-is-leaf]=\"!node.hasChildren\"\r\n [class.nxe-state-selected]=\"selectionMode() !== 'none' && node.key === selectedKey()\"\r\n [class.nxe-state-focused]=\"isFocused(node)\"\r\n [style.padding-left.px]=\"node.level * 15\">\r\n <div class=\"nxe-treeview-item\" (click)=\"onNodeClick(node, $event)\">\r\n @if (node.hasChildren) {\r\n <span\r\n class=\"nxe-treeview-toggle-item-visibility\"\r\n [class.nxe-treeview-toggle-item-visibility-opened]=\"isExpanded(node)\"\r\n (click)=\"toggle(node, $event)\">\r\n </span>\r\n } @else {\r\n <span class=\"nxe-treeview-expander-icon-stub\"></span>\r\n }\r\n <div class=\"nxe-treeview-item-content\">\r\n <span>{{ node.text }}</span>\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n</ul>\r\n", styles: ["nxe-tree-view{display:flex;flex-direction:column;height:100%}nxe-tree-view.nxe-treeview-border-visible{border:1px solid var(--nxe-ui-border, #ddd)}nxe-tree-view.nxe-treeview-border-visible>.nxe-treeview-node-container{padding:1px 1px 1px 7px}nxe-tree-view .nxe-treeview-search{position:relative;display:flex;flex:0 0 auto;box-sizing:border-box;margin:0 0 5px;padding:0;border:1px solid var(--nxe-ui-border, #ddd);border-radius:var(--nxe-ui-radius, 4px);background:var(--nxe-ui-surface, #fff)}nxe-tree-view .nxe-treeview-search:hover{border-color:#337ab766}nxe-tree-view .nxe-treeview-search:focus-within{border-color:var(--nxe-ui-accent, #337ab7)}nxe-tree-view .nxe-treeview-search-input{-webkit-appearance:none;appearance:none;flex:1 1 auto;min-width:0;width:100%;box-sizing:border-box;min-height:34px;margin:0;padding:7px 9px 8px;padding-inline-start:34px;border:0;border-radius:var(--nxe-ui-radius, 4px);outline:0;background:transparent;color:var(--nxe-ui-text, #333);font-size:1em}nxe-tree-view .nxe-treeview-search-input::placeholder{color:var(--nxe-ui-text-muted, #999);opacity:1}nxe-tree-view .nxe-treeview-search-icon{position:absolute;top:50%;left:0;display:block;width:34px;height:34px;margin-top:-17px;color:var(--nxe-ui-text-muted, #999);pointer-events:none}nxe-tree-view .nxe-treeview-search-clear{position:relative;display:flex;align-items:center;justify-content:center;flex:0 0 34px;width:34px;min-width:34px;margin:0;padding:0;border:0;background:transparent;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-tree-view .nxe-treeview-search-clear svg{display:block;width:18px;height:18px}nxe-tree-view .nxe-treeview-node-container{flex:1 1 auto;min-height:0;overflow-x:hidden;overflow-y:auto;list-style:none;margin:0;padding:0}nxe-tree-view .nxe-treeview-node{list-style:none;-webkit-user-select:none;user-select:none}nxe-tree-view .nxe-treeview-node:focus{outline:0}nxe-tree-view .nxe-treeview-item{display:flex;align-items:center;gap:8px;box-sizing:border-box;margin:0;padding:5px 10px;cursor:pointer}nxe-tree-view .nxe-treeview-item-content{flex:1 1 auto;min-width:0}nxe-tree-view .nxe-treeview-item-content span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tree-view .nxe-treeview-expander-icon-stub{display:flex;flex:0 0 22px;width:22px;height:22px}nxe-tree-view .nxe-treeview-toggle-item-visibility{display:flex;align-items:center;justify-content:center;flex:0 0 22px;width:22px;height:22px;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-tree-view .nxe-treeview-toggle-item-visibility:before{content:\"\";width:0;height:0;border-style:solid;border-width:4px 0 4px 4px;border-color:transparent transparent transparent currentColor}nxe-tree-view .nxe-treeview-toggle-item-visibility.nxe-treeview-toggle-item-visibility-opened:before{content:\"\";border-width:4px 4px 0;border-color:currentColor transparent transparent}nxe-tree-view .nxe-treeview-node.nxe-state-focused>.nxe-treeview-item .nxe-treeview-toggle-item-visibility{color:inherit}:where(nxe-tree-view) .nxe-treeview-item{color:var(--nxe-ui-text, #333)}:where(nxe-tree-view .nxe-treeview-item):hover{background-color:var(--nxe-ui-hover-bg, rgba(0, 0, 0, .04))}:where(nxe-tree-view .nxe-treeview-node.nxe-state-selected)>.nxe-treeview-item{background-color:var(--nxe-ui-selected-bg, rgba(0, 0, 0, .1));color:var(--nxe-ui-text, #333);border-radius:0}:where(nxe-tree-view .nxe-treeview-node.nxe-state-focused)>.nxe-treeview-item{background-color:var(--nxe-ui-accent, #337ab7);color:var(--nxe-ui-accent-contrast, #fff);border-radius:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
185
314
|
}
|
|
186
315
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImport: i0, type: NxeTreeViewComponent, decorators: [{
|
|
187
316
|
type: Component,
|
|
@@ -189,8 +318,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.5", ngImpor
|
|
|
189
318
|
class: 'nxe-widget nxe-tree-view',
|
|
190
319
|
'[class.nxe-treeview-with-search]': 'searchEnabled()',
|
|
191
320
|
'[style.width]': 'widthStyle()',
|
|
192
|
-
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if (searchEnabled()) {\r\n <div class=\"nxe-treeview-search\">\r\n <input\r\n class=\"nxe-treeview-search-input\"\r\n type=\"text\"\r\n placeholder=\"Search\"\r\n [value]=\"searchText()\"\r\n (input)=\"onSearch($event)\" />\r\n </div>\r\n}\r\n\r\n<ul
|
|
193
|
-
}], propDecorators: { dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], dataStructure: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataStructure", required: false }] }], keyExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyExpr", required: false }] }], displayExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], parentIdExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentIdExpr", required: false }] }], rootValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootValue", required: false }] }], expandedExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedExpr", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selectByClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectByClick", required: false }] }], searchEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], searchMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchMode", required: false }] }], useNativeScrolling: [{ type: i0.Input, args: [{ isSignal: true, alias: "useNativeScrolling", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], onItemClick: [{ type: i0.Output, args: ["onItemClick"] }] } });
|
|
321
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if (searchEnabled()) {\r\n <!-- dx builds this as a dxTextBox in mode 'search' (ui.search_box_mixin.js), which forces\r\n showClearButton: a magnifier in a 34px slot inside the left border, and a clear button in\r\n a 34px area inside the right border that only exists while there is text to clear. Both\r\n glyphs are drawn here from primitives; the DXIcons font is not used. -->\r\n <div class=\"nxe-treeview-search\">\r\n <!-- The magnifier both search boxes share (dx draws them with one rule,\r\n .dx-searchbox .dx-icon-search): a r4.75 ring and a 45deg handle, 1.9px strokes. Keep\r\n it identical to the header filter's (nxe-header-filter-panel.component.html). -->\r\n <svg class=\"nxe-treeview-search-icon\" viewBox=\"0 0 34 34\" aria-hidden=\"true\" focusable=\"false\">\r\n <circle cx=\"15\" cy=\"15\" r=\"4.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" />\r\n <path d=\"M18.5 18.5 23.5 23.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" />\r\n </svg>\r\n <input\r\n #searchInput\r\n class=\"nxe-treeview-search-input\"\r\n type=\"text\"\r\n placeholder=\"Search\"\r\n aria-label=\"Search\"\r\n [value]=\"searchText()\"\r\n (input)=\"onSearch($event)\" />\r\n @if (searchText()) {\r\n <button\r\n class=\"nxe-treeview-search-clear\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n aria-label=\"Clear\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"clearSearch()\">\r\n <!-- The editors' clear glyph: a 16px disc with a 2px x cut out, two 2px bars\r\n each running corner to corner of the 8px square centred on the disc, drawn as\r\n a plus and turned 45deg. -->\r\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\" focusable=\"false\">\r\n <path\r\n fill=\"currentColor\"\r\n fill-rule=\"evenodd\"\r\n transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n}\r\n\r\n<ul\r\n class=\"nxe-treeview-node-container nxe-treeview-node-container-opened\"\r\n role=\"tree\"\r\n [attr.aria-multiselectable]=\"selectionMode() === 'multiple' ? true : null\"\r\n (keydown)=\"onKeydown($event)\">\r\n @for (row of visibleRows(); track row.node.key; let i = $index) {\r\n @let node = row.node;\r\n <li\r\n class=\"nxe-treeview-node nxe-treeview-item-without-checkbox\"\r\n role=\"treeitem\"\r\n [attr.aria-level]=\"node.level + 1\"\r\n [attr.aria-posinset]=\"row.posInSet\"\r\n [attr.aria-setsize]=\"row.setSize\"\r\n [attr.aria-expanded]=\"node.hasChildren ? isExpanded(node) : null\"\r\n [attr.aria-selected]=\"selectionMode() === 'none' ? null : node.key === selectedKey()\"\r\n [attr.tabindex]=\"isTabStop(node, i) ? 0 : -1\"\r\n (focusin)=\"onNodeFocus(node)\"\r\n (focusout)=\"onNodeBlur(node)\"\r\n [class.nxe-treeview-node-is-leaf]=\"!node.hasChildren\"\r\n [class.nxe-state-selected]=\"selectionMode() !== 'none' && node.key === selectedKey()\"\r\n [class.nxe-state-focused]=\"isFocused(node)\"\r\n [style.padding-left.px]=\"node.level * 15\">\r\n <div class=\"nxe-treeview-item\" (click)=\"onNodeClick(node, $event)\">\r\n @if (node.hasChildren) {\r\n <span\r\n class=\"nxe-treeview-toggle-item-visibility\"\r\n [class.nxe-treeview-toggle-item-visibility-opened]=\"isExpanded(node)\"\r\n (click)=\"toggle(node, $event)\">\r\n </span>\r\n } @else {\r\n <span class=\"nxe-treeview-expander-icon-stub\"></span>\r\n }\r\n <div class=\"nxe-treeview-item-content\">\r\n <span>{{ node.text }}</span>\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n</ul>\r\n", styles: ["nxe-tree-view{display:flex;flex-direction:column;height:100%}nxe-tree-view.nxe-treeview-border-visible{border:1px solid var(--nxe-ui-border, #ddd)}nxe-tree-view.nxe-treeview-border-visible>.nxe-treeview-node-container{padding:1px 1px 1px 7px}nxe-tree-view .nxe-treeview-search{position:relative;display:flex;flex:0 0 auto;box-sizing:border-box;margin:0 0 5px;padding:0;border:1px solid var(--nxe-ui-border, #ddd);border-radius:var(--nxe-ui-radius, 4px);background:var(--nxe-ui-surface, #fff)}nxe-tree-view .nxe-treeview-search:hover{border-color:#337ab766}nxe-tree-view .nxe-treeview-search:focus-within{border-color:var(--nxe-ui-accent, #337ab7)}nxe-tree-view .nxe-treeview-search-input{-webkit-appearance:none;appearance:none;flex:1 1 auto;min-width:0;width:100%;box-sizing:border-box;min-height:34px;margin:0;padding:7px 9px 8px;padding-inline-start:34px;border:0;border-radius:var(--nxe-ui-radius, 4px);outline:0;background:transparent;color:var(--nxe-ui-text, #333);font-size:1em}nxe-tree-view .nxe-treeview-search-input::placeholder{color:var(--nxe-ui-text-muted, #999);opacity:1}nxe-tree-view .nxe-treeview-search-icon{position:absolute;top:50%;left:0;display:block;width:34px;height:34px;margin-top:-17px;color:var(--nxe-ui-text-muted, #999);pointer-events:none}nxe-tree-view .nxe-treeview-search-clear{position:relative;display:flex;align-items:center;justify-content:center;flex:0 0 34px;width:34px;min-width:34px;margin:0;padding:0;border:0;background:transparent;color:var(--nxe-ui-text-muted, #999);cursor:pointer}nxe-tree-view .nxe-treeview-search-clear svg{display:block;width:18px;height:18px}nxe-tree-view .nxe-treeview-node-container{flex:1 1 auto;min-height:0;overflow-x:hidden;overflow-y:auto;list-style:none;margin:0;padding:0}nxe-tree-view .nxe-treeview-node{list-style:none;-webkit-user-select:none;user-select:none}nxe-tree-view .nxe-treeview-node:focus{outline:0}nxe-tree-view .nxe-treeview-item{display:flex;align-items:center;gap:8px;box-sizing:border-box;margin:0;padding:5px 10px;cursor:pointer}nxe-tree-view .nxe-treeview-item-content{flex:1 1 auto;min-width:0}nxe-tree-view .nxe-treeview-item-content span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nxe-tree-view .nxe-treeview-expander-icon-stub{display:flex;flex:0 0 22px;width:22px;height:22px}nxe-tree-view .nxe-treeview-toggle-item-visibility{display:flex;align-items:center;justify-content:center;flex:0 0 22px;width:22px;height:22px;color:var(--nxe-ui-text, #333);cursor:pointer}nxe-tree-view .nxe-treeview-toggle-item-visibility:before{content:\"\";width:0;height:0;border-style:solid;border-width:4px 0 4px 4px;border-color:transparent transparent transparent currentColor}nxe-tree-view .nxe-treeview-toggle-item-visibility.nxe-treeview-toggle-item-visibility-opened:before{content:\"\";border-width:4px 4px 0;border-color:currentColor transparent transparent}nxe-tree-view .nxe-treeview-node.nxe-state-focused>.nxe-treeview-item .nxe-treeview-toggle-item-visibility{color:inherit}:where(nxe-tree-view) .nxe-treeview-item{color:var(--nxe-ui-text, #333)}:where(nxe-tree-view .nxe-treeview-item):hover{background-color:var(--nxe-ui-hover-bg, rgba(0, 0, 0, .04))}:where(nxe-tree-view .nxe-treeview-node.nxe-state-selected)>.nxe-treeview-item{background-color:var(--nxe-ui-selected-bg, rgba(0, 0, 0, .1));color:var(--nxe-ui-text, #333);border-radius:0}:where(nxe-tree-view .nxe-treeview-node.nxe-state-focused)>.nxe-treeview-item{background-color:var(--nxe-ui-accent, #337ab7);color:var(--nxe-ui-accent-contrast, #fff);border-radius:0}\n"] }]
|
|
322
|
+
}], propDecorators: { dataSource: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataSource", required: false }] }], dataStructure: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataStructure", required: false }] }], keyExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyExpr", required: false }] }], displayExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayExpr", required: false }] }], parentIdExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentIdExpr", required: false }] }], rootValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootValue", required: false }] }], expandedExpr: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedExpr", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selectByClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectByClick", required: false }] }], searchEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchEnabled", required: false }] }], searchMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchMode", required: false }] }], useNativeScrolling: [{ type: i0.Input, args: [{ isSignal: true, alias: "useNativeScrolling", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], onItemClick: [{ type: i0.Output, args: ["onItemClick"] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }] } });
|
|
194
323
|
|
|
195
324
|
// @nexterajs/ui/tree-view — public API.
|
|
196
325
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nexterajs-ui-tree-view.mjs","sources":["../../../projects/nextera-ui/tree-view/src/lib/tree-view/nxe-tree-view.component.ts","../../../projects/nextera-ui/tree-view/src/lib/tree-view/nxe-tree-view.component.html","../../../projects/nextera-ui/tree-view/src/public-api.ts","../../../projects/nextera-ui/tree-view/src/nexterajs-ui-tree-view.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n input,\r\n output,\r\n signal,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\n\r\n/** A node in the assembled tree (children built from the flat `parentIdExpr` list). */\r\nexport interface NxeTreeNode {\r\n key: unknown;\r\n text: string;\r\n /** The original data row (consumers read `itemData` off the click event = this). */\r\n data: Record<string, unknown>;\r\n children: NxeTreeNode[];\r\n hasChildren: boolean;\r\n level: number;\r\n}\r\n\r\n/** DevExtreme-shaped `onItemClick` payload (consumers read `event.itemData.<field>`). */\r\nexport interface NxeTreeItemClickEvent {\r\n itemData: Record<string, unknown>;\r\n node: NxeTreeNode;\r\n event: Event;\r\n component: NxeTreeViewComponent;\r\n element: HTMLElement;\r\n}\r\n\r\n/**\r\n * `nxe-tree-view` — drop-in replacement for DevExtreme `dx-tree-view`.\r\n *\r\n * The single usage (settings sidebar) feeds a FLAT list (`dataStructure=\"plain\"`) and lets the\r\n * widget assemble the hierarchy via `keyExpr`/`parentIdExpr`/`rootValue`; so this builds the tree\r\n * internally. Single selection, `selectByClick`, optional search box, and a programmatic\r\n * `expandAll()` (called via `@ViewChild(NxeTreeViewComponent).instance.expandAll()` after async\r\n * load). `(onItemClick)` emits `{ itemData: <full original row>, ... }` so the navigation handler\r\n * keeps reading `event.itemData.url/urlParams/objectName`.\r\n */\r\n@Component({\r\n selector: 'nxe-tree-view',\r\n standalone: true,\r\n templateUrl: './nxe-tree-view.component.html',\r\n styleUrl: './nxe-tree-view.component.scss',\r\n host: {\r\n class: 'nxe-widget nxe-tree-view',\r\n '[class.nxe-treeview-with-search]': 'searchEnabled()',\r\n '[style.width]': 'widthStyle()',\r\n },\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeTreeViewComponent {\r\n readonly dataSource = input<readonly unknown[] | null | undefined>([]);\r\n /** Accepted for parity; this component always assembles a tree from the flat list. */\r\n readonly dataStructure = input<'plain' | 'tree'>('plain');\r\n readonly keyExpr = input<string>('id');\r\n readonly displayExpr = input<string>('text');\r\n readonly parentIdExpr = input<string>('parentId');\r\n readonly rootValue = input<unknown>(0);\r\n /** Accepted for parity (no-op: rows carry no `expanded` field; use `expandAll()`). */\r\n readonly expandedExpr = input<string>('expanded');\r\n readonly selectionMode = input<'single' | 'multiple' | 'none'>('single');\r\n readonly selectByClick = input(false);\r\n readonly searchEnabled = input(false);\r\n readonly searchMode = input<'contains' | 'startswith' | 'equals'>('contains');\r\n /** Accepted for parity (native scrolling is the default here anyway). */\r\n readonly useNativeScrolling = input(true);\r\n readonly width = input<number | string | undefined>(undefined);\r\n\r\n readonly onItemClick = output<NxeTreeItemClickEvent>();\r\n\r\n readonly expanded = signal<ReadonlySet<unknown>>(new Set());\r\n readonly selectedKey = signal<unknown>(null);\r\n readonly searchText = signal('');\r\n\r\n /** DevExtreme `.instance` facade — `expandAll()` is the only method used. */\r\n get instance(): this {\r\n return this;\r\n }\r\n\r\n protected readonly widthStyle = computed(() => {\r\n const w = this.width();\r\n return typeof w === 'number' ? `${w}px` : w;\r\n });\r\n\r\n private readonly tree = computed<NxeTreeNode[]>(() => {\r\n const rows = (this.dataSource() ?? []) as Record<string, unknown>[];\r\n const keyF = this.keyExpr();\r\n const parentF = this.parentIdExpr();\r\n const dispF = this.displayExpr();\r\n const root = this.rootValue();\r\n\r\n const byKey = new Map<unknown, NxeTreeNode>();\r\n for (const r of rows) {\r\n byKey.set(r[keyF], {\r\n key: r[keyF],\r\n text: String(r[dispF] ?? ''),\r\n data: r,\r\n children: [],\r\n hasChildren: false,\r\n level: 0,\r\n });\r\n }\r\n const roots: NxeTreeNode[] = [];\r\n for (const r of rows) {\r\n const node = byKey.get(r[keyF])!;\r\n const parentKey = r[parentF];\r\n const parent = parentKey !== root ? byKey.get(parentKey) : undefined;\r\n if (parent) {\r\n parent.children.push(node);\r\n parent.hasChildren = true;\r\n } else {\r\n roots.push(node);\r\n }\r\n }\r\n const assignLevels = (nodes: NxeTreeNode[], level: number): void => {\r\n for (const n of nodes) {\r\n n.level = level;\r\n assignLevels(n.children, level + 1);\r\n }\r\n };\r\n assignLevels(roots, 0);\r\n return roots;\r\n });\r\n\r\n /** Flattened list of currently-visible nodes (respects expand state + search). */\r\n protected readonly visibleNodes = computed<NxeTreeNode[]>(() => {\r\n const out: NxeTreeNode[] = [];\r\n const query = this.searchText().trim().toLowerCase();\r\n if (query) {\r\n const match = (text: string): boolean => {\r\n const t = text.toLowerCase();\r\n switch (this.searchMode()) {\r\n case 'startswith':\r\n return t.startsWith(query);\r\n case 'equals':\r\n return t === query;\r\n default:\r\n return t.includes(query);\r\n }\r\n };\r\n const walkAll = (nodes: NxeTreeNode[]): void => {\r\n for (const n of nodes) {\r\n if (match(n.text)) {\r\n out.push(n);\r\n }\r\n walkAll(n.children);\r\n }\r\n };\r\n walkAll(this.tree());\r\n } else {\r\n const expanded = this.expanded();\r\n const walk = (nodes: NxeTreeNode[]): void => {\r\n for (const n of nodes) {\r\n out.push(n);\r\n if (n.hasChildren && expanded.has(n.key)) {\r\n walk(n.children);\r\n }\r\n }\r\n };\r\n walk(this.tree());\r\n }\r\n return out;\r\n });\r\n\r\n expandAll(): void {\r\n const keys = new Set<unknown>();\r\n const walk = (nodes: NxeTreeNode[]): void => {\r\n for (const n of nodes) {\r\n if (n.hasChildren) {\r\n keys.add(n.key);\r\n }\r\n walk(n.children);\r\n }\r\n };\r\n walk(this.tree());\r\n this.expanded.set(keys);\r\n }\r\n\r\n collapseAll(): void {\r\n this.expanded.set(new Set());\r\n }\r\n\r\n protected isExpanded(node: NxeTreeNode): boolean {\r\n return this.expanded().has(node.key);\r\n }\r\n\r\n protected toggle(node: NxeTreeNode, event: Event): void {\r\n event.stopPropagation();\r\n this.expanded.update((set) => {\r\n const next = new Set(set);\r\n next.has(node.key) ? next.delete(node.key) : next.add(node.key);\r\n return next;\r\n });\r\n }\r\n\r\n protected onNodeClick(node: NxeTreeNode, event: Event): void {\r\n if (this.selectByClick() && this.selectionMode() !== 'none') {\r\n this.selectedKey.set(node.key);\r\n }\r\n this.onItemClick.emit({\r\n itemData: node.data,\r\n node,\r\n event,\r\n component: this,\r\n element: event.currentTarget as HTMLElement,\r\n });\r\n }\r\n\r\n protected onSearch(event: Event): void {\r\n this.searchText.set((event.target as HTMLInputElement).value);\r\n }\r\n}\r\n","@if (searchEnabled()) {\r\n <div class=\"nxe-treeview-search\">\r\n <input\r\n class=\"nxe-treeview-search-input\"\r\n type=\"text\"\r\n placeholder=\"Search\"\r\n [value]=\"searchText()\"\r\n (input)=\"onSearch($event)\" />\r\n </div>\r\n}\r\n\r\n<ul class=\"nxe-treeview-node-container nxe-treeview-node-container-opened\">\r\n @for (node of visibleNodes(); track node.key) {\r\n <li\r\n class=\"nxe-treeview-node\"\r\n [class.nxe-treeview-node-is-leaf]=\"!node.hasChildren\"\r\n [class.nxe-state-selected]=\"selectionMode() !== 'none' && node.key === selectedKey()\"\r\n [style.padding-left.px]=\"node.level * 15\">\r\n <div class=\"nxe-treeview-item\" (click)=\"onNodeClick(node, $event)\">\r\n @if (node.hasChildren) {\r\n <span\r\n class=\"nxe-treeview-toggle-item-visibility\"\r\n [class.nxe-treeview-toggle-item-visibility-opened]=\"isExpanded(node)\"\r\n (click)=\"toggle(node, $event)\">\r\n </span>\r\n } @else {\r\n <span class=\"nxe-treeview-expander-icon-stub\"></span>\r\n }\r\n <div class=\"nxe-treeview-item-content\">\r\n <span>{{ node.text }}</span>\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n</ul>\r\n","// @nexterajs/ui/tree-view — public API.\r\nexport * from './lib/tree-view/nxe-tree-view.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nexterajs-ui-tree-view.mjs","sources":["../../../projects/nextera-ui/tree-view/src/lib/tree-view/nxe-tree-view.component.ts","../../../projects/nextera-ui/tree-view/src/lib/tree-view/nxe-tree-view.component.html","../../../projects/nextera-ui/tree-view/src/public-api.ts","../../../projects/nextera-ui/tree-view/src/nexterajs-ui-tree-view.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n ElementRef,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n viewChild,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\n\r\n/** A node in the assembled tree (children built from the flat `parentIdExpr` list). */\r\nexport interface NxeTreeNode {\r\n key: unknown;\r\n text: string;\r\n /** The original data row (consumers read `itemData` off the click event = this). */\r\n data: Record<string, unknown>;\r\n children: NxeTreeNode[];\r\n hasChildren: boolean;\r\n level: number;\r\n}\r\n\r\n/** A visible node with the sibling position a flattened tree has to state explicitly. */\r\nexport interface NxeTreeRow {\r\n node: NxeTreeNode;\r\n posInSet: number;\r\n setSize: number;\r\n}\r\n\r\n/** DevExtreme-shaped `onItemClick` payload (consumers read `event.itemData.<field>`). */\r\nexport interface NxeTreeItemClickEvent {\r\n itemData: Record<string, unknown>;\r\n node: NxeTreeNode;\r\n event: Event;\r\n component: NxeTreeViewComponent;\r\n element: HTMLElement;\r\n}\r\n\r\n/**\r\n * `nxe-tree-view` — drop-in replacement for DevExtreme `dx-tree-view`.\r\n *\r\n * The single usage (settings sidebar) feeds a FLAT list (`dataStructure=\"plain\"`) and lets the\r\n * widget assemble the hierarchy via `keyExpr`/`parentIdExpr`/`rootValue`; so this builds the tree\r\n * internally. Single selection, `selectByClick`, optional search box, and a programmatic\r\n * `expandAll()` (called via `@ViewChild(NxeTreeViewComponent).instance.expandAll()` after async\r\n * load). `(onItemClick)` emits `{ itemData: <full original row>, ... }` so the navigation handler\r\n * keeps reading `event.itemData.url/urlParams/objectName`.\r\n */\r\n@Component({\r\n selector: 'nxe-tree-view',\r\n standalone: true,\r\n templateUrl: './nxe-tree-view.component.html',\r\n styleUrl: './nxe-tree-view.component.scss',\r\n host: {\r\n class: 'nxe-widget nxe-tree-view',\r\n '[class.nxe-treeview-with-search]': 'searchEnabled()',\r\n '[style.width]': 'widthStyle()',\r\n },\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\nexport class NxeTreeViewComponent {\r\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\r\n\r\n readonly dataSource = input<readonly unknown[] | null | undefined>([]);\r\n /** Accepted for parity; this component always assembles a tree from the flat list. */\r\n readonly dataStructure = input<'plain' | 'tree'>('plain');\r\n readonly keyExpr = input<string>('id');\r\n readonly displayExpr = input<string>('text');\r\n readonly parentIdExpr = input<string>('parentId');\r\n readonly rootValue = input<unknown>(0);\r\n /** Accepted for parity (no-op: rows carry no `expanded` field; use `expandAll()`). */\r\n readonly expandedExpr = input<string>('expanded');\r\n readonly selectionMode = input<'single' | 'multiple' | 'none'>('single');\r\n readonly selectByClick = input(false);\r\n readonly searchEnabled = input(false);\r\n readonly searchMode = input<'contains' | 'startswith' | 'equals'>('contains');\r\n /** Accepted for parity (native scrolling is the default here anyway). */\r\n readonly useNativeScrolling = input(true);\r\n readonly width = input<number | string | undefined>(undefined);\r\n\r\n readonly onItemClick = output<NxeTreeItemClickEvent>();\r\n\r\n readonly expanded = signal<ReadonlySet<unknown>>(new Set());\r\n readonly selectedKey = signal<unknown>(null);\r\n readonly searchText = signal('');\r\n\r\n private readonly searchInput = viewChild<ElementRef<HTMLInputElement>>('searchInput');\r\n\r\n /** DevExtreme `.instance` facade — `expandAll()` is the only method used. */\r\n get instance(): this {\r\n return this;\r\n }\r\n\r\n protected readonly widthStyle = computed(() => {\r\n const w = this.width();\r\n return typeof w === 'number' ? `${w}px` : w;\r\n });\r\n\r\n private readonly tree = computed<NxeTreeNode[]>(() => {\r\n const rows = (this.dataSource() ?? []) as Record<string, unknown>[];\r\n const keyF = this.keyExpr();\r\n const parentF = this.parentIdExpr();\r\n const dispF = this.displayExpr();\r\n const root = this.rootValue();\r\n\r\n const byKey = new Map<unknown, NxeTreeNode>();\r\n for (const r of rows) {\r\n byKey.set(r[keyF], {\r\n key: r[keyF],\r\n text: String(r[dispF] ?? ''),\r\n data: r,\r\n children: [],\r\n hasChildren: false,\r\n level: 0,\r\n });\r\n }\r\n const roots: NxeTreeNode[] = [];\r\n for (const r of rows) {\r\n const node = byKey.get(r[keyF])!;\r\n const parentKey = r[parentF];\r\n const parent = parentKey !== root ? byKey.get(parentKey) : undefined;\r\n if (parent) {\r\n parent.children.push(node);\r\n parent.hasChildren = true;\r\n } else {\r\n roots.push(node);\r\n }\r\n }\r\n const assignLevels = (nodes: NxeTreeNode[], level: number): void => {\r\n for (const n of nodes) {\r\n n.level = level;\r\n assignLevels(n.children, level + 1);\r\n }\r\n };\r\n assignLevels(roots, 0);\r\n return roots;\r\n });\r\n\r\n /**\r\n * The visible nodes, each with its position among its siblings.\r\n *\r\n * The tree renders as one flat `<ul>` with indentation rather than nested lists, so a screen\r\n * reader cannot infer depth or sibling counts from the DOM. `aria-level`, `aria-setsize` and\r\n * `aria-posinset` are what carry that, which makes them required for a flattened tree rather\r\n * than optional extras. They are computed during the walk, where the sibling array is already\r\n * in hand — reconstructing them from the flat list afterwards is possible but much harder to\r\n * read for no gain.\r\n */\r\n protected readonly visibleRows = computed<NxeTreeRow[]>(() => {\r\n const out: NxeTreeRow[] = [];\r\n const query = this.searchText().trim().toLowerCase();\r\n\r\n if (query) {\r\n const match = (text: string): boolean => {\r\n const t = text.toLowerCase();\r\n switch (this.searchMode()) {\r\n case 'startswith':\r\n return t.startsWith(query);\r\n case 'equals':\r\n return t === query;\r\n default:\r\n return t.includes(query);\r\n }\r\n };\r\n const matches: NxeTreeNode[] = [];\r\n const walkAll = (nodes: NxeTreeNode[]): void => {\r\n for (const n of nodes) {\r\n if (match(n.text)) {\r\n matches.push(n);\r\n }\r\n walkAll(n.children);\r\n }\r\n };\r\n walkAll(this.tree());\r\n // Search flattens the hierarchy, so the results ARE the set: reporting each match\r\n // with its original sibling count would describe a structure that is not on screen.\r\n return matches.map((node, i) => ({ node, posInSet: i + 1, setSize: matches.length }));\r\n }\r\n\r\n const expanded = this.expanded();\r\n const walk = (nodes: NxeTreeNode[]): void => {\r\n nodes.forEach((n, i) => {\r\n out.push({ node: n, posInSet: i + 1, setSize: nodes.length });\r\n if (n.hasChildren && expanded.has(n.key)) {\r\n walk(n.children);\r\n }\r\n });\r\n };\r\n walk(this.tree());\r\n return out;\r\n });\r\n\r\n /** Flattened list of currently-visible nodes (respects expand state + search). */\r\n protected readonly visibleNodes = computed<NxeTreeNode[]>(() =>\r\n this.visibleRows().map((row) => row.node),\r\n );\r\n\r\n expandAll(): void {\r\n const keys = new Set<unknown>();\r\n const walk = (nodes: NxeTreeNode[]): void => {\r\n for (const n of nodes) {\r\n if (n.hasChildren) {\r\n keys.add(n.key);\r\n }\r\n walk(n.children);\r\n }\r\n };\r\n walk(this.tree());\r\n this.expanded.set(keys);\r\n }\r\n\r\n collapseAll(): void {\r\n this.expanded.set(new Set());\r\n }\r\n\r\n protected isExpanded(node: NxeTreeNode): boolean {\r\n return this.expanded().has(node.key);\r\n }\r\n\r\n protected toggle(node: NxeTreeNode, event: Event): void {\r\n event.stopPropagation();\r\n this.expanded.update((set) => {\r\n const next = new Set(set);\r\n next.has(node.key) ? next.delete(node.key) : next.add(node.key);\r\n return next;\r\n });\r\n }\r\n\r\n protected onNodeClick(node: NxeTreeNode, event: Event): void {\r\n if (this.selectByClick() && this.selectionMode() !== 'none') {\r\n this.selectedKey.set(node.key);\r\n }\r\n this.onItemClick.emit({\r\n itemData: node.data,\r\n node,\r\n event,\r\n component: this,\r\n element: event.currentTarget as HTMLElement,\r\n });\r\n }\r\n\r\n protected onSearch(event: Event): void {\r\n this.searchText.set((event.target as HTMLInputElement).value);\r\n }\r\n\r\n /**\r\n * The search box's clear button. dx empties the value and leaves the caret in the box (its\r\n * clear button swallows the mouse-down so the input never loses focus); refocusing here covers\r\n * the case where focus had already left the input.\r\n */\r\n protected clearSearch(): void {\r\n this.searchText.set('');\r\n this.searchInput()?.nativeElement.focus();\r\n }\r\n\r\n /**\r\n * The node holding the tree's single tab stop.\r\n *\r\n * A tree is one stop in the tab order, not one per node, so a roving tabindex is part of the\r\n * role rather than an extra: `role=\"tree\"` on a list nothing can focus would announce a\r\n * structure a keyboard user cannot reach.\r\n */\r\n protected readonly focusedKey = signal<unknown>(null);\r\n\r\n protected isTabStop(node: NxeTreeNode, index: number): boolean {\r\n const focused = this.focusedKey();\r\n return focused === null ? index === 0 : focused === node.key;\r\n }\r\n\r\n /**\r\n * The node that holds DOM focus right now, or `null` while focus is anywhere else.\r\n *\r\n * Deliberately not `focusedKey`: that is the roving tab stop and has to outlive a blur, so Tab\r\n * comes back to the same node. dx drops `dx-state-focused` the moment focus leaves the node,\r\n * and the focused look goes with it — the row colour, and the toggle, which follows the row's\r\n * colour only while focused (`color: unset`, dx.light.css). Keyed off focusin/focusout so the\r\n * class means exactly what it says.\r\n */\r\n private readonly focusedNode = signal<NxeTreeNode | null>(null);\r\n\r\n protected isFocused(node: NxeTreeNode): boolean {\r\n const focused = this.focusedNode();\r\n return focused !== null && focused.key === node.key;\r\n }\r\n\r\n protected onNodeFocus(node: NxeTreeNode): void {\r\n this.focusedKey.set(node.key);\r\n this.focusedNode.set(node);\r\n }\r\n\r\n protected onNodeBlur(node: NxeTreeNode): void {\r\n // focusout on the old node fires before focusin on the new one, so this only ever clears\r\n // the node that is actually losing focus.\r\n if (this.isFocused(node)) {\r\n this.focusedNode.set(null);\r\n }\r\n }\r\n\r\n /** Arrow-key navigation, per the WAI-ARIA tree pattern. */\r\n protected onKeydown(event: KeyboardEvent): void {\r\n const rows = this.visibleRows();\r\n if (!rows.length) {\r\n return;\r\n }\r\n const current = Math.max(\r\n 0,\r\n rows.findIndex((r) => r.node.key === this.focusedKey()),\r\n );\r\n const node = rows[current].node;\r\n const expanded = this.isExpanded(node);\r\n\r\n const focusAt = (index: number): void => {\r\n const target = rows[Math.max(0, Math.min(index, rows.length - 1))];\r\n this.focusedKey.set(target.node.key);\r\n const items = (this.elementRef.nativeElement as HTMLElement).querySelectorAll<HTMLElement>(\r\n '[role=\"treeitem\"]',\r\n );\r\n items[rows.indexOf(target)]?.focus();\r\n };\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n focusAt(current + 1);\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n focusAt(current - 1);\r\n break;\r\n case 'ArrowRight':\r\n event.preventDefault();\r\n if (node.hasChildren && !expanded) {\r\n this.toggle(node, event);\r\n } else if (node.hasChildren) {\r\n focusAt(current + 1);\r\n }\r\n break;\r\n case 'ArrowLeft':\r\n event.preventDefault();\r\n if (node.hasChildren && expanded) {\r\n this.toggle(node, event);\r\n } else {\r\n // to the parent: the nearest earlier row one level up\r\n for (let i = current - 1; i >= 0; i--) {\r\n if (rows[i].node.level < node.level) {\r\n focusAt(i);\r\n break;\r\n }\r\n }\r\n }\r\n break;\r\n case 'Home':\r\n event.preventDefault();\r\n focusAt(0);\r\n break;\r\n case 'End':\r\n event.preventDefault();\r\n focusAt(rows.length - 1);\r\n break;\r\n case 'Enter':\r\n case ' ':\r\n event.preventDefault();\r\n this.onNodeClick(node, event);\r\n break;\r\n default:\r\n }\r\n }\r\n}\r\n","@if (searchEnabled()) {\r\n <!-- dx builds this as a dxTextBox in mode 'search' (ui.search_box_mixin.js), which forces\r\n showClearButton: a magnifier in a 34px slot inside the left border, and a clear button in\r\n a 34px area inside the right border that only exists while there is text to clear. Both\r\n glyphs are drawn here from primitives; the DXIcons font is not used. -->\r\n <div class=\"nxe-treeview-search\">\r\n <!-- The magnifier both search boxes share (dx draws them with one rule,\r\n .dx-searchbox .dx-icon-search): a r4.75 ring and a 45deg handle, 1.9px strokes. Keep\r\n it identical to the header filter's (nxe-header-filter-panel.component.html). -->\r\n <svg class=\"nxe-treeview-search-icon\" viewBox=\"0 0 34 34\" aria-hidden=\"true\" focusable=\"false\">\r\n <circle cx=\"15\" cy=\"15\" r=\"4.75\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" />\r\n <path d=\"M18.5 18.5 23.5 23.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.9\" />\r\n </svg>\r\n <input\r\n #searchInput\r\n class=\"nxe-treeview-search-input\"\r\n type=\"text\"\r\n placeholder=\"Search\"\r\n aria-label=\"Search\"\r\n [value]=\"searchText()\"\r\n (input)=\"onSearch($event)\" />\r\n @if (searchText()) {\r\n <button\r\n class=\"nxe-treeview-search-clear\"\r\n type=\"button\"\r\n tabindex=\"-1\"\r\n aria-label=\"Clear\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"clearSearch()\">\r\n <!-- The editors' clear glyph: a 16px disc with a 2px x cut out, two 2px bars\r\n each running corner to corner of the 8px square centred on the disc, drawn as\r\n a plus and turned 45deg. -->\r\n <svg viewBox=\"0 0 18 18\" aria-hidden=\"true\" focusable=\"false\">\r\n <path\r\n fill=\"currentColor\"\r\n fill-rule=\"evenodd\"\r\n transform=\"rotate(45 9 9)\"\r\n d=\"M9 1a8 8 0 1 1 0 16A8 8 0 1 1 9 1ZM8 3.343h2V8h4.657v2H10v4.657H8V10H3.343V8H8Z\" />\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n}\r\n\r\n<ul\r\n class=\"nxe-treeview-node-container nxe-treeview-node-container-opened\"\r\n role=\"tree\"\r\n [attr.aria-multiselectable]=\"selectionMode() === 'multiple' ? true : null\"\r\n (keydown)=\"onKeydown($event)\">\r\n @for (row of visibleRows(); track row.node.key; let i = $index) {\r\n @let node = row.node;\r\n <li\r\n class=\"nxe-treeview-node nxe-treeview-item-without-checkbox\"\r\n role=\"treeitem\"\r\n [attr.aria-level]=\"node.level + 1\"\r\n [attr.aria-posinset]=\"row.posInSet\"\r\n [attr.aria-setsize]=\"row.setSize\"\r\n [attr.aria-expanded]=\"node.hasChildren ? isExpanded(node) : null\"\r\n [attr.aria-selected]=\"selectionMode() === 'none' ? null : node.key === selectedKey()\"\r\n [attr.tabindex]=\"isTabStop(node, i) ? 0 : -1\"\r\n (focusin)=\"onNodeFocus(node)\"\r\n (focusout)=\"onNodeBlur(node)\"\r\n [class.nxe-treeview-node-is-leaf]=\"!node.hasChildren\"\r\n [class.nxe-state-selected]=\"selectionMode() !== 'none' && node.key === selectedKey()\"\r\n [class.nxe-state-focused]=\"isFocused(node)\"\r\n [style.padding-left.px]=\"node.level * 15\">\r\n <div class=\"nxe-treeview-item\" (click)=\"onNodeClick(node, $event)\">\r\n @if (node.hasChildren) {\r\n <span\r\n class=\"nxe-treeview-toggle-item-visibility\"\r\n [class.nxe-treeview-toggle-item-visibility-opened]=\"isExpanded(node)\"\r\n (click)=\"toggle(node, $event)\">\r\n </span>\r\n } @else {\r\n <span class=\"nxe-treeview-expander-icon-stub\"></span>\r\n }\r\n <div class=\"nxe-treeview-item-content\">\r\n <span>{{ node.text }}</span>\r\n </div>\r\n </div>\r\n </li>\r\n }\r\n</ul>\r\n","// @nexterajs/ui/tree-view — public API.\r\nexport * from './lib/tree-view/nxe-tree-view.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|