luxen-ui 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/chunks/decorate.js +2 -0
- package/cdn/chunks/decorate.js.map +1 -0
- package/cdn/chunks/lit.js +3 -0
- package/cdn/chunks/lit.js.map +1 -0
- package/cdn/custom-elements.json +14499 -0
- package/cdn/define.d.ts +9 -0
- package/cdn/define.d.ts.map +1 -0
- package/cdn/define.js +2 -0
- package/cdn/define.js.map +1 -0
- package/cdn/elements/avatar/avatar.d.ts +21 -0
- package/cdn/elements/avatar/avatar.d.ts.map +1 -0
- package/cdn/elements/avatar/avatar.js +18 -0
- package/cdn/elements/avatar/avatar.js.map +1 -0
- package/cdn/elements/avatar/index.d.ts +8 -0
- package/cdn/elements/avatar/index.d.ts.map +1 -0
- package/cdn/elements/avatar/index.js +2 -0
- package/cdn/elements/avatar/index.js.map +1 -0
- package/cdn/elements/badge/badge.d.ts +17 -0
- package/cdn/elements/badge/badge.d.ts.map +1 -0
- package/cdn/elements/badge/badge.js +2 -0
- package/cdn/elements/badge/badge.js.map +1 -0
- package/cdn/elements/badge/index.d.ts +8 -0
- package/cdn/elements/badge/index.d.ts.map +1 -0
- package/cdn/elements/badge/index.js +2 -0
- package/cdn/elements/badge/index.js.map +1 -0
- package/cdn/elements/carousel/carousel.d.ts +148 -0
- package/cdn/elements/carousel/carousel.d.ts.map +1 -0
- package/cdn/elements/carousel/carousel.js +87 -0
- package/cdn/elements/carousel/carousel.js.map +1 -0
- package/cdn/elements/carousel/index.d.ts +8 -0
- package/cdn/elements/carousel/index.d.ts.map +1 -0
- package/cdn/elements/carousel/index.js +2 -0
- package/cdn/elements/carousel/index.js.map +1 -0
- package/cdn/elements/carousel-item/carousel-item.d.ts +13 -0
- package/cdn/elements/carousel-item/carousel-item.d.ts.map +1 -0
- package/cdn/elements/carousel-item/carousel-item.js +2 -0
- package/cdn/elements/carousel-item/carousel-item.js.map +1 -0
- package/cdn/elements/carousel-item/index.d.ts +8 -0
- package/cdn/elements/carousel-item/index.d.ts.map +1 -0
- package/cdn/elements/carousel-item/index.js +2 -0
- package/cdn/elements/carousel-item/index.js.map +1 -0
- package/cdn/elements/dialog/dialog.d.ts +57 -0
- package/cdn/elements/dialog/dialog.d.ts.map +1 -0
- package/cdn/elements/dialog/dialog.js +18 -0
- package/cdn/elements/dialog/dialog.js.map +1 -0
- package/cdn/elements/dialog/dialog.styles.d.ts +8 -0
- package/cdn/elements/dialog/dialog.styles.d.ts.map +1 -0
- package/cdn/elements/dialog/dialog.styles.js +2 -0
- package/cdn/elements/dialog/dialog.styles.js.map +1 -0
- package/cdn/elements/dialog/index.d.ts +8 -0
- package/cdn/elements/dialog/index.d.ts.map +1 -0
- package/cdn/elements/dialog/index.js +2 -0
- package/cdn/elements/dialog/index.js.map +1 -0
- package/cdn/elements/divider/divider.d.ts +23 -0
- package/cdn/elements/divider/divider.d.ts.map +1 -0
- package/cdn/elements/divider/divider.js +2 -0
- package/cdn/elements/divider/divider.js.map +1 -0
- package/cdn/elements/divider/index.d.ts +8 -0
- package/cdn/elements/divider/index.d.ts.map +1 -0
- package/cdn/elements/divider/index.js +2 -0
- package/cdn/elements/divider/index.js.map +1 -0
- package/cdn/elements/drawer/drawer.d.ts +34 -0
- package/cdn/elements/drawer/drawer.d.ts.map +1 -0
- package/cdn/elements/drawer/drawer.js +2 -0
- package/cdn/elements/drawer/drawer.js.map +1 -0
- package/cdn/elements/drawer/index.d.ts +8 -0
- package/cdn/elements/drawer/index.d.ts.map +1 -0
- package/cdn/elements/drawer/index.js +2 -0
- package/cdn/elements/drawer/index.js.map +1 -0
- package/cdn/elements/dropdown/dropdown.d.ts +64 -0
- package/cdn/elements/dropdown/dropdown.d.ts.map +1 -0
- package/cdn/elements/dropdown/dropdown.js +20 -0
- package/cdn/elements/dropdown/dropdown.js.map +1 -0
- package/cdn/elements/dropdown/index.d.ts +8 -0
- package/cdn/elements/dropdown/index.d.ts.map +1 -0
- package/cdn/elements/dropdown/index.js +2 -0
- package/cdn/elements/dropdown/index.js.map +1 -0
- package/cdn/elements/dropdown-item/dropdown-item.d.ts +25 -0
- package/cdn/elements/dropdown-item/dropdown-item.d.ts.map +1 -0
- package/cdn/elements/dropdown-item/dropdown-item.js +34 -0
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -0
- package/cdn/elements/dropdown-item/index.d.ts +8 -0
- package/cdn/elements/dropdown-item/index.d.ts.map +1 -0
- package/cdn/elements/dropdown-item/index.js +2 -0
- package/cdn/elements/dropdown-item/index.js.map +1 -0
- package/cdn/elements/icon/icon.d.ts +18 -0
- package/cdn/elements/icon/icon.d.ts.map +1 -0
- package/cdn/elements/icon/icon.js +7 -0
- package/cdn/elements/icon/icon.js.map +1 -0
- package/cdn/elements/icon/index.d.ts +8 -0
- package/cdn/elements/icon/index.d.ts.map +1 -0
- package/cdn/elements/icon/index.js +2 -0
- package/cdn/elements/icon/index.js.map +1 -0
- package/cdn/elements/input-otp/index.d.ts +8 -0
- package/cdn/elements/input-otp/index.d.ts.map +1 -0
- package/cdn/elements/input-otp/index.js +2 -0
- package/cdn/elements/input-otp/index.js.map +1 -0
- package/cdn/elements/input-otp/input-otp.d.ts +31 -0
- package/cdn/elements/input-otp/input-otp.d.ts.map +1 -0
- package/cdn/elements/input-otp/input-otp.js +2 -0
- package/cdn/elements/input-otp/input-otp.js.map +1 -0
- package/cdn/elements/input-stepper/index.d.ts +8 -0
- package/cdn/elements/input-stepper/index.d.ts.map +1 -0
- package/cdn/elements/input-stepper/index.js +2 -0
- package/cdn/elements/input-stepper/index.js.map +1 -0
- package/cdn/elements/input-stepper/input-stepper.d.ts +66 -0
- package/cdn/elements/input-stepper/input-stepper.d.ts.map +1 -0
- package/cdn/elements/input-stepper/input-stepper.js +2 -0
- package/cdn/elements/input-stepper/input-stepper.js.map +1 -0
- package/cdn/elements/popover/index.d.ts +8 -0
- package/cdn/elements/popover/index.d.ts.map +1 -0
- package/cdn/elements/popover/index.js +2 -0
- package/cdn/elements/popover/index.js.map +1 -0
- package/cdn/elements/popover/popover.d.ts +64 -0
- package/cdn/elements/popover/popover.d.ts.map +1 -0
- package/cdn/elements/popover/popover.js +17 -0
- package/cdn/elements/popover/popover.js.map +1 -0
- package/cdn/elements/rating/index.d.ts +8 -0
- package/cdn/elements/rating/index.d.ts.map +1 -0
- package/cdn/elements/rating/index.js +2 -0
- package/cdn/elements/rating/index.js.map +1 -0
- package/cdn/elements/rating/rating.d.ts +38 -0
- package/cdn/elements/rating/rating.d.ts.map +1 -0
- package/cdn/elements/rating/rating.js +41 -0
- package/cdn/elements/rating/rating.js.map +1 -0
- package/cdn/elements/skeleton/index.d.ts +8 -0
- package/cdn/elements/skeleton/index.d.ts.map +1 -0
- package/cdn/elements/skeleton/index.js +2 -0
- package/cdn/elements/skeleton/index.js.map +1 -0
- package/cdn/elements/skeleton/skeleton.d.ts +12 -0
- package/cdn/elements/skeleton/skeleton.d.ts.map +1 -0
- package/cdn/elements/skeleton/skeleton.js +2 -0
- package/cdn/elements/skeleton/skeleton.js.map +1 -0
- package/cdn/elements/spinner/index.d.ts +8 -0
- package/cdn/elements/spinner/index.d.ts.map +1 -0
- package/cdn/elements/spinner/index.js +2 -0
- package/cdn/elements/spinner/index.js.map +1 -0
- package/cdn/elements/spinner/spinner.d.ts +16 -0
- package/cdn/elements/spinner/spinner.d.ts.map +1 -0
- package/cdn/elements/spinner/spinner.js +18 -0
- package/cdn/elements/spinner/spinner.js.map +1 -0
- package/cdn/elements/tabs/index.d.ts +8 -0
- package/cdn/elements/tabs/index.d.ts.map +1 -0
- package/cdn/elements/tabs/index.js +2 -0
- package/cdn/elements/tabs/index.js.map +1 -0
- package/cdn/elements/tabs/tabs.d.ts +48 -0
- package/cdn/elements/tabs/tabs.d.ts.map +1 -0
- package/cdn/elements/tabs/tabs.js +2 -0
- package/cdn/elements/tabs/tabs.js.map +1 -0
- package/cdn/elements/toast/index.d.ts +9 -0
- package/cdn/elements/toast/index.d.ts.map +1 -0
- package/cdn/elements/toast/index.js +2 -0
- package/cdn/elements/toast/index.js.map +1 -0
- package/cdn/elements/toast/toast.d.ts +72 -0
- package/cdn/elements/toast/toast.d.ts.map +1 -0
- package/cdn/elements/toast/toast.js +2 -0
- package/cdn/elements/toast/toast.js.map +1 -0
- package/cdn/elements/tooltip/index.d.ts +8 -0
- package/cdn/elements/tooltip/index.d.ts.map +1 -0
- package/cdn/elements/tooltip/index.js +2 -0
- package/cdn/elements/tooltip/index.js.map +1 -0
- package/cdn/elements/tooltip/tooltip.d.ts +59 -0
- package/cdn/elements/tooltip/tooltip.d.ts.map +1 -0
- package/cdn/elements/tooltip/tooltip.js +17 -0
- package/cdn/elements/tooltip/tooltip.js.map +1 -0
- package/cdn/elements/tree/index.d.ts +8 -0
- package/cdn/elements/tree/index.d.ts.map +1 -0
- package/cdn/elements/tree/index.js +2 -0
- package/cdn/elements/tree/index.js.map +1 -0
- package/cdn/elements/tree/tree.d.ts +76 -0
- package/cdn/elements/tree/tree.d.ts.map +1 -0
- package/cdn/elements/tree/tree.js +14 -0
- package/cdn/elements/tree/tree.js.map +1 -0
- package/cdn/elements/tree-item/index.d.ts +8 -0
- package/cdn/elements/tree-item/index.d.ts.map +1 -0
- package/cdn/elements/tree-item/index.js +2 -0
- package/cdn/elements/tree-item/index.js.map +1 -0
- package/cdn/elements/tree-item/tree-item.d.ts +74 -0
- package/cdn/elements/tree-item/tree-item.d.ts.map +1 -0
- package/cdn/elements/tree-item/tree-item.js +83 -0
- package/cdn/elements/tree-item/tree-item.js.map +1 -0
- package/cdn/index.d.ts +6 -0
- package/cdn/index.d.ts.map +1 -0
- package/cdn/index.js +1 -0
- package/cdn/registry.d.ts +22 -0
- package/cdn/registry.d.ts.map +1 -0
- package/cdn/registry.js +2 -0
- package/cdn/registry.js.map +1 -0
- package/cdn/shared/controllers/popover.d.ts +45 -0
- package/cdn/shared/controllers/popover.d.ts.map +1 -0
- package/cdn/shared/controllers/popover.js +2 -0
- package/cdn/shared/controllers/popover.js.map +1 -0
- package/cdn/shared/luxen-element.d.ts +20 -0
- package/cdn/shared/luxen-element.d.ts.map +1 -0
- package/cdn/shared/luxen-element.js +2 -0
- package/cdn/shared/luxen-element.js.map +1 -0
- package/cdn/shared/luxen-form-associated-element.d.ts +49 -0
- package/cdn/shared/luxen-form-associated-element.d.ts.map +1 -0
- package/cdn/shared/luxen-form-associated-element.js +2 -0
- package/cdn/shared/luxen-form-associated-element.js.map +1 -0
- package/cdn/shared/styles/host.styles.d.ts +9 -0
- package/cdn/shared/styles/host.styles.d.ts.map +1 -0
- package/cdn/shared/styles/host.styles.js +2 -0
- package/cdn/shared/styles/host.styles.js.map +1 -0
- package/cdn/styles/elements/avatar.css +20 -0
- package/cdn/styles/elements/badge.css +159 -0
- package/cdn/styles/elements/button.css +171 -0
- package/cdn/styles/elements/close-button/circle.css +66 -0
- package/cdn/styles/elements/close-button/ring.css +71 -0
- package/cdn/styles/elements/close-button/square.css +70 -0
- package/cdn/styles/elements/disclosure.css +137 -0
- package/cdn/styles/elements/divider.css +75 -0
- package/cdn/styles/elements/input-otp.css +164 -0
- package/cdn/styles/elements/input-stepper/default.css +248 -0
- package/cdn/styles/elements/input-stepper/rounded.css +241 -0
- package/cdn/styles/elements/kbd.css +21 -0
- package/cdn/styles/elements/progress.css +114 -0
- package/cdn/styles/elements/select.css +71 -0
- package/cdn/styles/elements/skeleton.css +89 -0
- package/cdn/styles/elements/tabs/enclosed.css +148 -0
- package/cdn/styles/elements/tabs/line.css +138 -0
- package/cdn/styles/elements/toast.css +260 -0
- package/cdn/styles/index.css +885 -0
- package/cdn/vite-env.d.js +0 -0
- package/dist/css/elements/input-stepper/default.css +19 -16
- package/dist/css/elements/input-stepper/rounded.css +14 -11
- package/dist/custom-elements.json +299 -224
- package/dist/elements/dialog/dialog.css +4 -3
- package/dist/elements/dialog/dialog.d.ts +1 -0
- package/dist/elements/dialog/dialog.d.ts.map +1 -1
- package/dist/elements/dialog/dialog.js +1 -0
- package/dist/elements/input-stepper/input-stepper.d.ts +3 -0
- package/dist/elements/input-stepper/input-stepper.d.ts.map +1 -1
- package/dist/elements/input-stepper/input-stepper.js +3 -0
- package/dist/elements/popover/popover.css +7 -2
- package/dist/elements/popover/popover.d.ts +3 -1
- package/dist/elements/popover/popover.d.ts.map +1 -1
- package/dist/elements/popover/popover.js +15 -4
- package/dist/shared/controllers/popover.d.ts +1 -0
- package/dist/shared/controllers/popover.d.ts.map +1 -1
- package/dist/shared/controllers/popover.js +2 -1
- package/package.json +12 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.js","names":[],"sources":["../../../src/html/elements/toast/toast.ts"],"sourcesContent":["/* eslint-disable no-shadow -- the local `toast` HTMLElement intentionally\n shadows the module-level `toast()` export; renaming would touch ~50 lines\n without behavioral benefit. */\nimport { LuxenElement } from '../../shared/luxen-element';\nimport { property } from 'lit/decorators.js';\nimport { tagName, cls, uniqueId } from '../../registry';\n\ndeclare global {\n interface Element {\n /** @see https://developer.mozilla.org/en-US/docs/Web/API/Element/setHTML */\n setHTML(input: string, options?: Record<string, unknown>): void;\n }\n}\n\n/** Minimal custom element for toast items — no render, no shadow DOM. */\nexport class LuxenToastItem extends HTMLElement {}\n\ninterface ToastOptionsBase {\n /** Optional heading text displayed above the message. */\n heading?: string;\n /** Override the element's variant for this toast. */\n variant?: string;\n /** Override auto-dismiss duration (ms) for this toast. 0 = no auto-dismiss. */\n duration?: number;\n /** Iconify icon name (e.g. 'lucide:check'). Replaces the accent bar. */\n icon?: string;\n /** Show a countdown progress bar at the bottom. Default `false`. */\n timer?: boolean;\n}\n\nexport type ToastOptions =\n | (ToastOptionsBase & { /** The message text to display. */ text: string; html?: never })\n | (ToastOptionsBase & {\n text?: never;\n /** HTML content (sanitized via the Sanitizer API). */ html: string;\n });\n\ninterface TimerState {\n remaining: number;\n startTime: number;\n timeoutId: number;\n paused: boolean;\n}\n\n/**\n * @summary A toast notification container that generates toast items internally.\n * @customElement l-toast\n *\n * @event show - Emitted when a toast begins to show. Cancelable.\n * @event after-show - Emitted after the show animation completes.\n * @event hide - Emitted when a toast begins to hide. Cancelable.\n * @event after-hide - Emitted after the hide animation completes and toast is removed.\n *\n * @cssproperty --gap - Gap between stacked toast items.\n * @cssproperty --width - Width of the toast stack.\n * @cssproperty --show-duration - Duration of the show animation.\n * @cssproperty --hide-duration - Duration of the hide animation.\n */\nexport class LuxenToast extends LuxenElement {\n /** Use light DOM — no Shadow DOM. */\n override createRenderRoot() {\n return this;\n }\n\n /** Position of the toast stack on the screen. */\n @property({ reflect: true }) placement:\n | 'top-start'\n | 'top-center'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-center'\n | 'bottom-end' = 'top-end';\n\n /** Default auto-dismiss delay in milliseconds. 0 disables auto-dismiss. */\n @property({ type: Number, reflect: true }) duration = 5000;\n\n /** Default variant for toast items: info, success, warning, danger. */\n @property({ reflect: true }) variant = '';\n\n private _timers = new WeakMap<HTMLElement, TimerState>();\n private _positionCache = new WeakMap<Element, DOMRect>();\n private _documentHidden = false;\n\n override connectedCallback() {\n super.connectedCallback();\n this.popover = 'manual';\n this.setAttribute('role', 'log');\n this.setAttribute('aria-live', 'polite');\n this.setAttribute('aria-relevant', 'additions');\n\n document.addEventListener('keydown', this._onKeyDown);\n document.addEventListener('visibilitychange', this._onVisibilityChange);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('keydown', this._onKeyDown);\n document.removeEventListener('visibilitychange', this._onVisibilityChange);\n }\n\n /** Create and show a toast notification. */\n toast(options: ToastOptions): HTMLElement {\n const { heading, variant = this.variant, duration = this.duration } = options;\n\n // Build toast DOM\n const uid = uniqueId('toast');\n const toast = document.createElement(tagName('toast-item'));\n if (variant) toast.setAttribute('variant', variant);\n toast.setAttribute('role', variant === 'danger' ? 'alert' : 'status');\n toast.setAttribute('aria-atomic', 'true');\n\n if (options.icon) {\n const icon = document.createElement('iconify-icon');\n icon.setAttribute('icon', options.icon);\n icon.setAttribute('width', '20');\n icon.setAttribute('height', '20');\n icon.setAttribute('aria-hidden', 'true');\n icon.className = cls('toast-icon');\n toast.appendChild(icon);\n } else {\n const accent = document.createElement('div');\n accent.className = cls('toast-accent');\n accent.setAttribute('aria-hidden', 'true');\n toast.appendChild(accent);\n }\n\n const content = document.createElement('div');\n content.className = cls('toast-content');\n\n const textWrap = document.createElement('div');\n\n if (heading) {\n const headingEl = document.createElement('div');\n headingEl.id = `${uid}-heading`;\n headingEl.className = `${cls('toast-heading')} font-medium`;\n headingEl.textContent = heading;\n textWrap.appendChild(headingEl);\n toast.setAttribute('aria-labelledby', `${uid}-heading`);\n }\n\n const messageEl = document.createElement('div');\n messageEl.id = `${uid}-message`;\n messageEl.className = cls('toast-message');\n if ('html' in options && options.html) {\n messageEl.setHTML(options.html);\n } else {\n messageEl.textContent = options.text ?? '';\n }\n textWrap.appendChild(messageEl);\n toast.setAttribute(heading ? 'aria-describedby' : 'aria-labelledby', `${uid}-message`);\n\n content.appendChild(textWrap);\n toast.appendChild(content);\n\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = cls('close');\n closeBtn.setAttribute('data-appearance', 'ring');\n closeBtn.setAttribute('aria-label', 'Close');\n closeBtn.addEventListener('click', () => this._hideToast(toast));\n toast.appendChild(closeBtn);\n\n // Timer bar (opt-in)\n if (options.timer && duration > 0 && isFinite(duration)) {\n const timerBar = document.createElement('div');\n timerBar.className = cls('toast-timer');\n timerBar.setAttribute('aria-hidden', 'true');\n timerBar.style.setProperty('--_timer-duration', `${duration}ms`);\n toast.appendChild(timerBar);\n }\n\n // FLIP: capture existing positions\n this._capturePositions();\n\n // Insert into container\n if (this.placement.includes('bottom')) {\n this.appendChild(toast);\n } else {\n this.prepend(toast);\n }\n\n // Show popover if not already open\n if (!this.matches(':popover-open')) {\n this.showPopover();\n }\n\n // Dispatch show\n if (!this.emit('show', { cancelable: true, detail: { toast } })) {\n toast.remove();\n return toast;\n }\n\n // Trigger show animation on next frame\n requestAnimationFrame(() => {\n toast.setAttribute('showing', '');\n this._animatePositions();\n\n const onShown = (e: TransitionEvent) => {\n if (e.target !== toast) return;\n toast.removeEventListener('transitionend', onShown);\n this.emit('after-show', { detail: { toast } });\n };\n toast.addEventListener('transitionend', onShown);\n });\n\n // Auto-dismiss timer (0 or Infinity = persistent)\n if (duration > 0 && isFinite(duration)) {\n this._startTimer(toast, duration);\n }\n\n // Pause/resume timer on hover and focus\n toast.addEventListener('pointerenter', () => this._pauseTimer(toast));\n toast.addEventListener('pointerleave', () => this._resumeTimer(toast));\n toast.addEventListener('focusin', () => this._pauseTimer(toast));\n toast.addEventListener('focusout', () => this._resumeTimer(toast));\n\n // ── Swipe-to-dismiss ──────────────────────────────────────────────────────\n\n let swipeStart: { x: number; y: number } | null = null;\n let swiping = false;\n\n toast.addEventListener('pointerdown', (e: PointerEvent) => {\n if (e.button !== 0) return;\n if ((e.target as Element).closest('button, a, [role=\"button\"]')) return;\n swipeStart = { x: e.clientX, y: e.clientY };\n swiping = false;\n toast.setPointerCapture(e.pointerId);\n toast.style.transition = 'none';\n });\n\n // Only allow swiping away from the screen edge, never inward\n const clampDelta = (dx: number) =>\n this.placement.endsWith('-start')\n ? Math.min(dx, 0)\n : this.placement.endsWith('-end')\n ? Math.max(dx, 0)\n : dx;\n\n toast.addEventListener('pointermove', (e: PointerEvent) => {\n if (!swipeStart) return;\n const deltaX = clampDelta(e.clientX - swipeStart.x);\n const deltaY = e.clientY - swipeStart.y;\n\n const buffer = e.pointerType === 'touch' ? 10 : 2;\n if (!swiping && Math.abs(deltaX) < buffer) return;\n\n // If vertical movement dominates, cancel swipe tracking\n if (!swiping && Math.abs(deltaY) > Math.abs(deltaX)) {\n swipeStart = null;\n return;\n }\n\n swiping = true;\n this._pauseTimer(toast);\n toast.style.transform = `translateX(${deltaX}px)`;\n toast.style.opacity = `${1 - Math.abs(deltaX) / 300}`;\n });\n\n toast.addEventListener('pointerup', (e: PointerEvent) => {\n if (!swipeStart) return;\n const deltaX = clampDelta(e.clientX - swipeStart.x);\n swipeStart = null;\n toast.style.transition = '';\n\n if (swiping && Math.abs(deltaX) > 50) {\n const dir = deltaX > 0 ? 1 : -1;\n toast.style.transform = `translateX(${dir * 120}%)`;\n toast.style.opacity = '0';\n toast.addEventListener('transitionend', () => this._hideToast(toast), { once: true });\n } else {\n toast.style.transform = '';\n toast.style.opacity = '';\n if (swiping) this._resumeTimer(toast);\n }\n swiping = false;\n });\n\n return toast;\n }\n\n // ── Timer management ──────────────────────────────────────────────────────────\n\n private _startTimer(toast: HTMLElement, duration: number) {\n const timeoutId = window.setTimeout(() => this._hideToast(toast), duration);\n this._timers.set(toast, {\n remaining: duration,\n startTime: performance.now(),\n timeoutId,\n paused: false,\n });\n }\n\n private _pauseTimer(toast: HTMLElement) {\n const timer = this._timers.get(toast);\n if (!timer || timer.paused) return;\n clearTimeout(timer.timeoutId);\n timer.remaining -= performance.now() - timer.startTime;\n timer.paused = true;\n\n // Use the Web Animations API to pause the countdown bar. CSS `animation-play-state`\n // cannot be used here because browsers defer style recalculations while the tab is\n // hidden, so the animation runs to completion before the style change takes effect.\n const timerBar = toast.querySelector(`.${cls('toast-timer')}`);\n if (timerBar) for (const anim of timerBar.getAnimations()) anim.pause();\n }\n\n private _resumeTimer(toast: HTMLElement) {\n const timer = this._timers.get(toast);\n if (!timer || !timer.paused || timer.remaining <= 0 || this._documentHidden) return;\n timer.startTime = performance.now();\n timer.timeoutId = window.setTimeout(() => this._hideToast(toast), timer.remaining);\n timer.paused = false;\n\n const timerBar = toast.querySelector(`.${cls('toast-timer')}`);\n if (timerBar) for (const anim of timerBar.getAnimations()) anim.play();\n }\n\n // ── Hide a toast ──────────────────────────────────────────────────────────────\n\n private _hideToast(toast: HTMLElement) {\n // Clear timer\n const timer = this._timers.get(toast);\n if (timer) {\n clearTimeout(timer.timeoutId);\n this._timers.delete(toast);\n }\n\n // Prevent double-hide\n if (!toast.hasAttribute('showing')) return;\n\n // Dispatch hide\n if (!this.emit('hide', { cancelable: true, detail: { toast } })) return;\n\n this._capturePositions();\n\n // Remove showing class to trigger exit transition\n toast.removeAttribute('showing');\n\n const remove = () => {\n toast.remove();\n this._animatePositions();\n\n this.emit('after-hide', { detail: { toast } });\n\n // Close popover if no toasts remain\n const remaining = this.querySelectorAll(`:scope > ${tagName('toast-item')}`);\n if (remaining.length === 0 && this.matches(':popover-open')) {\n this.hidePopover();\n }\n };\n\n // Handle zero-duration transitions (reduced motion)\n const duration = parseFloat(getComputedStyle(toast).transitionDuration);\n if (duration === 0) {\n remove();\n } else {\n const onEnd = (e: TransitionEvent) => {\n if (e.target !== toast) return;\n toast.removeEventListener('transitionend', onEnd);\n remove();\n };\n toast.addEventListener('transitionend', onEnd);\n }\n }\n\n // ── FLIP animation for reordering ─────────────────────────────────────────────\n\n private _capturePositions() {\n const items = this.querySelectorAll(`:scope > ${tagName('toast-item')}`);\n for (const child of items) {\n this._positionCache.set(child, child.getBoundingClientRect());\n }\n }\n\n private _animatePositions() {\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n\n const items = this.querySelectorAll(`:scope > ${tagName('toast-item')}`);\n for (const child of items) {\n const oldRect = this._positionCache.get(child);\n if (!oldRect) continue;\n\n const newRect = child.getBoundingClientRect();\n const deltaY = oldRect.top - newRect.top;\n\n if (Math.abs(deltaY) < 1) continue;\n\n (child as HTMLElement).animate(\n [{ transform: `translateY(${deltaY}px)` }, { transform: 'translateY(0)' }],\n { duration: 200, easing: 'cubic-bezier(0.2, 0, 0, 1)' },\n );\n }\n }\n\n // ── Document visibility ──────────────────────────────────────────────────────\n\n private _onVisibilityChange = () => {\n this._documentHidden = document.hidden;\n const items = this.querySelectorAll<HTMLElement>(`:scope > ${tagName('toast-item')}`);\n if (document.hidden) {\n for (const item of items) this._pauseTimer(item);\n } else {\n for (const item of items) this._resumeTimer(item);\n }\n };\n\n // ── Keyboard ──────────────────────────────────────────────────────────────────\n\n private _onKeyDown = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return;\n if (!this.matches(':popover-open')) return;\n\n const last = this.querySelector<HTMLElement>(`:scope > ${tagName('toast-item')}:last-of-type`);\n if (last) {\n e.preventDefault();\n this._hideToast(last);\n }\n };\n}\n\n// ── Standalone function ───────────────────────────────────────────────────────\n\nlet _defaultInstance: LuxenToast | null = null;\n\nfunction _getDefault(): LuxenToast {\n if (!_defaultInstance || !_defaultInstance.isConnected) {\n _defaultInstance =\n document.querySelector(tagName('toast')) ??\n (document.createElement(tagName('toast')) as LuxenToast);\n if (!_defaultInstance.isConnected) {\n document.body.appendChild(_defaultInstance);\n }\n }\n return _defaultInstance;\n}\n\n/** Show a toast notification. Auto-creates `<l-toast>` if none exists in the DOM. */\nexport function toast(options: ToastOptions): HTMLElement {\n return _getDefault().toast(options);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tooltip/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,cAAc,WAAW,CAAC;AAG1B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,YAAY,CAAC;KAC3B;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/tooltip/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenTooltip } from './tooltip';\nexport * from './tooltip';\ndefine('tooltip', LuxenTooltip);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-tooltip': LuxenTooltip;\n }\n}\n"],"mappings":"qFAGA,EAAO,UAAW,EAAa"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
2
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
3
|
+
import { Placement } from '@floating-ui/dom';
|
|
4
|
+
/**
|
|
5
|
+
* @summary A tooltip that displays contextual text on hover or focus.
|
|
6
|
+
* @customElement l-tooltip
|
|
7
|
+
*
|
|
8
|
+
* @slot - Tooltip content (text or rich HTML).
|
|
9
|
+
*
|
|
10
|
+
* @csspart body - The tooltip popover container.
|
|
11
|
+
* @csspart arrow - The directional arrow element.
|
|
12
|
+
*
|
|
13
|
+
* @cssproperty --background - Background color. Default: dark in light mode, light in dark mode.
|
|
14
|
+
* @cssproperty --color - Text color.
|
|
15
|
+
* @cssproperty --radius - Border radius. Default `4px`.
|
|
16
|
+
* @cssproperty --max-width - Maximum width. Default `180px`.
|
|
17
|
+
* @cssproperty --arrow-size - Arrow size. Default `6px`.
|
|
18
|
+
* @cssproperty --show-duration - Show animation duration. Default `150ms`.
|
|
19
|
+
* @cssproperty --hide-duration - Hide animation duration. Default `150ms`.
|
|
20
|
+
*/
|
|
21
|
+
export declare class LuxenTooltip extends LuxenElement {
|
|
22
|
+
static styles: import('lit').CSSResult[];
|
|
23
|
+
private _tooltipId;
|
|
24
|
+
private _floating;
|
|
25
|
+
/** The HTML id of the element triggering the tooltip. */
|
|
26
|
+
accessor for: string;
|
|
27
|
+
/** The preferred placement of the tooltip. */
|
|
28
|
+
accessor placement: Placement;
|
|
29
|
+
/** The distance in pixels from the target element. */
|
|
30
|
+
accessor distance: number;
|
|
31
|
+
/** Whether or not the tooltip is visible. */
|
|
32
|
+
accessor open: boolean;
|
|
33
|
+
/** Hide the directional arrow. */
|
|
34
|
+
accessor withoutArrow: boolean;
|
|
35
|
+
/** Space-separated list of trigger modes: `hover`, `focus`, `click`, `manual`. */
|
|
36
|
+
accessor trigger: string;
|
|
37
|
+
private _hasTrigger;
|
|
38
|
+
private get _trigger();
|
|
39
|
+
private get _popover();
|
|
40
|
+
private get _arrowEl();
|
|
41
|
+
private _getDuration;
|
|
42
|
+
connectedCallback(): void;
|
|
43
|
+
disconnectedCallback(): void;
|
|
44
|
+
updated(changed: PropertyValues<this>): void;
|
|
45
|
+
show(): void;
|
|
46
|
+
hide(): void;
|
|
47
|
+
toggle(): void;
|
|
48
|
+
private _handleOpenChange;
|
|
49
|
+
private _onPointerEnter;
|
|
50
|
+
private _onPointerLeave;
|
|
51
|
+
private _onFocusIn;
|
|
52
|
+
private _onFocusOut;
|
|
53
|
+
private _onClick;
|
|
54
|
+
private _onKeyDown;
|
|
55
|
+
private _addTriggerListeners;
|
|
56
|
+
private _removeTriggerListeners;
|
|
57
|
+
render(): import('lit').TemplateResult<1>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=tooltip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tooltip/tooltip.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQlD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAgB,MAAM,4BAAwB;IAE9C,OAAO,CAAC,UAAU,CAAuB;IAEzC,OAAO,CAAC,SAAS,CAId;IAEH,yDAAyD;IAEzD,QAAQ,CAAC,GAAG,SAAM;IAElB,8CAA8C;IAE9C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAS;IAEtC,sDAAsD;IAEtD,QAAQ,CAAC,QAAQ,SAAK;IAEtB,6CAA6C;IAE7C,QAAQ,CAAC,IAAI,UAAS;IAEtB,kCAAkC;IAElC,QAAQ,CAAC,YAAY,UAAS;IAE9B,kFAAkF;IAElF,QAAQ,CAAC,OAAO,SAAiB;IAEjC,OAAO,CAAC,WAAW;IAInB,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,CAAC,YAAY;IAKX,iBAAiB;IAKjB,oBAAoB;IAKpB,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAU9C,IAAI;IAIJ,IAAI;IAIJ,MAAM;YAIQ,iBAAiB;IAwB/B,OAAO,CAAC,eAAe,CAIrB;IAEF,OAAO,CAAC,eAAe,CAGrB;IAEF,OAAO,CAAC,UAAU,CAEhB;IACF,OAAO,CAAC,WAAW,CAEjB;IACF,OAAO,CAAC,QAAQ,CAEd;IAEF,OAAO,CAAC,UAAU,CAKhB;IAEF,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,uBAAuB;IAOtB,MAAM;CAoBhB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import{uniqueId as e}from"../../registry.js";import{c as t,i as n,n as r}from"../../chunks/lit.js";import{LuxenElement as i}from"../../shared/luxen-element.js";import{a,t as o}from"../../chunks/decorate.js";import s from"../../shared/styles/host.styles.js";import{PopoverController as c}from"../../shared/controllers/popover.js";var l=t(`:host{--background:var(--l-color-bg-fill-brand,var(--lightningcss-light,#1f2937)var(--lightningcss-dark,#f9fafb));--color:var(--lightningcss-light,#fff)var(--lightningcss-dark,#111827);--radius:4px;--max-width:180px;--arrow-size:6px;--show-duration:.15s;--hide-duration:.15s;display:contents}[popover]{inset:unset;box-sizing:border-box;width:max-content;max-width:var(--max-width);border-radius:var(--radius);background:var(--background);color:var(--color);filter:drop-shadow(0 1px 2px #00000029);pointer-events:none;border:0;padding:4px 8px;font-size:.8125rem;line-height:1.4;overflow:visible}i{width:var(--arrow-size);height:var(--arrow-size);background:var(--background);display:block;position:absolute;transform:rotate(45deg)}`),u=class extends i{constructor(...t){super(...t),this._tooltipId=e(`tooltip`),this._floating=new c(this,{getTriggerElement:()=>this._trigger,getFloatingElement:()=>this._popover,getArrowElement:()=>this._arrowEl}),this.#e=``,this.#t=`top`,this.#n=8,this.#r=!1,this.#i=!1,this.#a=`hover focus`,this._onPointerEnter=()=>{this._hasTrigger(`hover`)&&(this._floating.cleanupSafePolygon(),this.show())},this._onPointerLeave=e=>{!this._hasTrigger(`hover`)||!this.open||this._floating.handlePointerLeave(e,()=>this.hide())},this._onFocusIn=()=>{this._hasTrigger(`focus`)&&this.show()},this._onFocusOut=()=>{this._hasTrigger(`focus`)&&this.hide()},this._onClick=()=>{this._hasTrigger(`click`)&&this.toggle()},this._onKeyDown=e=>{this.open&&e.key===`Escape`&&(e.stopPropagation(),this.hide())}}static{this.styles=[s,l]}#e;get for(){return this.#e}set for(e){this.#e=e}#t;get placement(){return this.#t}set placement(e){this.#t=e}#n;get distance(){return this.#n}set distance(e){this.#n=e}#r;get open(){return this.#r}set open(e){this.#r=e}#i;get withoutArrow(){return this.#i}set withoutArrow(e){this.#i=e}#a;get trigger(){return this.#a}set trigger(e){this.#a=e}_hasTrigger(e){return this.trigger.split(` `).includes(e)}get _trigger(){return this.for?this.getRootNode().getElementById(this.for):null}get _popover(){return this.shadowRoot.querySelector(`[popover]`)}get _arrowEl(){return this.withoutArrow?null:this.shadowRoot.querySelector(`i`)}_getDuration(e){let t=parseFloat(getComputedStyle(this).getPropertyValue(e));return Number.isNaN(t)?150:t}connectedCallback(){super.connectedCallback(),requestAnimationFrame(()=>this._addTriggerListeners())}disconnectedCallback(){super.disconnectedCallback(),this._removeTriggerListeners()}updated(e){e.has(`open`)&&this._handleOpenChange(),e.has(`for`)&&(this._removeTriggerListeners(e.get(`for`)),this._addTriggerListeners())}show(){this.open||=!0}hide(){this.open&&=!1}toggle(){this.open=!this.open}async _handleOpenChange(){let e=this._popover;if(!e)return;let t={placement:this.placement,distance:this.distance};if(this.open){if(e.showPopover(),await this._floating.updatePosition(t),!this.open)return;await this._floating.animateShow(e,this._getDuration(`--show-duration`)),this._floating.startPositioning(t),this._trigger?.setAttribute(`aria-describedby`,this._tooltipId)}else this._floating.stopPositioning(),this._floating.cleanupSafePolygon(),this._trigger?.removeAttribute(`aria-describedby`),await this._floating.animateHide(e,this._getDuration(`--hide-duration`)),e.matches(`:popover-open`)&&e.hidePopover()}_addTriggerListeners(){this._floating.addTriggerListeners({onPointerEnter:this._onPointerEnter,onPointerLeave:this._onPointerLeave,onFocusIn:this._onFocusIn,onFocusOut:this._onFocusOut,onClick:this._onClick,onKeyDown:this._onKeyDown})}_removeTriggerListeners(e){let t=e?this.getRootNode().getElementById(e):void 0;this._floating.removeTriggerListeners(t)}render(){return n`
|
|
2
|
+
<div
|
|
3
|
+
id=${this._tooltipId}
|
|
4
|
+
popover="manual"
|
|
5
|
+
role="tooltip"
|
|
6
|
+
part="body"
|
|
7
|
+
>
|
|
8
|
+
${this.withoutArrow?r:n`
|
|
9
|
+
<i
|
|
10
|
+
part="arrow"
|
|
11
|
+
role="presentation"
|
|
12
|
+
></i>
|
|
13
|
+
`}
|
|
14
|
+
<slot></slot>
|
|
15
|
+
</div>
|
|
16
|
+
`}};o([a()],u.prototype,`for`,null),o([a()],u.prototype,`placement`,null),o([a({type:Number})],u.prototype,`distance`,null),o([a({type:Boolean,reflect:!0})],u.prototype,`open`,null),o([a({type:Boolean,reflect:!0,attribute:`without-arrow`})],u.prototype,`withoutArrow`,null),o([a()],u.prototype,`trigger`,null);export{u as LuxenTooltip};
|
|
17
|
+
//# sourceMappingURL=tooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tooltip.js","names":[],"sources":["../../../src/html/elements/tooltip/tooltip.css?inline","../../../src/html/elements/tooltip/tooltip.ts"],"sourcesContent":[":host {\n --background: var(--l-color-bg-fill-brand, light-dark(#1f2937, #f9fafb));\n --color: light-dark(#fff, #111827);\n --radius: 4px;\n --max-width: 180px;\n --arrow-size: 6px;\n --show-duration: 150ms;\n --hide-duration: 150ms;\n\n display: contents;\n}\n\n[popover] {\n inset: unset;\n overflow: visible;\n box-sizing: border-box;\n width: max-content;\n max-width: var(--max-width);\n padding: 4px 8px;\n border: 0;\n border-radius: var(--radius);\n background: var(--background);\n color: var(--color);\n font-size: 0.8125rem;\n line-height: 1.4;\n filter: drop-shadow(0 1px 2px rgb(0 0 0 / 16%));\n pointer-events: none;\n}\n\ni {\n position: absolute;\n display: block;\n width: var(--arrow-size);\n height: var(--arrow-size);\n background: var(--background);\n transform: rotate(45deg);\n}\n","import { html, nothing, unsafeCSS, type PropertyValues } from 'lit';\nimport { LuxenElement } from '../../shared/luxen-element';\nimport { property } from 'lit/decorators.js';\nimport type { Placement } from '@floating-ui/dom';\nimport { PopoverController } from '../../shared/controllers/popover';\nimport { uniqueId } from '../../registry';\nimport hostStyles from '../../shared/styles/host.styles';\nimport rawStyles from './tooltip.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\n/**\n * @summary A tooltip that displays contextual text on hover or focus.\n * @customElement l-tooltip\n *\n * @slot - Tooltip content (text or rich HTML).\n *\n * @csspart body - The tooltip popover container.\n * @csspart arrow - The directional arrow element.\n *\n * @cssproperty --background - Background color. Default: dark in light mode, light in dark mode.\n * @cssproperty --color - Text color.\n * @cssproperty --radius - Border radius. Default `4px`.\n * @cssproperty --max-width - Maximum width. Default `180px`.\n * @cssproperty --arrow-size - Arrow size. Default `6px`.\n * @cssproperty --show-duration - Show animation duration. Default `150ms`.\n * @cssproperty --hide-duration - Hide animation duration. Default `150ms`.\n */\nexport class LuxenTooltip extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _tooltipId = uniqueId('tooltip');\n\n private _floating = new PopoverController(this, {\n getTriggerElement: () => this._trigger,\n getFloatingElement: () => this._popover,\n getArrowElement: () => this._arrowEl,\n });\n\n /** The HTML id of the element triggering the tooltip. */\n @property()\n accessor for = '';\n\n /** The preferred placement of the tooltip. */\n @property()\n accessor placement: Placement = 'top';\n\n /** The distance in pixels from the target element. */\n @property({ type: Number })\n accessor distance = 8;\n\n /** Whether or not the tooltip is visible. */\n @property({ type: Boolean, reflect: true })\n accessor open = false;\n\n /** Hide the directional arrow. */\n @property({ type: Boolean, reflect: true, attribute: 'without-arrow' })\n accessor withoutArrow = false;\n\n /** Space-separated list of trigger modes: `hover`, `focus`, `click`, `manual`. */\n @property()\n accessor trigger = 'hover focus';\n\n private _hasTrigger(type: string) {\n return this.trigger.split(' ').includes(type);\n }\n\n private get _trigger(): HTMLElement | null {\n return this.for ? (this.getRootNode() as Document | ShadowRoot).getElementById(this.for) : null;\n }\n\n private get _popover(): HTMLElement {\n return this.shadowRoot!.querySelector('[popover]')!;\n }\n\n private get _arrowEl(): HTMLElement | null {\n return this.withoutArrow ? null : this.shadowRoot!.querySelector('i');\n }\n\n private _getDuration(prop: '--show-duration' | '--hide-duration'): number {\n const parsed = parseFloat(getComputedStyle(this).getPropertyValue(prop));\n return Number.isNaN(parsed) ? 150 : parsed;\n }\n\n override connectedCallback() {\n super.connectedCallback();\n requestAnimationFrame(() => this._addTriggerListeners());\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._removeTriggerListeners();\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('open')) {\n this._handleOpenChange();\n }\n if (changed.has('for')) {\n this._removeTriggerListeners(changed.get('for') as string);\n this._addTriggerListeners();\n }\n }\n\n show() {\n if (!this.open) this.open = true;\n }\n\n hide() {\n if (this.open) this.open = false;\n }\n\n toggle() {\n this.open = !this.open;\n }\n\n private async _handleOpenChange() {\n const popover = this._popover;\n if (!popover) return;\n\n const posOpts = { placement: this.placement, distance: this.distance };\n\n if (this.open) {\n popover.showPopover();\n await this._floating.updatePosition(posOpts);\n if (!this.open) return;\n await this._floating.animateShow(popover, this._getDuration('--show-duration'));\n this._floating.startPositioning(posOpts);\n this._trigger?.setAttribute('aria-describedby', this._tooltipId);\n } else {\n this._floating.stopPositioning();\n this._floating.cleanupSafePolygon();\n this._trigger?.removeAttribute('aria-describedby');\n await this._floating.animateHide(popover, this._getDuration('--hide-duration'));\n if (popover.matches(':popover-open')) popover.hidePopover();\n }\n }\n\n // --- Trigger event handlers ---\n\n private _onPointerEnter = () => {\n if (!this._hasTrigger('hover')) return;\n this._floating.cleanupSafePolygon();\n this.show();\n };\n\n private _onPointerLeave = (e: PointerEvent) => {\n if (!this._hasTrigger('hover') || !this.open) return;\n this._floating.handlePointerLeave(e, () => this.hide());\n };\n\n private _onFocusIn = () => {\n if (this._hasTrigger('focus')) this.show();\n };\n private _onFocusOut = () => {\n if (this._hasTrigger('focus')) this.hide();\n };\n private _onClick = () => {\n if (this._hasTrigger('click')) this.toggle();\n };\n\n private _onKeyDown = (e: KeyboardEvent) => {\n if (this.open && e.key === 'Escape') {\n e.stopPropagation();\n this.hide();\n }\n };\n\n private _addTriggerListeners() {\n this._floating.addTriggerListeners({\n onPointerEnter: this._onPointerEnter,\n onPointerLeave: this._onPointerLeave,\n onFocusIn: this._onFocusIn,\n onFocusOut: this._onFocusOut,\n onClick: this._onClick,\n onKeyDown: this._onKeyDown,\n });\n }\n\n private _removeTriggerListeners(forId?: string) {\n const trigger = forId\n ? (this.getRootNode() as Document | ShadowRoot).getElementById(forId)\n : undefined;\n this._floating.removeTriggerListeners(trigger);\n }\n\n override render() {\n return html`\n <div\n id=${this._tooltipId}\n popover=\"manual\"\n role=\"tooltip\"\n part=\"body\"\n >\n ${this.withoutArrow\n ? nothing\n : html`\n <i\n part=\"arrow\"\n role=\"presentation\"\n ></i>\n `}\n <slot></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tree/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,cAAc,QAAQ,CAAC;AAGvB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,QAAQ,EAAE,SAAS,CAAC;KACrB;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/tree/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenTree } from './tree';\nexport * from './tree';\ndefine('tree', LuxenTree);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-tree': LuxenTree;\n }\n}\n"],"mappings":"+EAGA,EAAO,OAAQ,EAAU"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
2
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
3
|
+
import { LuxenTreeItem } from '../tree-item/tree-item';
|
|
4
|
+
export type TreeSelection = 'single' | 'multiple' | 'leaf' | 'none';
|
|
5
|
+
/**
|
|
6
|
+
* A hierarchical tree view composed of `<l-tree-item>` children.
|
|
7
|
+
*
|
|
8
|
+
* @slot - One or more `l-tree-item` elements.
|
|
9
|
+
*
|
|
10
|
+
* @csspart base - The root tree container.
|
|
11
|
+
*
|
|
12
|
+
* @cssproperty --indent-size - Horizontal indent per depth level. Default `1rem`.
|
|
13
|
+
* @cssproperty --indent-guide-width - Thickness of the vertical guide line between a parent and its children. Default `1px`. Set to `0` to hide guides.
|
|
14
|
+
* @cssproperty --indent-guide-style - Line style of the guide (`solid`, `dashed`, `dotted`, `double`…). Default `solid`.
|
|
15
|
+
* @cssproperty --indent-guide-color - Color of the guide line.
|
|
16
|
+
* @cssproperty --row-height - Minimum row height. Default `1.75rem`.
|
|
17
|
+
* @cssproperty --row-padding-inline - Inner inline padding of the row; also drives the content slot left indent and the indent guide column. Default `0.25rem`.
|
|
18
|
+
* @cssproperty --chevron-size - Size of the expand/collapse chevron box. Default `1.125rem`.
|
|
19
|
+
* @cssproperty --item-gap - Horizontal gap between chevron, prefix, label and suffix on the row; also drives the content slot left indent. Default `0.375rem`.
|
|
20
|
+
*
|
|
21
|
+
* @event selection-change - Fired when the selected items change. Detail: `{ selection: LuxenTreeItem[] }`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class LuxenTree extends LuxenElement {
|
|
24
|
+
static styles: import('lit').CSSResult[];
|
|
25
|
+
private _mutationObserver?;
|
|
26
|
+
private _lastFocusedItem;
|
|
27
|
+
/**
|
|
28
|
+
* Selection behaviour:
|
|
29
|
+
* - `single` (default): at most one item selected via `aria-selected`.
|
|
30
|
+
* - `multiple`: any number of items selected. Checkboxes are rendered.
|
|
31
|
+
* - `leaf`: only leaf items can be selected (single). Branches just toggle.
|
|
32
|
+
* - `none`: purely navigable, no selection state.
|
|
33
|
+
*/
|
|
34
|
+
accessor selection: TreeSelection;
|
|
35
|
+
/**
|
|
36
|
+
* When set with `selection="multiple"`, parent and children selection are decoupled:
|
|
37
|
+
* toggling a parent does NOT toggle its descendants and vice versa.
|
|
38
|
+
* Without it, selection cascades both ways and branches may become indeterminate.
|
|
39
|
+
*/
|
|
40
|
+
accessor independent: boolean;
|
|
41
|
+
connectedCallback(): void;
|
|
42
|
+
disconnectedCallback(): void;
|
|
43
|
+
updated(changed: PropertyValues<this>): void;
|
|
44
|
+
/** Returns all items in document (flat) order, including nested ones. */
|
|
45
|
+
getAllItems({ includeDisabled }?: {
|
|
46
|
+
includeDisabled?: boolean | undefined;
|
|
47
|
+
}): LuxenTreeItem[];
|
|
48
|
+
/** Returns currently selected items. */
|
|
49
|
+
getSelection(): LuxenTreeItem[];
|
|
50
|
+
/** Expands every item that has children. */
|
|
51
|
+
expandAll(): void;
|
|
52
|
+
/** Collapses every item. */
|
|
53
|
+
collapseAll(): void;
|
|
54
|
+
private _syncAll;
|
|
55
|
+
private _syncSubtree;
|
|
56
|
+
private _canShowCheckboxOn;
|
|
57
|
+
private _rootItems;
|
|
58
|
+
private _ensureTabStop;
|
|
59
|
+
/** Items currently visible (parent chain all expanded). */
|
|
60
|
+
private _visibleItems;
|
|
61
|
+
private _onItemToggle;
|
|
62
|
+
private _handleRowActivate;
|
|
63
|
+
private _setSingleSelection;
|
|
64
|
+
private _selectItem;
|
|
65
|
+
private _setSubtreeSelection;
|
|
66
|
+
/** Propagate child state UP to parents (indeterminate / auto-checked). */
|
|
67
|
+
private _updateBranchStates;
|
|
68
|
+
private _emitSelectionChange;
|
|
69
|
+
private _onClick;
|
|
70
|
+
private _itemFromEvent;
|
|
71
|
+
private _focusItem;
|
|
72
|
+
private _onFocusIn;
|
|
73
|
+
private _onKeyDown;
|
|
74
|
+
render(): import('lit').TemplateResult<1>;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tree/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAM5D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,SAAU,SAAQ,YAAY;IACzC,OAAgB,MAAM,4BAAwB;IAE9C,OAAO,CAAC,iBAAiB,CAAC,CAAmB;IAC7C,OAAO,CAAC,gBAAgB,CAA8B;IAEtD;;;;;;OAMG;IAEH,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAY;IAE7C;;;;OAIG;IAEH,QAAQ,CAAC,WAAW,UAAS;IAEpB,iBAAiB;IAUjB,oBAAoB;IAMpB,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAQ9C,yEAAyE;IACzE,WAAW,CAAC,EAAE,eAAsB,EAAE;;KAAK,GAAG,aAAa,EAAE;IAO7D,wCAAwC;IACxC,YAAY,IAAI,aAAa,EAAE;IAI/B,4CAA4C;IAC5C,SAAS;IAMT,4BAA4B;IAC5B,WAAW;IAQX,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,cAAc;IAUtB,2DAA2D;IAC3D,OAAO,CAAC,aAAa;IAcrB,OAAO,CAAC,aAAa,CAGnB;IAEF,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,oBAAoB;IAS5B,0EAA0E;IAC1E,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,QAAQ,CAqDd;IAEF,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,UAAU,CAMhB;IAEF,OAAO,CAAC,UAAU,CAyEhB;IAEO,MAAM;CAehB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{tagName as e}from"../../registry.js";import{c as t,i as n}from"../../chunks/lit.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{a as i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=t(`:host{--indent-size:1rem;--indent-guide-width:1px;--indent-guide-style:solid;--indent-guide-color:var(--l-color-border-interactive,var(--lightningcss-light,#d1d5db)var(--lightningcss-dark,#3a4048));--row-height:1.75rem;--row-padding-inline:.25rem;--chevron-size:1.125rem;--item-gap:.375rem;color:var(--l-color-text-primary,CanvasText);font-family:inherit;line-height:1.5;display:block}.tree{outline:none;display:block}.tree:focus-visible{outline:2px solid var(--l-focus-ring,Highlight);outline-offset:2px;border-radius:.375rem}`),c=class extends r{constructor(...t){super(...t),this._lastFocusedItem=null,this.#e=`single`,this.#t=!1,this._onItemToggle=e=>{let{item:t,checked:n}=e.detail;this._selectItem(t,n)},this._onClick=e=>{let t=this._itemFromEvent(e);if(!t||t.disabled)return;let n=e.composedPath();if(n.some(e=>e instanceof HTMLInputElement&&e.type===`checkbox`))return;let r=new Set([`BUTTON`,`A`,`INPUT`,`SELECT`,`TEXTAREA`]),i=new Set([`button`,`link`,`menuitem`,`menuitemcheckbox`]);if(n.some(e=>{if(!(e instanceof HTMLElement)||e===t||e.getAttribute?.(`part`)===`expand-button`||e instanceof HTMLInputElement&&e.type===`checkbox`)return!1;if(r.has(e.tagName))return!0;let n=e.getAttribute?.(`role`);return n!==null&&i.has(n)}))return;let a=n.some(e=>e instanceof HTMLElement&&e.getAttribute?.(`part`)===`expand-button`);if(this._focusItem(t),a){t.toggle();return}switch(this.selection){case`single`:this._setSingleSelection(t),t.isLeaf()||t.toggle();break;case`leaf`:t.isLeaf()?this._setSingleSelection(t):t.toggle();break;case`multiple`:this._selectItem(t,!t.selected);break;case`none`:t.toggle();break}},this._onFocusIn=t=>{let n=t.target;if(n instanceof HTMLElement){let t=n.closest(e(`tree-item`));t&&(this._lastFocusedItem=t)}},this._onKeyDown=t=>{let n=this._lastFocusedItem??this._visibleItems()[0];if(!n)return;let r=this._visibleItems(),i=r.indexOf(n);switch(t.key){case`ArrowDown`:{t.preventDefault();let e=r[Math.min(i+1,r.length-1)];e&&this._focusItem(e);break}case`ArrowUp`:{t.preventDefault();let e=r[Math.max(i-1,0)];e&&this._focusItem(e);break}case`ArrowRight`:if(t.preventDefault(),!n.isLeaf()&&!n.expanded)n.expanded=!0;else if(n.expanded){let e=n.getChildrenItems()[0];e&&this._focusItem(e)}break;case`ArrowLeft`:if(t.preventDefault(),n.expanded&&!n.isLeaf())n.expanded=!1;else{let t=n.parentElement?.closest(e(`tree-item`));t&&this._focusItem(t)}break;case`Home`:t.preventDefault(),r[0]&&this._focusItem(r[0]);break;case`End`:{t.preventDefault();let e=r[r.length-1];e&&this._focusItem(e);break}case`Enter`:case` `:t.preventDefault(),this._handleRowActivate(n);break;case`*`:{t.preventDefault();let r=(n.parentElement?Array.from(n.parentElement.children):[]).filter(t=>t.tagName===e(`tree-item`).toUpperCase());for(let e of r)e.isLeaf()||(e.expanded=!0);break}}}}static{this.styles=[o,s]}#e;get selection(){return this.#e}set selection(e){this.#e=e}#t;get independent(){return this.#t}set independent(e){this.#t=e}connectedCallback(){super.connectedCallback(),this._mutationObserver=new MutationObserver(()=>this._syncAll()),this._mutationObserver.observe(this,{childList:!0,subtree:!0}),this.addEventListener(`l-tree-item-toggle`,this._onItemToggle),queueMicrotask(()=>this._syncAll())}disconnectedCallback(){super.disconnectedCallback(),this._mutationObserver?.disconnect(),this.removeEventListener(`l-tree-item-toggle`,this._onItemToggle)}updated(e){(e.has(`selection`)||e.has(`independent`))&&this._syncAll()}getAllItems({includeDisabled:t=!0}={}){let n=e(`tree-item`);return Array.from(this.querySelectorAll(n)).filter(e=>t||!e.disabled)}getSelection(){return this.getAllItems().filter(e=>e.selected)}expandAll(){for(let e of this.getAllItems())e.isLeaf()||(e.expanded=!0)}collapseAll(){for(let e of this.getAllItems())e.expanded=!1}_syncAll(){let e=this.selection===`multiple`,t=this._rootItems();for(let n of t)this._syncSubtree(n,0,e);this._updateBranchStates(),this._ensureTabStop()}_syncSubtree(e,t,n){e.depth=t,e.showCheckbox=n&&this._canShowCheckboxOn(e);for(let r of e.getChildrenItems())this._syncSubtree(r,t+1,n)}_canShowCheckboxOn(e){return this.selection===`multiple`}_rootItems(){let t=e(`tree-item`).toUpperCase();return Array.from(this.children).filter(e=>e.tagName===t)}_ensureTabStop(){let e=this._visibleItems();if(e.length!==0&&!e.some(e=>e.tabIndex===0)){for(let t of e)t.tabIndex=-1;e[0].tabIndex=0}}_visibleItems(){let e=[],t=n=>{for(let r of n)e.push(r),r.expanded&&t(r.getChildrenItems())};return t(this._rootItems()),e}_handleRowActivate(e){if(!e.disabled)switch(this.selection){case`single`:this._setSingleSelection(e);break;case`leaf`:e.isLeaf()?this._setSingleSelection(e):e.toggle();break;case`multiple`:this._selectItem(e,!e.selected);break;case`none`:e.toggle();break}}_setSingleSelection(e){for(let t of this.getAllItems())t!==e&&t.selected&&(t.selected=!1);e.selected=!0,this._emitSelectionChange()}_selectItem(e,t){e.disabled||(e.selected=t,this.selection===`multiple`&&!this.independent&&this._setSubtreeSelection(e,t),e.indeterminate=!1,this._updateBranchStates(),this._emitSelectionChange())}_setSubtreeSelection(e,t){for(let n of e.getChildrenItems())n.disabled||(n.selected=t,n.indeterminate=!1,this._setSubtreeSelection(n,t))}_updateBranchStates(){if(this.selection!==`multiple`||this.independent){for(let e of this.getAllItems())e.indeterminate=!1;return}let e=t=>{let n=t.getChildrenItems({includeDisabled:!1});if(n.length===0)return{all:t.selected,any:t.selected};let r=!0,i=!1;for(let t of n){let n=e(t);n.all||(r=!1),n.any&&(i=!0)}return t.selected=r,t.indeterminate=!r&&i,{all:r&&(t.getChildrenItems().length>0?r:t.selected),any:i}};for(let t of this._rootItems())e(t)}_emitSelectionChange(){this.emit(`selection-change`,{detail:{selection:this.getSelection()}})}_itemFromEvent(t){let n=e(`tree-item`),r=t.composedPath();for(let e of r)if(e instanceof HTMLElement&&e.matches?.(n))return e;return null}_focusItem(e){let t=this._visibleItems();for(let e of t)e.tabIndex=-1;e.tabIndex=0,e.focus(),this._lastFocusedItem=e}render(){return n`
|
|
2
|
+
<div
|
|
3
|
+
class="tree"
|
|
4
|
+
part="base"
|
|
5
|
+
role="tree"
|
|
6
|
+
aria-multiselectable=${this.selection===`multiple`?`true`:`false`}
|
|
7
|
+
@click=${this._onClick}
|
|
8
|
+
@keydown=${this._onKeyDown}
|
|
9
|
+
@focusin=${this._onFocusIn}
|
|
10
|
+
>
|
|
11
|
+
<slot></slot>
|
|
12
|
+
</div>
|
|
13
|
+
`}};a([i({reflect:!0})],c.prototype,`selection`,null),a([i({type:Boolean,reflect:!0})],c.prototype,`independent`,null);export{c as LuxenTree};
|
|
14
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","names":[],"sources":["../../../src/html/elements/tree/tree.css?inline","../../../src/html/elements/tree/tree.ts"],"sourcesContent":[":host {\n --indent-size: 1rem;\n --indent-guide-width: 1px;\n --indent-guide-style: solid;\n --indent-guide-color: var(--l-color-border-interactive, light-dark(#d1d5db, #3a4048));\n --row-height: 1.75rem;\n --row-padding-inline: 0.25rem;\n --chevron-size: 1.125rem;\n --item-gap: 0.375rem;\n\n display: block;\n color: var(--l-color-text-primary, CanvasText);\n font-family: inherit;\n line-height: 1.5;\n}\n\n.tree {\n display: block;\n outline: none;\n}\n\n.tree:focus-visible {\n outline: 2px solid var(--l-focus-ring, Highlight);\n outline-offset: 2px;\n border-radius: 0.375rem;\n}\n","import { html, unsafeCSS, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { LuxenElement } from '../../shared/luxen-element';\nimport { tagName } from '../../registry';\nimport type { LuxenTreeItem } from '../tree-item/tree-item';\nimport hostStyles from '../../shared/styles/host.styles';\nimport rawStyles from './tree.css?inline';\n\nconst styles = unsafeCSS(rawStyles);\n\nexport type TreeSelection = 'single' | 'multiple' | 'leaf' | 'none';\n\n/**\n * A hierarchical tree view composed of `<l-tree-item>` children.\n *\n * @slot - One or more `l-tree-item` elements.\n *\n * @csspart base - The root tree container.\n *\n * @cssproperty --indent-size - Horizontal indent per depth level. Default `1rem`.\n * @cssproperty --indent-guide-width - Thickness of the vertical guide line between a parent and its children. Default `1px`. Set to `0` to hide guides.\n * @cssproperty --indent-guide-style - Line style of the guide (`solid`, `dashed`, `dotted`, `double`…). Default `solid`.\n * @cssproperty --indent-guide-color - Color of the guide line.\n * @cssproperty --row-height - Minimum row height. Default `1.75rem`.\n * @cssproperty --row-padding-inline - Inner inline padding of the row; also drives the content slot left indent and the indent guide column. Default `0.25rem`.\n * @cssproperty --chevron-size - Size of the expand/collapse chevron box. Default `1.125rem`.\n * @cssproperty --item-gap - Horizontal gap between chevron, prefix, label and suffix on the row; also drives the content slot left indent. Default `0.375rem`.\n *\n * @event selection-change - Fired when the selected items change. Detail: `{ selection: LuxenTreeItem[] }`.\n */\nexport class LuxenTree extends LuxenElement {\n static override styles = [hostStyles, styles];\n\n private _mutationObserver?: MutationObserver;\n private _lastFocusedItem: LuxenTreeItem | null = null;\n\n /**\n * Selection behaviour:\n * - `single` (default): at most one item selected via `aria-selected`.\n * - `multiple`: any number of items selected. Checkboxes are rendered.\n * - `leaf`: only leaf items can be selected (single). Branches just toggle.\n * - `none`: purely navigable, no selection state.\n */\n @property({ reflect: true })\n accessor selection: TreeSelection = 'single';\n\n /**\n * When set with `selection=\"multiple\"`, parent and children selection are decoupled:\n * toggling a parent does NOT toggle its descendants and vice versa.\n * Without it, selection cascades both ways and branches may become indeterminate.\n */\n @property({ type: Boolean, reflect: true })\n accessor independent = false;\n\n override connectedCallback() {\n super.connectedCallback();\n this._mutationObserver = new MutationObserver(() => this._syncAll());\n this._mutationObserver.observe(this, { childList: true, subtree: true });\n this.addEventListener('l-tree-item-toggle', this._onItemToggle as EventListener);\n\n // Defer sync to let light DOM upgrade.\n queueMicrotask(() => this._syncAll());\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._mutationObserver?.disconnect();\n this.removeEventListener('l-tree-item-toggle', this._onItemToggle as EventListener);\n }\n\n override updated(changed: PropertyValues<this>) {\n if (changed.has('selection') || changed.has('independent')) {\n this._syncAll();\n }\n }\n\n // --- Public API ---\n\n /** Returns all items in document (flat) order, including nested ones. */\n getAllItems({ includeDisabled = true } = {}): LuxenTreeItem[] {\n const tag = tagName('tree-item');\n return Array.from(this.querySelectorAll<LuxenTreeItem>(tag)).filter(\n (item) => includeDisabled || !item.disabled,\n );\n }\n\n /** Returns currently selected items. */\n getSelection(): LuxenTreeItem[] {\n return this.getAllItems().filter((i) => i.selected);\n }\n\n /** Expands every item that has children. */\n expandAll() {\n for (const item of this.getAllItems()) {\n if (!item.isLeaf()) item.expanded = true;\n }\n }\n\n /** Collapses every item. */\n collapseAll() {\n for (const item of this.getAllItems()) {\n item.expanded = false;\n }\n }\n\n // --- Sync / ARIA / depth / checkbox visibility ---\n\n private _syncAll() {\n const showCheckbox = this.selection === 'multiple';\n const roots = this._rootItems();\n for (const root of roots) {\n this._syncSubtree(root, 0, showCheckbox);\n }\n this._updateBranchStates();\n // Ensure at least one item is tabbable.\n this._ensureTabStop();\n }\n\n private _syncSubtree(item: LuxenTreeItem, depth: number, showCheckbox: boolean) {\n item.depth = depth;\n item.showCheckbox = showCheckbox && this._canShowCheckboxOn(item);\n for (const child of item.getChildrenItems()) {\n this._syncSubtree(child, depth + 1, showCheckbox);\n }\n }\n\n private _canShowCheckboxOn(_item: LuxenTreeItem): boolean {\n if (this.selection !== 'multiple') return false;\n // In cascade mode, branches get a checkbox too so you can bulk-toggle children.\n // In leaf-only selection, hidden here because selection !== 'multiple'.\n return true;\n }\n\n private _rootItems(): LuxenTreeItem[] {\n const tag = tagName('tree-item').toUpperCase();\n return (Array.from(this.children) as LuxenTreeItem[]).filter((el) => el.tagName === tag);\n }\n\n private _ensureTabStop() {\n const items = this._visibleItems();\n if (items.length === 0) return;\n const hasTabStop = items.some((i) => i.tabIndex === 0);\n if (!hasTabStop) {\n for (const i of items) i.tabIndex = -1;\n items[0].tabIndex = 0;\n }\n }\n\n /** Items currently visible (parent chain all expanded). */\n private _visibleItems(): LuxenTreeItem[] {\n const out: LuxenTreeItem[] = [];\n const walk = (items: LuxenTreeItem[]) => {\n for (const i of items) {\n out.push(i);\n if (i.expanded) walk(i.getChildrenItems());\n }\n };\n walk(this._rootItems());\n return out;\n }\n\n // --- Selection handling ---\n\n private _onItemToggle = (event: CustomEvent<{ item: LuxenTreeItem; checked: boolean }>) => {\n const { item, checked } = event.detail;\n this._selectItem(item, checked);\n };\n\n private _handleRowActivate(item: LuxenTreeItem) {\n if (item.disabled) return;\n\n switch (this.selection) {\n case 'single':\n this._setSingleSelection(item);\n break;\n case 'leaf':\n if (item.isLeaf()) this._setSingleSelection(item);\n else item.toggle();\n break;\n case 'multiple':\n this._selectItem(item, !item.selected);\n break;\n case 'none':\n item.toggle();\n break;\n }\n }\n\n private _setSingleSelection(item: LuxenTreeItem) {\n for (const i of this.getAllItems()) {\n if (i !== item && i.selected) i.selected = false;\n }\n item.selected = true;\n this._emitSelectionChange();\n }\n\n private _selectItem(item: LuxenTreeItem, value: boolean) {\n if (item.disabled) return;\n item.selected = value;\n\n if (this.selection === 'multiple' && !this.independent) {\n // Cascade DOWN: toggling a branch toggles all descendants.\n this._setSubtreeSelection(item, value);\n }\n\n item.indeterminate = false;\n this._updateBranchStates();\n this._emitSelectionChange();\n }\n\n private _setSubtreeSelection(item: LuxenTreeItem, value: boolean) {\n for (const child of item.getChildrenItems()) {\n if (child.disabled) continue;\n child.selected = value;\n child.indeterminate = false;\n this._setSubtreeSelection(child, value);\n }\n }\n\n /** Propagate child state UP to parents (indeterminate / auto-checked). */\n private _updateBranchStates() {\n if (this.selection !== 'multiple' || this.independent) {\n // In independent or non-multiple modes, clear any indeterminate flags.\n for (const i of this.getAllItems()) i.indeterminate = false;\n return;\n }\n\n const recompute = (item: LuxenTreeItem): { all: boolean; any: boolean } => {\n const children = item.getChildrenItems({ includeDisabled: false });\n if (children.length === 0) {\n return { all: item.selected, any: item.selected };\n }\n\n let all = true;\n let any = false;\n for (const child of children) {\n const state = recompute(child);\n if (!state.all) all = false;\n if (state.any) any = true;\n }\n\n item.selected = all;\n item.indeterminate = !all && any;\n return { all: all && (item.getChildrenItems().length > 0 ? all : item.selected), any };\n };\n\n for (const root of this._rootItems()) recompute(root);\n }\n\n private _emitSelectionChange() {\n this.emit('selection-change', { detail: { selection: this.getSelection() } });\n }\n\n // --- Keyboard / focus ---\n\n private _onClick = (event: MouseEvent) => {\n const item = this._itemFromEvent(event);\n if (!item || item.disabled) return;\n\n const path = event.composedPath();\n const onCheckbox = path.some((n) => n instanceof HTMLInputElement && n.type === 'checkbox');\n if (onCheckbox) return; // handled via change event\n\n // Clicks on consumer-provided interactive elements (buttons, links, form\n // controls, menu items…) must not toggle the row — the consumer owns that\n // interaction. Works regardless of which slot the element was placed in.\n const INTERACTIVE_TAGS = new Set(['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA']);\n const INTERACTIVE_ROLES = new Set(['button', 'link', 'menuitem', 'menuitemcheckbox']);\n const onInteractive = path.some((n) => {\n if (!(n instanceof HTMLElement) || n === item) return false;\n if (n.getAttribute?.('part') === 'expand-button') return false;\n if (n instanceof HTMLInputElement && n.type === 'checkbox') return false;\n if (INTERACTIVE_TAGS.has(n.tagName)) return true;\n const role = n.getAttribute?.('role');\n return role !== null && INTERACTIVE_ROLES.has(role);\n });\n if (onInteractive) return;\n\n const onExpand = path.some(\n (n) => n instanceof HTMLElement && n.getAttribute?.('part') === 'expand-button',\n );\n\n this._focusItem(item);\n\n if (onExpand) {\n item.toggle();\n return;\n }\n\n // Row click (label area): mode-dependent behaviour.\n switch (this.selection) {\n case 'single':\n this._setSingleSelection(item);\n if (!item.isLeaf()) item.toggle();\n break;\n case 'leaf':\n if (item.isLeaf()) this._setSingleSelection(item);\n else item.toggle();\n break;\n case 'multiple':\n // The whole row acts like a <label> for the checkbox: clicking anywhere\n // on it toggles selection. Use the chevron to expand/collapse branches.\n this._selectItem(item, !item.selected);\n break;\n case 'none':\n item.toggle();\n break;\n }\n };\n\n private _itemFromEvent(event: Event): LuxenTreeItem | null {\n const tag = tagName('tree-item');\n const path = event.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.matches?.(tag)) {\n return node as LuxenTreeItem;\n }\n }\n return null;\n }\n\n private _focusItem(item: LuxenTreeItem) {\n const visible = this._visibleItems();\n for (const i of visible) i.tabIndex = -1;\n item.tabIndex = 0;\n item.focus();\n this._lastFocusedItem = item;\n }\n\n private _onFocusIn = (event: FocusEvent) => {\n const target = event.target;\n if (target instanceof HTMLElement) {\n const item = target.closest(tagName('tree-item')) as LuxenTreeItem | null;\n if (item) this._lastFocusedItem = item;\n }\n };\n\n private _onKeyDown = (event: KeyboardEvent) => {\n const current = this._lastFocusedItem ?? this._visibleItems()[0];\n if (!current) return;\n\n const visible = this._visibleItems();\n const index = visible.indexOf(current);\n\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault();\n const next = visible[Math.min(index + 1, visible.length - 1)];\n if (next) this._focusItem(next);\n break;\n }\n case 'ArrowUp': {\n event.preventDefault();\n const prev = visible[Math.max(index - 1, 0)];\n if (prev) this._focusItem(prev);\n break;\n }\n case 'ArrowRight': {\n event.preventDefault();\n if (!current.isLeaf() && !current.expanded) {\n current.expanded = true;\n } else if (current.expanded) {\n const first = current.getChildrenItems()[0];\n if (first) this._focusItem(first);\n }\n break;\n }\n case 'ArrowLeft': {\n event.preventDefault();\n if (current.expanded && !current.isLeaf()) {\n current.expanded = false;\n } else {\n const parent = current.parentElement?.closest(\n tagName('tree-item'),\n ) as LuxenTreeItem | null;\n if (parent) this._focusItem(parent);\n }\n break;\n }\n case 'Home': {\n event.preventDefault();\n if (visible[0]) this._focusItem(visible[0]);\n break;\n }\n case 'End': {\n event.preventDefault();\n const last = visible[visible.length - 1];\n if (last) this._focusItem(last);\n break;\n }\n case 'Enter':\n case ' ': {\n event.preventDefault();\n this._handleRowActivate(current);\n break;\n }\n case '*': {\n event.preventDefault();\n // Expand all siblings of the current item.\n const siblings = (\n current.parentElement\n ? (Array.from(current.parentElement.children) as LuxenTreeItem[])\n : []\n ).filter((el) => el.tagName === tagName('tree-item').toUpperCase());\n for (const sib of siblings) {\n if (!sib.isLeaf()) sib.expanded = true;\n }\n break;\n }\n }\n };\n\n override render() {\n return html`\n <div\n class=\"tree\"\n part=\"base\"\n role=\"tree\"\n aria-multiselectable=${this.selection === 'multiple' ? 'true' : 'false'}\n @click=${this._onClick}\n @keydown=${this._onKeyDown}\n @focusin=${this._onFocusIn}\n >\n <slot></slot>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tree-item/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,cAAc,aAAa,CAAC;AAG5B,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,aAAa,CAAC;KAC9B;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/html/elements/tree-item/index.ts"],"sourcesContent":["import { define } from '../../define';\nimport { LuxenTreeItem } from './tree-item';\nexport * from './tree-item';\ndefine('tree-item', LuxenTreeItem);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'l-tree-item': LuxenTreeItem;\n }\n}\n"],"mappings":"wFAGA,EAAO,YAAa,EAAc"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
2
|
+
import { LuxenElement } from '../../shared/luxen-element';
|
|
3
|
+
/**
|
|
4
|
+
* A node inside `<l-tree>`. Nested `<l-tree-item>` children become sub-nodes.
|
|
5
|
+
*
|
|
6
|
+
* @slot - Label content (kept to a single row).
|
|
7
|
+
* @slot prefix - Leading content before the label (e.g. icon).
|
|
8
|
+
* @slot suffix - Trailing content.
|
|
9
|
+
* @slot expand-icon - Icon shown when the item is collapsed.
|
|
10
|
+
* @slot collapse-icon - Icon shown when the item is expanded.
|
|
11
|
+
* @slot content - Block content that belongs to the item but not to its header row (e.g. comment body, action bar). Hidden when a branch is collapsed.
|
|
12
|
+
*
|
|
13
|
+
* @csspart base - The item row.
|
|
14
|
+
* @csspart expand-button - The chevron toggle area.
|
|
15
|
+
* @csspart checkbox - The native checkbox input.
|
|
16
|
+
* @csspart label - The label container.
|
|
17
|
+
* @csspart branch - Wrapper around the content and children slots; carries the indent guide.
|
|
18
|
+
* @csspart content - The content slot wrapper (block area between the row and the children).
|
|
19
|
+
* @csspart children - The nested items container.
|
|
20
|
+
*
|
|
21
|
+
* @cssproperty [--_depth] - Internal depth index driving indentation. Set by `<l-tree>`.
|
|
22
|
+
*
|
|
23
|
+
* Layout tokens (`--chevron-size`, `--row-height`, `--row-padding-inline`, `--item-gap`) live on `<l-tree>` and cascade down — see its CSS custom properties.
|
|
24
|
+
*
|
|
25
|
+
* @event expand - Fired when the item is expanded.
|
|
26
|
+
* @event collapse - Fired when the item is collapsed.
|
|
27
|
+
* @event lazy-load - Fired when a lazy item is expanded for the first time. Consumers should append children and set `lazy=false`.
|
|
28
|
+
*/
|
|
29
|
+
export declare class LuxenTreeItem extends LuxenElement {
|
|
30
|
+
static styles: import('lit').CSSResult[];
|
|
31
|
+
private _internals;
|
|
32
|
+
private _childObserver?;
|
|
33
|
+
/** Whether the item is expanded. */
|
|
34
|
+
accessor expanded: boolean;
|
|
35
|
+
/** Whether the item is selected. */
|
|
36
|
+
accessor selected: boolean;
|
|
37
|
+
/** Whether the checkbox is indeterminate (some descendants selected). */
|
|
38
|
+
accessor indeterminate: boolean;
|
|
39
|
+
/** Whether the item is disabled. */
|
|
40
|
+
accessor disabled: boolean;
|
|
41
|
+
/** Marks this item as having children that will be loaded on first expand. */
|
|
42
|
+
accessor lazy: boolean;
|
|
43
|
+
/** Whether the item is currently loading (shows a spinner). */
|
|
44
|
+
accessor loading: boolean;
|
|
45
|
+
/** Set by `<l-tree>`: whether a checkbox is shown. */
|
|
46
|
+
set showCheckbox(value: boolean);
|
|
47
|
+
get showCheckbox(): boolean;
|
|
48
|
+
private _showCheckbox;
|
|
49
|
+
/** Set by `<l-tree>`: depth of the item in the tree (0 = root). */
|
|
50
|
+
set depth(value: number);
|
|
51
|
+
get depth(): number;
|
|
52
|
+
private _depth;
|
|
53
|
+
/** Whether this item has nested tree-item children. */
|
|
54
|
+
get hasChildren(): boolean;
|
|
55
|
+
private _hasChildren;
|
|
56
|
+
/** Returns the child `<l-tree-item>` elements directly under this one. */
|
|
57
|
+
getChildrenItems({ includeDisabled }?: {
|
|
58
|
+
includeDisabled?: boolean | undefined;
|
|
59
|
+
}): LuxenTreeItem[];
|
|
60
|
+
/** Returns true if this item has no expandable children. */
|
|
61
|
+
isLeaf(): boolean;
|
|
62
|
+
/** Returns the text label of this item. */
|
|
63
|
+
getTextLabel(): string;
|
|
64
|
+
connectedCallback(): void;
|
|
65
|
+
disconnectedCallback(): void;
|
|
66
|
+
updated(changed: PropertyValues<this>): void;
|
|
67
|
+
private _setState;
|
|
68
|
+
private _syncChildren;
|
|
69
|
+
/** Toggle expand state. Emits `lazy-load` the first time a lazy item opens. */
|
|
70
|
+
toggle(): void;
|
|
71
|
+
private _onCheckboxChange;
|
|
72
|
+
render(): import('lit').TemplateResult<1>;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=tree-item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-item.d.ts","sourceRoot":"","sources":["../../../src/html/elements/tree-item/tree-item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAO1D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAgB,MAAM,4BAAwB;IAE9C,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAAC,CAAmB;IAE1C,oCAAoC;IAEpC,QAAQ,CAAC,QAAQ,UAAS;IAE1B,oCAAoC;IAEpC,QAAQ,CAAC,QAAQ,UAAS;IAE1B,yEAAyE;IAEzE,QAAQ,CAAC,aAAa,UAAS;IAE/B,oCAAoC;IAEpC,QAAQ,CAAC,QAAQ,UAAS;IAE1B,8EAA8E;IAE9E,QAAQ,CAAC,IAAI,UAAS;IAEtB,+DAA+D;IAE/D,QAAQ,CAAC,OAAO,UAAS;IAEzB,sDAAsD;IACtD,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAG9B;IACD,IAAI,YAAY,IAAI,OAAO,CAE1B;IACD,OAAO,CAAC,aAAa,CAAS;IAE9B,mEAAmE;IACnE,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAGtB;IACD,IAAI,KAAK,IAAI,MAAM,CAElB;IACD,OAAO,CAAC,MAAM,CAAK;IAEnB,uDAAuD;IACvD,IAAI,WAAW,IAAI,OAAO,CAEzB;IACD,OAAO,CAAC,YAAY,CAAS;IAE7B,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,eAAsB,EAAE;;KAAK,GAAG,aAAa,EAAE;IAOlE,4DAA4D;IAC5D,MAAM,IAAI,OAAO;IAIjB,2CAA2C;IAC3C,YAAY,IAAI,MAAM;IAUb,iBAAiB;IAQjB,oBAAoB;IAKpB,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAe9C,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,aAAa;IAmBrB,+EAA+E;IAC/E,MAAM;IASN,OAAO,CAAC,iBAAiB,CAUvB;IAEO,MAAM;CAwFhB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import{tagName as e}from"../../registry.js";import{c as t,i as n}from"../../chunks/lit.js";import{LuxenElement as r}from"../../shared/luxen-element.js";import{a as i,t as a}from"../../chunks/decorate.js";import o from"../../shared/styles/host.styles.js";var s=t(`:host{color:var(--l-color-text-primary,CanvasText);font-size:.875rem;line-height:1.5;display:block}:host([disabled]){opacity:.4}:host([disabled]) .item{cursor:not-allowed}.item{align-items:center;gap:var(--item-gap);min-block-size:var(--row-height);padding-inline:var(--row-padding-inline);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.375rem;padding-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline));transition:background-color .12s,color .12s;display:flex;position:relative}.item:focus-visible,:host(:focus-visible) .item{outline:2px solid var(--l-focus-ring,Highlight);outline-offset:1px}@media (hover:hover){:host(:not([disabled])) .item:hover{background-color:var(--l-color-bg-state-hover)}}:host([selected]:not([disabled])) .item{background-color:var(--l-color-bg-state-selected)}.expand{inline-size:var(--chevron-size);block-size:var(--chevron-size);color:var(--l-color-text-secondary,CanvasText);cursor:pointer;border-radius:3px;flex:none;place-items:center;display:grid}:host(:not(:state(has-children)):not([lazy])) .expand>svg{display:none}.expand svg{width:100%;height:100%;display:block}.checkbox{accent-color:var(--l-color-bg-fill-brand,Highlight);cursor:pointer;flex:none;block-size:1rem;inline-size:1rem;margin:0}:host(:not(:state(checkbox))) .checkbox{display:none}.label{text-overflow:ellipsis;white-space:nowrap;flex:1;align-items:center;gap:.375rem;min-inline-size:0;display:flex;overflow:hidden}.label ::slotted(*){min-inline-size:0}.branch{position:relative}.content{padding-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline) + var(--chevron-size) + var(--item-gap));padding-inline-end:var(--row-padding-inline);display:block}:host(:state(has-children):not([expanded])) .content,.children{display:none}:host([expanded]) .children{display:block}.branch:before{content:"";border-inline-start:var(--indent-guide-width) var(--indent-guide-style) var(--indent-guide-color);pointer-events:none;inline-size:0;position:absolute;inset-block:0;inset-inline-start:calc(var(--indent-size) * var(--_depth,0) + var(--row-padding-inline) + (var(--chevron-size) / 2) - (var(--indent-guide-width) / 2))}:host(:not([expanded])) .branch:before,:host(:not(:state(has-children))) .branch:before{display:none}.spinner{border:2px solid var(--l-color-border,currentColor);border-block-start-color:#0000;border-radius:50%;block-size:.875rem;inline-size:.875rem;animation:.7s linear infinite spin}@media (prefers-reduced-motion:reduce){.spinner{animation:none}}@keyframes spin{to{transform:rotate(360deg)}}`),c=class extends r{constructor(...e){super(...e),this._internals=this.attachInternals(),this.#e=!1,this.#t=!1,this.#n=!1,this.#r=!1,this.#i=!1,this.#a=!1,this._showCheckbox=!1,this._depth=0,this._hasChildren=!1,this._onCheckboxChange=e=>{e.stopPropagation();let t=e.target;this.dispatchEvent(new CustomEvent(`l-tree-item-toggle`,{bubbles:!0,composed:!0,detail:{item:this,checked:t.checked}}))}}static{this.styles=[o,s]}#e;get expanded(){return this.#e}set expanded(e){this.#e=e}#t;get selected(){return this.#t}set selected(e){this.#t=e}#n;get indeterminate(){return this.#n}set indeterminate(e){this.#n=e}#r;get disabled(){return this.#r}set disabled(e){this.#r=e}#i;get lazy(){return this.#i}set lazy(e){this.#i=e}#a;get loading(){return this.#a}set loading(e){this.#a=e}set showCheckbox(e){this._showCheckbox=e,this._setState(`checkbox`,e)}get showCheckbox(){return this._showCheckbox}set depth(e){this._depth=e,this.style.setProperty(`--_depth`,String(e))}get depth(){return this._depth}get hasChildren(){return this._hasChildren}getChildrenItems({includeDisabled:t=!0}={}){let n=e(`tree-item`).toUpperCase();return Array.from(this.children).filter(e=>e.tagName===n&&(t||!e.disabled))}isLeaf(){return!this.lazy&&this.getChildrenItems().length===0}getTextLabel(){let e=this.shadowRoot?.querySelector(`slot:not([name])`);return e?e.assignedNodes({flatten:!0}).map(e=>e.textContent??``).join(``).trim():(this.textContent??``).trim()}connectedCallback(){super.connectedCallback(),this._internals.role=`treeitem`,this._childObserver=new MutationObserver(()=>this._syncChildren()),this._childObserver.observe(this,{childList:!0}),this._syncChildren()}disconnectedCallback(){super.disconnectedCallback(),this._childObserver?.disconnect()}updated(e){e.has(`expanded`)&&(this._internals.ariaExpanded=this.isLeaf()?null:String(this.expanded),this.emit(this.expanded?`expand`:`collapse`)),e.has(`selected`)&&(this._internals.ariaSelected=String(this.selected)),e.has(`disabled`)&&(this._internals.ariaDisabled=this.disabled?`true`:null)}_setState(e,t){this._internals.states&&(t?this._internals.states.add(e):this._internals.states.delete(e))}_syncChildren(){let t=e(`tree-item`).toUpperCase(),n=0;for(let e of Array.from(this.children))e.tagName===t&&(n++,e.slot!==`children`&&(e.slot=`children`));this._hasChildren=n>0,this._setState(`has-children`,this._hasChildren),!this._hasChildren&&!this.lazy&&this.expanded&&(this.expanded=!1),this._internals.ariaExpanded=this.isLeaf()?null:String(this.expanded)}toggle(){if(this.isLeaf()&&!this.lazy)return;let e=!this.expanded;e&&this.lazy&&this.emit(`lazy-load`),this.expanded=e}render(){return n`
|
|
2
|
+
<div
|
|
3
|
+
class="item"
|
|
4
|
+
part="base"
|
|
5
|
+
>
|
|
6
|
+
<span
|
|
7
|
+
class="expand"
|
|
8
|
+
part="expand-button"
|
|
9
|
+
aria-hidden="true"
|
|
10
|
+
>
|
|
11
|
+
${this.loading?n`<span
|
|
12
|
+
class="spinner"
|
|
13
|
+
role="status"
|
|
14
|
+
></span>`:this.expanded||this.isLeaf()?n`<slot name="collapse-icon">
|
|
15
|
+
<svg
|
|
16
|
+
viewBox="0 0 16 16"
|
|
17
|
+
fill="none"
|
|
18
|
+
>
|
|
19
|
+
<path
|
|
20
|
+
d="M3.5 6l4.5 5 4.5-5"
|
|
21
|
+
stroke="currentColor"
|
|
22
|
+
stroke-width="1.5"
|
|
23
|
+
stroke-linecap="round"
|
|
24
|
+
stroke-linejoin="round"
|
|
25
|
+
/>
|
|
26
|
+
</svg>
|
|
27
|
+
</slot>`:n`<slot name="expand-icon">
|
|
28
|
+
<svg
|
|
29
|
+
viewBox="0 0 16 16"
|
|
30
|
+
fill="none"
|
|
31
|
+
>
|
|
32
|
+
<path
|
|
33
|
+
d="M6 3.5l5 4.5-5 4.5"
|
|
34
|
+
stroke="currentColor"
|
|
35
|
+
stroke-width="1.5"
|
|
36
|
+
stroke-linecap="round"
|
|
37
|
+
stroke-linejoin="round"
|
|
38
|
+
/>
|
|
39
|
+
</svg>
|
|
40
|
+
</slot>`}
|
|
41
|
+
</span>
|
|
42
|
+
|
|
43
|
+
<input
|
|
44
|
+
class="checkbox"
|
|
45
|
+
part="checkbox"
|
|
46
|
+
type="checkbox"
|
|
47
|
+
tabindex="-1"
|
|
48
|
+
.checked=${this.selected}
|
|
49
|
+
.indeterminate=${this.indeterminate}
|
|
50
|
+
?disabled=${this.disabled}
|
|
51
|
+
@click=${e=>e.stopPropagation()}
|
|
52
|
+
@change=${this._onCheckboxChange}
|
|
53
|
+
/>
|
|
54
|
+
|
|
55
|
+
<slot name="prefix"></slot>
|
|
56
|
+
<span
|
|
57
|
+
class="label"
|
|
58
|
+
part="label"
|
|
59
|
+
><slot></slot
|
|
60
|
+
></span>
|
|
61
|
+
<slot name="suffix"></slot>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div
|
|
65
|
+
class="branch"
|
|
66
|
+
part="branch"
|
|
67
|
+
>
|
|
68
|
+
<div
|
|
69
|
+
class="content"
|
|
70
|
+
part="content"
|
|
71
|
+
>
|
|
72
|
+
<slot name="content"></slot>
|
|
73
|
+
</div>
|
|
74
|
+
<div
|
|
75
|
+
class="children"
|
|
76
|
+
part="children"
|
|
77
|
+
role="group"
|
|
78
|
+
>
|
|
79
|
+
<slot name="children"></slot>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
`}};a([i({type:Boolean,reflect:!0})],c.prototype,`expanded`,null),a([i({type:Boolean,reflect:!0})],c.prototype,`selected`,null),a([i({type:Boolean,reflect:!0})],c.prototype,`indeterminate`,null),a([i({type:Boolean,reflect:!0})],c.prototype,`disabled`,null),a([i({type:Boolean,reflect:!0})],c.prototype,`lazy`,null),a([i({type:Boolean,reflect:!0})],c.prototype,`loading`,null);export{c as LuxenTreeItem};
|
|
83
|
+
//# sourceMappingURL=tree-item.js.map
|