@ahrowe/ui 0.13.0 → 0.14.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.
Files changed (84) hide show
  1. package/dist/esm/common/animatedIcon/animatedIcon.mjs +2 -0
  2. package/dist/esm/common/animatedIcon/animatedIcon.mjs.map +1 -0
  3. package/dist/esm/common/animatedIcon/animatedIcon.module.mjs +2 -0
  4. package/dist/esm/common/animatedIcon/animatedIcon.module.mjs.map +1 -0
  5. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  6. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  7. package/dist/esm/common/buttonGroup/buttonGroup.mjs +2 -0
  8. package/dist/esm/common/buttonGroup/buttonGroup.mjs.map +1 -0
  9. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs +2 -0
  10. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs.map +1 -0
  11. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs +2 -0
  12. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs.map +1 -0
  13. package/dist/esm/common/divider/divider.mjs +1 -1
  14. package/dist/esm/common/divider/divider.mjs.map +1 -1
  15. package/dist/esm/common/divider/divider.module.mjs +1 -1
  16. package/dist/esm/common/divider/divider.module.mjs.map +1 -1
  17. package/dist/esm/common/divider/divider.types.mjs +1 -1
  18. package/dist/esm/common/divider/divider.types.mjs.map +1 -1
  19. package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
  20. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  21. package/dist/esm/common/fab/fab.mjs +1 -1
  22. package/dist/esm/common/fab/fab.mjs.map +1 -1
  23. package/dist/esm/common/floatingMenu/floatingMenu.mjs +1 -1
  24. package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +1 -1
  25. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +1 -1
  26. package/dist/esm/common/hooks/useFocusBoundary.mjs +2 -0
  27. package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -0
  28. package/dist/esm/common/input/input.mjs +1 -1
  29. package/dist/esm/common/input/input.mjs.map +1 -1
  30. package/dist/esm/common/input/input.module.mjs +1 -1
  31. package/dist/esm/common/input/input.module.mjs.map +1 -1
  32. package/dist/esm/common/input/input.types.mjs +1 -1
  33. package/dist/esm/common/input/input.types.mjs.map +1 -1
  34. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  35. package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
  36. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  37. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  38. package/dist/esm/common/popover/popover.mjs +1 -1
  39. package/dist/esm/common/popover/popover.mjs.map +1 -1
  40. package/dist/esm/common/splitButton/splitButton.mjs +2 -0
  41. package/dist/esm/common/splitButton/splitButton.mjs.map +1 -0
  42. package/dist/esm/common/splitButton/splitButton.module.mjs +2 -0
  43. package/dist/esm/common/splitButton/splitButton.module.mjs.map +1 -0
  44. package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
  45. package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
  46. package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
  47. package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
  48. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  49. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  50. package/dist/esm/common/virtualList/virtualRow.mjs +1 -1
  51. package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -1
  52. package/dist/esm/index.mjs +1 -1
  53. package/dist/index.cjs +4 -4
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/style.css +1 -1
  56. package/dist/types/package/common/animatedIcon/animatedIcon.d.ts +3 -0
  57. package/dist/types/package/common/animatedIcon/animatedIcon.types.d.ts +25 -0
  58. package/dist/types/package/common/animatedIcon/index.d.ts +2 -0
  59. package/dist/types/package/common/buttonGroup/buttonGroup.d.ts +4 -0
  60. package/dist/types/package/common/buttonGroup/buttonGroup.types.d.ts +12 -0
  61. package/dist/types/package/common/buttonGroup/index.d.ts +2 -0
  62. package/dist/types/package/common/configProvider/configProvider.types.d.ts +2 -0
  63. package/dist/types/package/common/divider/divider.types.d.ts +5 -0
  64. package/dist/types/package/common/hooks/useFocusBoundary.d.ts +20 -0
  65. package/dist/types/package/common/input/input.types.d.ts +5 -0
  66. package/dist/types/package/common/splitButton/index.d.ts +2 -0
  67. package/dist/types/package/common/splitButton/splitButton.d.ts +3 -0
  68. package/dist/types/package/common/splitButton/splitButton.types.d.ts +28 -0
  69. package/dist/types/package/common/themeProvider/theme.types.d.ts +1 -0
  70. package/dist/types/package/common/virtualList/useRowDrag.d.ts +4 -0
  71. package/dist/types/package/common/virtualList/useVirtualWindow.d.ts +3 -1
  72. package/dist/types/package/common/virtualList/virtualList.types.d.ts +5 -1
  73. package/dist/types/package/common/virtualList/virtualRow.d.ts +8 -1
  74. package/dist/types/package/index.d.ts +4 -0
  75. package/docs/ButtonGroup.md +90 -0
  76. package/docs/CLAUDE.md +2 -0
  77. package/docs/Divider.md +15 -3
  78. package/docs/FloatingMenu.md +7 -3
  79. package/docs/Input.md +30 -6
  80. package/docs/NumberInput.md +2 -0
  81. package/docs/SearchInput.md +6 -0
  82. package/docs/SplitButton.md +79 -0
  83. package/docs/VirtualList.md +86 -3
  84. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useVirtualWindow.mjs","names":[],"sources":["../../../../package/common/virtualList/useVirtualWindow.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from 'react';\n\nimport { buildOffsets, findStartIndex, getVisibleRange } from './virtualList.utils';\nimport type { VirtualListHandle, VirtualListScrollOptions } from './virtualList.types';\n\n/**\n * Resolve a `rowGap` value to pixels for the offset math. Numbers and plain\n * `px`/numeric strings parse directly (no DOM, SSR/test-safe); any other CSS\n * length (`em`, `rem`, `%`, `var(...)`) is resolved via a hidden probe appended\n * to `contextEl` so it inherits the list's font-size and custom properties.\n */\nfunction resolveCssLength(value: number | string, contextEl: HTMLElement | null): number {\n if (typeof value === 'number') return value;\n const trimmed = value.trim();\n if (trimmed === '') return 0;\n const asNumber = Number(trimmed);\n if (!Number.isNaN(asNumber)) return asNumber; // \"8\" → 8\n const pxMatch = /^(-?\\d*\\.?\\d+)px$/.exec(trimmed);\n if (pxMatch) return parseFloat(pxMatch[1]); // \"8px\" → 8\n if (typeof document === 'undefined' || !contextEl) return 0;\n const probe = document.createElement('div');\n probe.style.cssText = `position:absolute;visibility:hidden;height:${trimmed};`;\n contextEl.appendChild(probe);\n const px = probe.getBoundingClientRect().height;\n contextEl.removeChild(probe);\n return Number.isFinite(px) ? px : 0;\n}\n\ninterface UseVirtualWindowArgs<T> {\n items: T[];\n /** Stable key per row (already derived by the caller). */\n keys: (string | number)[];\n getItemKey?: (item: T, index: number) => string | number;\n estimatedRowHeight: number;\n rowGap: number | string;\n overscan: number;\n onLoadMore?: () => Promise<void>;\n loadMoreThreshold: number;\n}\n\ninterface UseVirtualWindowResult {\n rootRef: React.RefObject<HTMLDivElement | null>;\n headerRef: React.RefObject<HTMLDivElement | null>;\n /** Shared by every row to measure its height (read back via `data-index`). */\n rowObserver: ResizeObserver | null;\n /** Latest index → key mapping, for async consumers (e.g. the drag hook). */\n keysRef: React.RefObject<(string | number)[]>;\n offsets: number[];\n totalHeight: number;\n containerHeight: number;\n containerWidth: number;\n startIndex: number;\n endIndex: number;\n handleScroll: (e: React.UIEvent<HTMLDivElement>) => void;\n showLoadMoreSpinner: boolean;\n /** The scroll-related imperative methods, for the component to compose into\n * the forwarded handle alongside column controls. */\n scrollApi: Omit<VirtualListHandle, 'recalculateColumns'>;\n}\n\n/**\n * The generic virtualization engine: viewport measurement, per-row height\n * caching, offset/visible-range computation, scroll coalescing, scroll\n * anchoring on height changes, infinite-load triggering, and the imperative\n * scroll handle. Mode-agnostic — knows nothing about columns, selection or\n * dragging.\n */\nexport function useVirtualWindow<T>({\n items,\n keys,\n getItemKey,\n estimatedRowHeight,\n rowGap,\n overscan,\n onLoadMore,\n loadMoreThreshold,\n}: UseVirtualWindowArgs<T>): UseVirtualWindowResult {\n const [scrollTop, setScrollTop] = useState(0);\n const [containerHeight, setContainerHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n // rowGap may be any CSS length; resolve it to px for the offset math. Seed with\n // the synchronous fast path (number / px), then refine before paint for units\n // that need the DOM (em/rem/%/var).\n const [resolvedRowGap, setResolvedRowGap] = useState<number>(() => resolveCssLength(rowGap, null));\n const [heightsMap, setHeightsMap] = useState<Map<string | number, number>>(new Map());\n const [showLoadMoreSpinner, setShowLoadMoreSpinner] = useState(false);\n const isLoadingMoreRef = useRef(false);\n\n const rootRef = useRef<HTMLDivElement>(null);\n const headerRef = useRef<HTMLDivElement>(null);\n const prevOffsetsRef = useRef<number[]>([]);\n const scrollRafRef = useRef<number | null>(null);\n const pendingScrollTopRef = useRef(0);\n const keysRef = useRef<(string | number)[]>([]);\n\n // One ResizeObserver shared by every row, created once via a lazy state\n // initializer so rows mounting in the same commit can register in their\n // layout effect. Batching all entries into a single setState avoids a\n // re-render per row when many rows enter the viewport at once (the main\n // source of scroll jank). The row index is read back from `data-index`.\n const [rowObserver] = useState<ResizeObserver | null>(() => {\n if (typeof ResizeObserver === 'undefined') return null;\n return new ResizeObserver((entries) => {\n setHeightsMap((prev) => {\n let next: Map<string | number, number> | null = null;\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const idx = Number(el.dataset.index);\n if (Number.isNaN(idx)) continue;\n // Resolve the row's stable key so the cache survives reorders/filters.\n const key = keysRef.current[idx];\n if (key === undefined) continue;\n // Prefer the size the observer already computed — reading offsetHeight\n // here would force a synchronous reflow on every measurement batch.\n const box = entry.borderBoxSize?.[0];\n const h = box ? Math.round(box.blockSize) : el.offsetHeight;\n if (prev.get(key) === h) continue;\n if (!next) next = new Map(prev);\n next.set(key, h);\n }\n return next ?? prev;\n });\n });\n });\n useEffect(() => () => rowObserver?.disconnect(), [rowObserver]);\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (!el) return;\n // Measure synchronously before the first paint so the initial render fills\n // the viewport, instead of painting a few overscan rows and re-rendering.\n setContainerHeight(el.clientHeight);\n setContainerWidth(el.clientWidth);\n // Track width too: `fit` columns are measured against this box and capped at\n // its width, so when the container settles to its real width after a route\n // transition / async layout, that change has to re-trigger the measure —\n // otherwise an early measure against a 0/tiny width gets pinned and sticks.\n const observer = new ResizeObserver(() => {\n setContainerHeight(el.clientHeight);\n setContainerWidth(el.clientWidth);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget;\n // Coalesce scroll-driven re-renders to at most one per animation frame.\n // Scroll events can fire several times per frame (especially while dragging\n // the scrollbar thumb); rendering the visible window once per frame keeps\n // the content in step with the cursor instead of lagging behind.\n pendingScrollTopRef.current = el.scrollTop;\n if (scrollRafRef.current == null) {\n scrollRafRef.current = requestAnimationFrame(() => {\n scrollRafRef.current = null;\n setScrollTop(pendingScrollTopRef.current);\n });\n }\n\n if (onLoadMore && !isLoadingMoreRef.current) {\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - loadMoreThreshold) {\n isLoadingMoreRef.current = true;\n setShowLoadMoreSpinner(true);\n onLoadMore().finally(() => {\n isLoadingMoreRef.current = false;\n setShowLoadMoreSpinner(false);\n });\n }\n }\n }, [onLoadMore, loadMoreThreshold]);\n\n useEffect(() => () => {\n if (scrollRafRef.current != null) cancelAnimationFrame(scrollRafRef.current);\n }, []);\n\n useLayoutEffect(() => {\n keysRef.current = keys;\n });\n\n // Resolve the gap to px before paint, re-running when the value or the\n // container's layout changes (a theme/font change that alters em/var is caught\n // by the container ResizeObserver feeding containerWidth/Height).\n useLayoutEffect(() => {\n const px = resolveCssLength(rowGap, rootRef.current);\n setResolvedRowGap((prev) => (prev === px ? prev : px));\n }, [rowGap, containerWidth, containerHeight]);\n\n const { offsets, totalHeight } = useMemo(\n () => buildOffsets(keys, heightsMap, estimatedRowHeight, resolvedRowGap),\n [keys, heightsMap, estimatedRowHeight, resolvedRowGap],\n );\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n const prevOffsets = prevOffsetsRef.current;\n prevOffsetsRef.current = offsets;\n\n // Nothing to anchor against on the first pass or when pinned at the top.\n if (!el || prevOffsets.length === 0) return;\n const curScrollTop = el.scrollTop;\n if (curScrollTop <= 0) return;\n\n // Scroll anchoring: pin the row at the top of the viewport. Find it under\n // the *previous* offsets, then re-derive scrollTop from its *new* offset so\n // it stays visually fixed when rows above it are measured or resized. This\n // is more robust than summing per-row height deltas — it can't drift, and\n // one correction covers any number of simultaneous changes above the fold.\n const prevCount = prevOffsets.length - 1;\n const anchor = findStartIndex(prevOffsets, curScrollTop, prevCount);\n if (anchor >= items.length) return;\n const within = curScrollTop - prevOffsets[anchor];\n const target = offsets[anchor] + within;\n if (Math.abs(target - curScrollTop) > 0.5) {\n el.scrollTop = target;\n pendingScrollTopRef.current = target;\n setScrollTop(target);\n }\n }, [offsets, items.length]);\n\n const scrollApi = useMemo<Omit<VirtualListHandle, 'recalculateColumns'>>(() => {\n function scrollToOffset(top: number, behavior?: ScrollBehavior) {\n const el = rootRef.current;\n if (!el) return;\n const clamped = Math.max(0, top);\n if (typeof el.scrollTo === 'function') el.scrollTo({ top: clamped, behavior: behavior ?? 'auto' });\n else el.scrollTop = clamped;\n }\n function scrollToIndex(index: number, options?: VirtualListScrollOptions) {\n const el = rootRef.current;\n if (!el || items.length === 0) return;\n const i = Math.max(0, Math.min(index, items.length - 1));\n const rowTop = offsets[i] ?? 0;\n const rowHeight = (offsets[i + 1] ?? rowTop) - rowTop;\n // The sticky header overlaps the top of the scroll area, so the usable\n // viewport starts below it — account for that when aligning.\n const headerH = headerRef.current?.offsetHeight ?? 0;\n const usable = Math.max(0, el.clientHeight - headerH);\n const align = options?.align ?? 'start';\n let top = rowTop - headerH;\n if (align === 'center') top -= (usable - rowHeight) / 2;\n else if (align === 'end') top -= usable - rowHeight;\n scrollToOffset(top, options?.behavior);\n }\n return {\n scrollToIndex,\n scrollToKey(key, options) {\n const i = items.findIndex((item, idx) => (getItemKey ? getItemKey(item, idx) : idx) === key);\n if (i >= 0) scrollToIndex(i, options);\n },\n scrollToTop(options) {\n scrollToOffset(0, options?.behavior);\n },\n getScrollElement: () => rootRef.current,\n };\n }, [items, offsets, getItemKey]);\n\n const { startIndex, endIndex } = useMemo(\n () => getVisibleRange(offsets, scrollTop, containerHeight, overscan, items.length),\n [offsets, scrollTop, containerHeight, overscan, items.length],\n );\n\n return {\n rootRef,\n headerRef,\n rowObserver,\n keysRef,\n offsets,\n totalHeight,\n containerHeight,\n containerWidth,\n startIndex,\n endIndex,\n handleScroll,\n showLoadMoreSpinner,\n scrollApi,\n };\n}\n"],"mappings":"+MAWA,SAAS,EAAiB,EAAwB,EAAuC,CACvF,GAAI,OAAO,GAAU,SAAU,OAAO,EACtC,IAAM,EAAU,EAAM,KAAK,EAC3B,GAAI,IAAY,GAAI,MAAO,GAC3B,IAAM,EAAW,OAAO,CAAO,EAC/B,GAAI,CAAC,OAAO,MAAM,CAAQ,EAAG,OAAO,EACpC,IAAM,EAAU,oBAAoB,KAAK,CAAO,EAChD,GAAI,EAAS,OAAO,WAAW,EAAQ,EAAE,EACzC,GAAI,OAAO,SAAa,KAAe,CAAC,EAAW,MAAO,GAC1D,IAAM,EAAQ,SAAS,cAAc,KAAK,EAC1C,EAAM,MAAM,QAAU,8CAA8C,EAAQ,GAC5E,EAAU,YAAY,CAAK,EAC3B,IAAM,EAAK,EAAM,sBAAsB,EAAE,OAEzC,OADA,EAAU,YAAY,CAAK,EACpB,OAAO,SAAS,CAAE,EAAI,EAAK,CACpC,CAyCA,SAAgB,EAAoB,CAClC,QACA,OACA,aACA,qBACA,SACA,WACA,aACA,qBACkD,CAClD,GAAM,CAAC,EAAW,GAAgB,EAAS,CAAC,EACtC,CAAC,EAAiB,GAAsB,EAAS,CAAC,EAClD,CAAC,EAAgB,GAAqB,EAAS,CAAC,EAIhD,CAAC,EAAgB,GAAqB,MAAuB,EAAiB,EAAQ,IAAI,CAAC,EAC3F,CAAC,EAAY,GAAiB,EAAuC,IAAI,GAAK,EAC9E,CAAC,EAAqB,GAA0B,EAAS,EAAK,EAC9D,EAAmB,EAAO,EAAK,EAE/B,EAAU,EAAuB,IAAI,EACrC,EAAY,EAAuB,IAAI,EACvC,EAAiB,EAAiB,CAAC,CAAC,EACpC,EAAe,EAAsB,IAAI,EACzC,EAAsB,EAAO,CAAC,EAC9B,EAAU,EAA4B,CAAC,CAAC,EAOxC,CAAC,GAAe,MAChB,OAAO,eAAmB,IAAoB,KAC3C,IAAI,eAAgB,GAAY,CACrC,EAAe,GAAS,CACtB,IAAI,EAA4C,KAChD,IAAK,IAAM,KAAS,EAAS,CAC3B,IAAM,EAAK,EAAM,OACX,EAAM,OAAO,EAAG,QAAQ,KAAK,EACnC,GAAI,OAAO,MAAM,CAAG,EAAG,SAEvB,IAAM,EAAM,EAAQ,QAAQ,GAC5B,GAAI,IAAQ,IAAA,GAAW,SAGvB,IAAM,EAAM,EAAM,gBAAgB,GAC5B,EAAI,EAAM,KAAK,MAAM,EAAI,SAAS,EAAI,EAAG,aAC3C,EAAK,IAAI,CAAG,IAAM,IACtB,AAAW,IAAO,IAAI,IAAI,CAAI,EAC9B,EAAK,IAAI,EAAK,CAAC,EACjB,CACA,OAAO,GAAQ,CACjB,CAAC,CACH,CAAC,CACF,EACD,UAAsB,GAAa,WAAW,EAAG,CAAC,CAAW,CAAC,EAE9D,MAAsB,CACpB,IAAM,EAAK,EAAQ,QACnB,GAAI,CAAC,EAAI,OAGT,EAAmB,EAAG,YAAY,EAClC,EAAkB,EAAG,WAAW,EAKhC,IAAM,EAAW,IAAI,mBAAqB,CACxC,EAAmB,EAAG,YAAY,EAClC,EAAkB,EAAG,WAAW,CAClC,CAAC,EAED,OADA,EAAS,QAAQ,CAAE,MACN,EAAS,WAAW,CACnC,EAAG,CAAC,CAAC,EAEL,IAAM,EAAe,EAAa,GAAqC,CACrE,IAAM,EAAK,EAAE,cAKb,EAAoB,QAAU,EAAG,UACjC,AACE,EAAa,UAAU,0BAA4B,CACjD,EAAa,QAAU,KACvB,EAAa,EAAoB,OAAO,CAC1C,CAAC,EAGC,GAAc,CAAC,EAAiB,SAC9B,EAAG,UAAY,EAAG,cAAgB,EAAG,aAAe,IACtD,EAAiB,QAAU,GAC3B,EAAuB,EAAI,EAC3B,EAAW,EAAE,YAAc,CACzB,EAAiB,QAAU,GAC3B,EAAuB,EAAK,CAC9B,CAAC,EAGP,EAAG,CAAC,EAAY,CAAiB,CAAC,EAElC,UAAsB,CAChB,EAAa,SAAW,MAAM,qBAAqB,EAAa,OAAO,CAC7E,EAAG,CAAC,CAAC,EAEL,MAAsB,CACpB,EAAQ,QAAU,CACpB,CAAC,EAKD,MAAsB,CACpB,IAAM,EAAK,EAAiB,EAAQ,EAAQ,OAAO,EACnD,EAAmB,GAAU,IAAS,EAAK,EAAO,CAAG,CACvD,EAAG,CAAC,EAAQ,EAAgB,CAAe,CAAC,EAE5C,GAAM,CAAE,UAAS,eAAgB,MACzB,EAAa,EAAM,EAAY,EAAoB,CAAc,EACvE,CAAC,EAAM,EAAY,EAAoB,CAAc,CACvD,EAEA,MAAsB,CACpB,IAAM,EAAK,EAAQ,QACb,EAAc,EAAe,QAInC,GAHA,EAAe,QAAU,EAGrB,CAAC,GAAM,EAAY,SAAW,EAAG,OACrC,IAAM,EAAe,EAAG,UACxB,GAAI,GAAgB,EAAG,OAQvB,IAAM,EAAS,EAAe,EAAa,EADzB,EAAY,OAAS,CAC2B,EAClE,GAAI,GAAU,EAAM,OAAQ,OAC5B,IAAM,EAAS,EAAe,EAAY,GACpC,EAAS,EAAQ,GAAU,EAC7B,KAAK,IAAI,EAAS,CAAY,EAAI,KACpC,EAAG,UAAY,EACf,EAAoB,QAAU,EAC9B,EAAa,CAAM,EAEvB,EAAG,CAAC,EAAS,EAAM,MAAM,CAAC,EAE1B,IAAM,EAAY,MAA6D,CAC7E,SAAS,EAAe,EAAa,EAA2B,CAC9D,IAAM,EAAK,EAAQ,QACnB,GAAI,CAAC,EAAI,OACT,IAAM,EAAU,KAAK,IAAI,EAAG,CAAG,EAC3B,OAAO,EAAG,UAAa,WAAY,EAAG,SAAS,CAAE,IAAK,EAAS,SAAU,GAAY,MAAO,CAAC,EAC5F,EAAG,UAAY,CACtB,CACA,SAAS,EAAc,EAAe,EAAoC,CACxE,IAAM,EAAK,EAAQ,QACnB,GAAI,CAAC,GAAM,EAAM,SAAW,EAAG,OAC/B,IAAM,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,EAAM,OAAS,CAAC,CAAC,EACjD,EAAS,EAAQ,IAAM,EACvB,GAAa,EAAQ,EAAI,IAAM,GAAU,EAGzC,EAAU,EAAU,SAAS,cAAgB,EAC7C,EAAS,KAAK,IAAI,EAAG,EAAG,aAAe,CAAO,EAC9C,EAAQ,GAAS,OAAS,QAC5B,EAAM,EAAS,EACf,IAAU,SAAU,IAAQ,EAAS,GAAa,EAC7C,IAAU,QAAO,GAAO,EAAS,GAC1C,EAAe,EAAK,GAAS,QAAQ,CACvC,CACA,MAAO,CACL,gBACA,YAAY,EAAK,EAAS,CACxB,IAAM,EAAI,EAAM,WAAW,EAAM,KAAS,EAAa,EAAW,EAAM,CAAG,EAAI,KAAS,CAAG,EACvF,GAAK,GAAG,EAAc,EAAG,CAAO,CACtC,EACA,YAAY,EAAS,CACnB,EAAe,EAAG,GAAS,QAAQ,CACrC,EACA,qBAAwB,EAAQ,OAClC,CACF,EAAG,CAAC,EAAO,EAAS,CAAU,CAAC,EAEzB,CAAE,aAAY,YAAa,MACzB,EAAgB,EAAS,EAAW,EAAiB,EAAU,EAAM,MAAM,EACjF,CAAC,EAAS,EAAW,EAAiB,EAAU,EAAM,MAAM,CAC9D,EAEA,MAAO,CACL,UACA,YACA,cACA,UACA,UACA,cACA,kBACA,iBACA,aACA,WACA,eACA,sBACA,WACF,CACF"}
1
+ {"version":3,"file":"useVirtualWindow.mjs","names":[],"sources":["../../../../package/common/virtualList/useVirtualWindow.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from 'react';\n\nimport { buildOffsets, findStartIndex, getVisibleRange } from './virtualList.utils';\nimport type { VirtualListHandle, VirtualListScrollOptions } from './virtualList.types';\n\n/**\n * Resolve a `rowGap` value to pixels for the offset math. Numbers and plain\n * `px`/numeric strings parse directly (no DOM, SSR/test-safe); any other CSS\n * length (`em`, `rem`, `%`, `var(...)`) is resolved via a hidden probe appended\n * to `contextEl` so it inherits the list's font-size and custom properties.\n */\nfunction resolveCssLength(value: number | string, contextEl: HTMLElement | null): number {\n if (typeof value === 'number') return value;\n const trimmed = value.trim();\n if (trimmed === '') return 0;\n const asNumber = Number(trimmed);\n if (!Number.isNaN(asNumber)) return asNumber; // \"8\" → 8\n const pxMatch = /^(-?\\d*\\.?\\d+)px$/.exec(trimmed);\n if (pxMatch) return parseFloat(pxMatch[1]); // \"8px\" → 8\n if (typeof document === 'undefined' || !contextEl) return 0;\n const probe = document.createElement('div');\n probe.style.cssText = `position:absolute;visibility:hidden;height:${trimmed};`;\n contextEl.appendChild(probe);\n const px = probe.getBoundingClientRect().height;\n contextEl.removeChild(probe);\n return Number.isFinite(px) ? px : 0;\n}\n\ninterface UseVirtualWindowArgs<T> {\n items: T[];\n /** Stable key per row (already derived by the caller). */\n keys: (string | number)[];\n getItemKey?: (item: T, index: number) => string | number;\n estimatedRowHeight: number;\n rowGap: number | string;\n overscan: number;\n onLoadMore?: () => Promise<void>;\n loadMoreThreshold: number;\n /** Initial/filter load in progress — the body is replaced by a spinner. */\n isLoading: boolean;\n}\n\ninterface UseVirtualWindowResult {\n rootRef: React.RefObject<HTMLDivElement | null>;\n headerRef: React.RefObject<HTMLDivElement | null>;\n /** Shared by every row to measure its height (read back via `data-index`). */\n rowObserver: ResizeObserver | null;\n /** Latest index → key mapping, for async consumers (e.g. the drag hook). */\n keysRef: React.RefObject<(string | number)[]>;\n offsets: number[];\n totalHeight: number;\n containerHeight: number;\n containerWidth: number;\n startIndex: number;\n endIndex: number;\n handleScroll: (e: React.UIEvent<HTMLDivElement>) => void;\n showLoadMoreSpinner: boolean;\n /** The scroll-related imperative methods, for the component to compose into\n * the forwarded handle alongside column controls. */\n scrollApi: Omit<VirtualListHandle, 'recalculateColumns'>;\n}\n\n/**\n * The generic virtualization engine: viewport measurement, per-row height\n * caching, offset/visible-range computation, scroll coalescing, scroll\n * anchoring on height changes, infinite-load triggering, and the imperative\n * scroll handle. Mode-agnostic — knows nothing about columns, selection or\n * dragging.\n */\nexport function useVirtualWindow<T>({\n items,\n keys,\n getItemKey,\n estimatedRowHeight,\n rowGap,\n overscan,\n onLoadMore,\n loadMoreThreshold,\n isLoading,\n}: UseVirtualWindowArgs<T>): UseVirtualWindowResult {\n const [scrollTop, setScrollTop] = useState(0);\n const [containerHeight, setContainerHeight] = useState(0);\n const [containerWidth, setContainerWidth] = useState(0);\n // rowGap may be any CSS length; resolve it to px for the offset math. Seed with\n // the synchronous fast path (number / px), then refine before paint for units\n // that need the DOM (em/rem/%/var).\n const [resolvedRowGap, setResolvedRowGap] = useState<number>(() => resolveCssLength(rowGap, null));\n const [heightsMap, setHeightsMap] = useState<Map<string | number, number>>(new Map());\n const [showLoadMoreSpinner, setShowLoadMoreSpinner] = useState(false);\n const isLoadingMoreRef = useRef(false);\n\n const rootRef = useRef<HTMLDivElement>(null);\n const headerRef = useRef<HTMLDivElement>(null);\n const prevOffsetsRef = useRef<number[]>([]);\n const scrollRafRef = useRef<number | null>(null);\n const pendingScrollTopRef = useRef(0);\n const keysRef = useRef<(string | number)[]>([]);\n\n // One ResizeObserver shared by every row, created once via a lazy state\n // initializer so rows mounting in the same commit can register in their\n // layout effect. Batching all entries into a single setState avoids a\n // re-render per row when many rows enter the viewport at once (the main\n // source of scroll jank). The row index is read back from `data-index`.\n const [rowObserver] = useState<ResizeObserver | null>(() => {\n if (typeof ResizeObserver === 'undefined') return null;\n return new ResizeObserver((entries) => {\n setHeightsMap((prev) => {\n let next: Map<string | number, number> | null = null;\n for (const entry of entries) {\n const el = entry.target as HTMLElement;\n const idx = Number(el.dataset.index);\n if (Number.isNaN(idx)) continue;\n // Resolve the row's stable key so the cache survives reorders/filters.\n const key = keysRef.current[idx];\n if (key === undefined) continue;\n // Prefer the size the observer already computed — reading offsetHeight\n // here would force a synchronous reflow on every measurement batch.\n const box = entry.borderBoxSize?.[0];\n const h = box ? Math.round(box.blockSize) : el.offsetHeight;\n if (prev.get(key) === h) continue;\n if (!next) next = new Map(prev);\n next.set(key, h);\n }\n return next ?? prev;\n });\n });\n });\n useEffect(() => () => rowObserver?.disconnect(), [rowObserver]);\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n if (!el) return;\n // Measure synchronously before the first paint so the initial render fills\n // the viewport, instead of painting a few overscan rows and re-rendering.\n setContainerHeight(el.clientHeight);\n setContainerWidth(el.clientWidth);\n // Track width too: `fit` columns are measured against this box and capped at\n // its width, so when the container settles to its real width after a route\n // transition / async layout, that change has to re-trigger the measure —\n // otherwise an early measure against a 0/tiny width gets pinned and sticks.\n const observer = new ResizeObserver(() => {\n setContainerHeight(el.clientHeight);\n setContainerWidth(el.clientWidth);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n // Read through a ref so the trigger below stays stable even when the consumer\n // passes a fresh `onLoadMore` closure on every render.\n const onLoadMoreRef = useRef(onLoadMore);\n useLayoutEffect(() => {\n onLoadMoreRef.current = onLoadMore;\n });\n\n /** Start a load unless one is already in flight (and drive the bottom spinner). */\n const triggerLoadMore = useCallback(() => {\n const load = onLoadMoreRef.current;\n if (!load || isLoadingMoreRef.current) return;\n isLoadingMoreRef.current = true;\n setShowLoadMoreSpinner(true);\n load().finally(() => {\n isLoadingMoreRef.current = false;\n setShowLoadMoreSpinner(false);\n });\n }, []);\n\n const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {\n const el = e.currentTarget;\n // Coalesce scroll-driven re-renders to at most one per animation frame.\n // Scroll events can fire several times per frame (especially while dragging\n // the scrollbar thumb); rendering the visible window once per frame keeps\n // the content in step with the cursor instead of lagging behind.\n pendingScrollTopRef.current = el.scrollTop;\n if (scrollRafRef.current == null) {\n scrollRafRef.current = requestAnimationFrame(() => {\n scrollRafRef.current = null;\n setScrollTop(pendingScrollTopRef.current);\n });\n }\n\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - loadMoreThreshold) triggerLoadMore();\n }, [loadMoreThreshold, triggerLoadMore]);\n\n useEffect(() => () => {\n if (scrollRafRef.current != null) cancelAnimationFrame(scrollRafRef.current);\n }, []);\n\n useLayoutEffect(() => {\n keysRef.current = keys;\n });\n\n // Resolve the gap to px before paint, re-running when the value or the\n // container's layout changes (a theme/font change that alters em/var is caught\n // by the container ResizeObserver feeding containerWidth/Height).\n useLayoutEffect(() => {\n const px = resolveCssLength(rowGap, rootRef.current);\n setResolvedRowGap((prev) => (prev === px ? prev : px));\n }, [rowGap, containerWidth, containerHeight]);\n\n const { offsets, totalHeight } = useMemo(\n () => buildOffsets(keys, heightsMap, estimatedRowHeight, resolvedRowGap),\n [keys, heightsMap, estimatedRowHeight, resolvedRowGap],\n );\n\n // The scroll trigger above can only fire on a list that actually scrolls. When\n // a batch is smaller than the viewport there is no overflow, so no scroll event\n // ever happens and lazy loading dead-ends after the first batch. Keep asking\n // for more until the content overflows; the consumer ends the loop by appending\n // nothing (or by dropping `onLoadMore` once its source is exhausted).\n //\n // Each (row count, viewport height) pair is probed at most once, so rows\n // settling to their measured heights can't re-ask a source that already ran\n // dry, and progress depends entirely on the consumer appending rows.\n const fillProbeRef = useRef('');\n useEffect(() => {\n if (!onLoadMore || isLoading || showLoadMoreSpinner) return;\n // 0 while the list is unmeasured or `display: none` — nothing to fill yet.\n if (containerHeight === 0) return;\n // The sticky header eats into the scroll area, so it isn't usable space.\n const headerH = headerRef.current?.offsetHeight ?? 0;\n if (totalHeight >= containerHeight - headerH) return; // already scrollable\n const probe = `${items.length}:${containerHeight}`;\n if (fillProbeRef.current === probe) return;\n fillProbeRef.current = probe;\n triggerLoadMore();\n }, [\n onLoadMore, isLoading, showLoadMoreSpinner,\n items.length, totalHeight, containerHeight, triggerLoadMore,\n ]);\n\n useLayoutEffect(() => {\n const el = rootRef.current;\n const prevOffsets = prevOffsetsRef.current;\n prevOffsetsRef.current = offsets;\n\n // Nothing to anchor against on the first pass or when pinned at the top.\n if (!el || prevOffsets.length === 0) return;\n const curScrollTop = el.scrollTop;\n if (curScrollTop <= 0) return;\n\n // Scroll anchoring: pin the row at the top of the viewport. Find it under\n // the *previous* offsets, then re-derive scrollTop from its *new* offset so\n // it stays visually fixed when rows above it are measured or resized. This\n // is more robust than summing per-row height deltas — it can't drift, and\n // one correction covers any number of simultaneous changes above the fold.\n const prevCount = prevOffsets.length - 1;\n const anchor = findStartIndex(prevOffsets, curScrollTop, prevCount);\n if (anchor >= items.length) return;\n const within = curScrollTop - prevOffsets[anchor];\n const target = offsets[anchor] + within;\n if (Math.abs(target - curScrollTop) > 0.5) {\n el.scrollTop = target;\n pendingScrollTopRef.current = target;\n setScrollTop(target);\n }\n }, [offsets, items.length]);\n\n const scrollApi = useMemo<Omit<VirtualListHandle, 'recalculateColumns'>>(() => {\n function scrollToOffset(top: number, behavior?: ScrollBehavior) {\n const el = rootRef.current;\n if (!el) return;\n const clamped = Math.max(0, top);\n if (typeof el.scrollTo === 'function') el.scrollTo({ top: clamped, behavior: behavior ?? 'auto' });\n else el.scrollTop = clamped;\n }\n function scrollToIndex(index: number, options?: VirtualListScrollOptions) {\n const el = rootRef.current;\n if (!el || items.length === 0) return;\n const i = Math.max(0, Math.min(index, items.length - 1));\n const rowTop = offsets[i] ?? 0;\n const rowHeight = (offsets[i + 1] ?? rowTop) - rowTop;\n // The sticky header overlaps the top of the scroll area, so the usable\n // viewport starts below it — account for that when aligning.\n const headerH = headerRef.current?.offsetHeight ?? 0;\n const usable = Math.max(0, el.clientHeight - headerH);\n const align = options?.align ?? 'start';\n let top = rowTop - headerH;\n if (align === 'center') top -= (usable - rowHeight) / 2;\n else if (align === 'end') top -= usable - rowHeight;\n scrollToOffset(top, options?.behavior);\n }\n return {\n scrollToIndex,\n scrollToKey(key, options) {\n const i = items.findIndex((item, idx) => (getItemKey ? getItemKey(item, idx) : idx) === key);\n if (i >= 0) scrollToIndex(i, options);\n },\n scrollToTop(options) {\n scrollToOffset(0, options?.behavior);\n },\n getScrollElement: () => rootRef.current,\n };\n }, [items, offsets, getItemKey]);\n\n const { startIndex, endIndex } = useMemo(\n () => getVisibleRange(offsets, scrollTop, containerHeight, overscan, items.length),\n [offsets, scrollTop, containerHeight, overscan, items.length],\n );\n\n return {\n rootRef,\n headerRef,\n rowObserver,\n keysRef,\n offsets,\n totalHeight,\n containerHeight,\n containerWidth,\n startIndex,\n endIndex,\n handleScroll,\n showLoadMoreSpinner,\n scrollApi,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"../loading/spinnerLoading/index.mjs";import{Align as t}from"../floatingMenu/floatingMenu.types.mjs";import n from"../floatingMenu/floatingMenu.mjs";import r from"../checkbox/checkbox.mjs";import i from"./virtualList.module.mjs";import ee from"./virtualRow.mjs";import"./virtualList.utils.mjs";import{useVirtualWindow as a}from"./useVirtualWindow.mjs";import{useSelection as o}from"./useSelection.mjs";import{useColumns as s}from"./useColumns.mjs";import{useRowDrag as te}from"./useRowDrag.mjs";import c,{useCallback as l,useImperativeHandle as ne,useMemo as u}from"react";import d from"classnames";import{FontAwesomeIcon as re}from"@fortawesome/react-fontawesome";import{faGear as ie}from"@fortawesome/free-solid-svg-icons";import{Fragment as f,jsx as p,jsxs as m}from"react/jsx-runtime";function h({items:c,renderRow:h,columns:g,height:_=`100%`,estimatedRowHeight:ae=40,overscan:oe=3,rowGap:se=0,rowPadding:v,selectedKey:y,getItemKey:b,onRowClick:ce,visibleColumnKeys:le,onVisibleColumnsChange:ue,persistColumnsKey:de,showColumnToggle:fe,onLoadMore:x,loadMoreThreshold:pe=100,isLoading:me=!1,multiSelect:S=!1,selectedKeys:he,onSelectionChange:ge,reorderable:_e=!1,onReorder:ve,longPressDelay:ye=400,treeReorder:C=!1,getItemDepth:w,isGroup:T,onTreeDrop:E,treeIndentPx:D=24,dragHandle:O=!1,showDivider:k=!0,rowHover:A=!0,className:j,style:M,classNames:N,styles:P,...be},xe){let F=l((e,t)=>b?b(e,t):t,[b]),I=u(()=>c.map((e,t)=>F(e,t)),[c,F]),L=u(()=>w?c.map((e,t)=>w(e,t)):[],[c,w]),Se=l(e=>T?T(c[e],e):!1,[T,c]),R=a({items:c,keys:I,getItemKey:b,estimatedRowHeight:ae,rowGap:se,overscan:oe,onLoadMore:x,loadMoreThreshold:pe}),{rootRef:z,headerRef:Ce,rowObserver:we,keysRef:Te,offsets:Ee,totalHeight:De,startIndex:B,endIndex:V}=R,H=o({items:c,getKey:F,multiSelect:S,selectedKeys:he,onSelectionChange:ge}),{effectiveSelectedKeys:U}=H,{hasColumns:W,visibleColumns:G,columnTemplate:K,shouldShowToggle:q,effectiveVisible:Oe,manuallyHiddenCount:J,toggleOpen:ke,setToggleOpen:Ae,handleToggleColumn:je,recalculateColumns:Y}=s({columns:g,items:c,multiSelect:S,visibleColumnKeys:le,onVisibleColumnsChange:ue,persistColumnsKey:de,showColumnToggle:fe,rootRef:z,startIndex:B,endIndex:V,containerHeight:R.containerHeight,containerWidth:R.containerWidth});ne(xe,()=>({...R.scrollApi,recalculateColumns:Y}),[R.scrollApi,Y]);let X=te({reorderable:_e,treeReorder:C,onReorder:ve,onTreeDrop:E,longPressDelay:ye,dragHandle:O,treeIndentPx:D,keys:I,depths:L,isGroupAt:Se,rootRef:z,keysRef:Te}),Me=typeof v==`number`?`${v}px`:v,Z=e=>{let t=c[e],n=F(t,e),a=y!=null&&n===y||U.has(n),o=X.getRowDragProps(e,n);return p(ee,{index:e,top:Ee[e],padding:Me,columnTemplate:K,isSelected:a,showDivider:k,hover:A,onClick:()=>{X.consumeSuppressedClick()||ce?.(t,e)},observer:we,ariaRowIndex:W?e+2:void 0,ariaPosInSet:W?void 0:e+1,ariaSetSize:W?void 0:c.length,rowRole:W?`row`:`listitem`,reserveToggleGutter:q,...o,dropIndicatorClassName:N?.dropIndicator,dropIndicatorStyle:P?.dropIndicator,rowClassName:N?.row,rowStyle:P?.row,children:W?m(f,{children:[S&&p(`div`,{className:d(i.virtualListSelectCell,N?.selectCell),style:P?.selectCell,role:`gridcell`,onClick:e=>e.stopPropagation(),children:p(r,{selected:U.has(n),onToggle:()=>H.handleRowSelect(n),"aria-label":`Select row`})}),G.map(n=>p(`div`,{className:d(i.virtualListCell,N?.cell),style:P?.cell,role:`gridcell`,"data-fit-key":n.width.type===`fit`?n.key:void 0,children:n.renderCell(t,e)},n.key))]}):h?.(t,e)},n)},Q=[];for(let e=B;e<=V;e++)Q.push(Z(e));let $=X.draggingKey==null?-1:I.indexOf(X.draggingKey);return $>=0&&($<B||$>V)&&Q.push(Z($)),m(`div`,{...be,ref:z,className:d(i.virtualList,X.draggingKey!=null&&i.virtualListReordering,j,N?.root),style:{height:_,...M,...P?.root},onScroll:R.handleScroll,role:W?`grid`:`list`,"aria-rowcount":W?c.length+1:void 0,children:[W&&m(`div`,{ref:Ce,className:d(i.virtualListHeader,N?.header),style:{gridTemplateColumns:K,...q?{paddingRight:32}:{},...P?.header},role:`row`,"aria-rowindex":1,children:[S&&p(`div`,{className:d(i.virtualListSelectCell,N?.selectCell),style:P?.selectCell,role:`columnheader`,children:p(r,{selected:H.allSelected||H.someSelected,onToggle:H.handleSelectAll,"aria-label":`Select all rows`})}),G.map(e=>p(`div`,{className:d(i.virtualListHeaderCell,N?.headerCell),style:P?.headerCell,role:`columnheader`,"data-fit-key":e.width.type===`fit`?e.key:void 0,children:e.label},e.key)),q&&m(`div`,{className:i.virtualListToggleWrapper,children:[p(n,{isOpen:ke,onOpenChange:Ae,align:t.Right,content:p(`div`,{className:d(i.virtualListTogglePopover,N?.togglePopover),style:P?.togglePopover,children:g.filter(e=>!e.hideFromToggle).map(e=>p(r,{className:d(i.virtualListToggleItem,N?.toggleItem),style:P?.toggleItem,selected:Oe.has(e.key),onToggle:()=>je(e.key),disabled:e.lockVisible,cursorDefault:!1,children:e.toggleLabel??e.label},e.key))}),children:p(`button`,{type:`button`,className:d(i.virtualListHeaderToggle,N?.headerToggle),style:P?.headerToggle,"aria-label":`Toggle column visibility`,children:p(re,{icon:ie,style:P?.headerToggle})})}),J>0&&p(`span`,{className:d(i.virtualListColumnChip,N?.columnChip),style:P?.columnChip,"data-column-hidden-count":J,"aria-label":`${J} columns hidden`,children:J})]})]}),me?p(`div`,{className:i.virtualListLoadingFull,children:p(e,{className:i.virtualListSpinner})}):p(`div`,{className:d(i.virtualListBody,N?.body),style:{height:De,...P?.body},children:Q}),R.showLoadMoreSpinner&&p(`div`,{className:d(i.virtualListLoadingIndicator,N?.loadingIndicator),style:P?.loadingIndicator,children:p(e,{className:i.virtualListSpinner})})]})}var g=c.forwardRef(h);export{g as default};
1
+ import e from"../loading/spinnerLoading/index.mjs";import{Align as t}from"../floatingMenu/floatingMenu.types.mjs";import n from"../floatingMenu/floatingMenu.mjs";import r from"../checkbox/checkbox.mjs";import i from"./virtualList.module.mjs";import ee from"./virtualRow.mjs";import"./virtualList.utils.mjs";import{useVirtualWindow as a}from"./useVirtualWindow.mjs";import{useSelection as o}from"./useSelection.mjs";import{useColumns as s}from"./useColumns.mjs";import{useRowDrag as te}from"./useRowDrag.mjs";import c,{useCallback as l,useImperativeHandle as ne,useMemo as u}from"react";import d from"classnames";import{FontAwesomeIcon as re}from"@fortawesome/react-fontawesome";import{faGear as ie}from"@fortawesome/free-solid-svg-icons";import{Fragment as f,jsx as p,jsxs as m}from"react/jsx-runtime";function h({items:c,renderRow:h,columns:g,height:_=`100%`,estimatedRowHeight:ae=40,overscan:oe=3,rowGap:se=0,rowPadding:v,selectedKey:y,getItemKey:b,onRowClick:ce,visibleColumnKeys:le,onVisibleColumnsChange:ue,persistColumnsKey:de,showColumnToggle:fe,onLoadMore:pe,loadMoreThreshold:x=100,isLoading:S=!1,multiSelect:C=!1,selectedKeys:me,onSelectionChange:he,reorderable:ge=!1,onReorder:_e,longPressDelay:ve=400,treeReorder:ye=!1,getItemDepth:w,isGroup:T,onTreeDrop:E,treeIndentPx:D=24,dragHandle:O=!1,showDivider:k=!0,rowHover:A=!0,className:j,style:M,classNames:N,styles:P,...be},xe){let F=l((e,t)=>b?b(e,t):t,[b]),I=u(()=>c.map((e,t)=>F(e,t)),[c,F]),L=u(()=>w?c.map((e,t)=>w(e,t)):[],[c,w]),Se=l(e=>T?T(c[e],e):!1,[T,c]),R=a({items:c,keys:I,getItemKey:b,estimatedRowHeight:ae,rowGap:se,overscan:oe,onLoadMore:pe,loadMoreThreshold:x,isLoading:S}),{rootRef:z,headerRef:Ce,rowObserver:we,keysRef:Te,offsets:Ee,totalHeight:De,startIndex:B,endIndex:V}=R,H=o({items:c,getKey:F,multiSelect:C,selectedKeys:me,onSelectionChange:he}),{effectiveSelectedKeys:U}=H,{hasColumns:W,visibleColumns:G,columnTemplate:K,shouldShowToggle:q,effectiveVisible:Oe,manuallyHiddenCount:J,toggleOpen:ke,setToggleOpen:Ae,handleToggleColumn:je,recalculateColumns:Y}=s({columns:g,items:c,multiSelect:C,visibleColumnKeys:le,onVisibleColumnsChange:ue,persistColumnsKey:de,showColumnToggle:fe,rootRef:z,startIndex:B,endIndex:V,containerHeight:R.containerHeight,containerWidth:R.containerWidth});ne(xe,()=>({...R.scrollApi,recalculateColumns:Y}),[R.scrollApi,Y]);let X=te({reorderable:ge,treeReorder:ye,onReorder:_e,onTreeDrop:E,longPressDelay:ve,dragHandle:O,treeIndentPx:D,keys:I,depths:L,isGroupAt:Se,rootRef:z,keysRef:Te}),Me=typeof v==`number`?`${v}px`:v,Z=e=>{let t=c[e],n=F(t,e),a=y!=null&&n===y||U.has(n),o=X.getRowDragProps(e,n);return p(ee,{index:e,top:Ee[e],padding:Me,columnTemplate:K,isSelected:a,showDivider:k,hover:A,onClick:()=>{X.consumeSuppressedClick()||ce?.(t,e)},observer:we,ariaRowIndex:W?e+2:void 0,ariaPosInSet:W?void 0:e+1,ariaSetSize:W?void 0:c.length,rowRole:W?`row`:`listitem`,reserveToggleGutter:q,...o,dropIndicatorClassName:N?.dropIndicator,dropIndicatorStyle:P?.dropIndicator,rowClassName:N?.row,rowStyle:P?.row,children:W?m(f,{children:[C&&p(`div`,{className:d(i.virtualListSelectCell,N?.selectCell),style:P?.selectCell,role:`gridcell`,onClick:e=>e.stopPropagation(),children:p(r,{selected:U.has(n),onToggle:()=>H.handleRowSelect(n),"aria-label":`Select row`})}),G.map(n=>p(`div`,{className:d(i.virtualListCell,N?.cell),style:P?.cell,role:`gridcell`,"data-fit-key":n.width.type===`fit`?n.key:void 0,children:n.renderCell(t,e)},n.key))]}):h?.(t,e)},n)},Q=[];for(let e=B;e<=V;e++)Q.push(Z(e));let $=X.draggingKey==null?-1:I.indexOf(X.draggingKey);return $>=0&&($<B||$>V)&&Q.push(Z($)),m(`div`,{...be,ref:z,className:d(i.virtualList,X.draggingKey!=null&&i.virtualListReordering,j,N?.root),style:{height:_,...M,...P?.root},onScroll:R.handleScroll,role:W?`grid`:`list`,"aria-rowcount":W?c.length+1:void 0,children:[W&&m(`div`,{ref:Ce,className:d(i.virtualListHeader,N?.header),style:{gridTemplateColumns:K,...q?{paddingRight:32}:{},...P?.header},role:`row`,"aria-rowindex":1,children:[C&&p(`div`,{className:d(i.virtualListSelectCell,N?.selectCell),style:P?.selectCell,role:`columnheader`,children:p(r,{selected:H.allSelected||H.someSelected,onToggle:H.handleSelectAll,"aria-label":`Select all rows`})}),G.map(e=>p(`div`,{className:d(i.virtualListHeaderCell,N?.headerCell),style:P?.headerCell,role:`columnheader`,"data-fit-key":e.width.type===`fit`?e.key:void 0,children:e.label},e.key)),q&&m(`div`,{className:i.virtualListToggleWrapper,children:[p(n,{isOpen:ke,onOpenChange:Ae,align:t.Right,dontCloseOnChildClick:!0,content:p(`div`,{className:d(i.virtualListTogglePopover,N?.togglePopover),style:P?.togglePopover,children:g.filter(e=>!e.hideFromToggle).map(e=>p(r,{className:d(i.virtualListToggleItem,N?.toggleItem),style:P?.toggleItem,selected:Oe.has(e.key),onToggle:()=>je(e.key),disabled:e.lockVisible,cursorDefault:!1,children:e.toggleLabel??e.label},e.key))}),children:p(`button`,{type:`button`,className:d(i.virtualListHeaderToggle,N?.headerToggle),style:P?.headerToggle,"aria-label":`Toggle column visibility`,children:p(re,{icon:ie,style:P?.headerToggle})})}),J>0&&p(`span`,{className:d(i.virtualListColumnChip,N?.columnChip),style:P?.columnChip,"data-column-hidden-count":J,"aria-label":`${J} columns hidden`,children:J})]})]}),S?p(`div`,{className:i.virtualListLoadingFull,children:p(e,{className:i.virtualListSpinner})}):p(`div`,{className:d(i.virtualListBody,N?.body),style:{height:De,...P?.body},children:Q}),R.showLoadMoreSpinner&&p(`div`,{className:d(i.virtualListLoadingIndicator,N?.loadingIndicator),style:P?.loadingIndicator,children:p(e,{className:i.virtualListSpinner})})]})}var g=c.forwardRef(h);export{g as default};
2
2
  //# sourceMappingURL=virtualList.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtualList.mjs","names":[],"sources":["../../../../package/common/virtualList/virtualList.tsx"],"sourcesContent":["import React, { useMemo, useCallback, useImperativeHandle } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faGear } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './virtualList.module.pcss';\nimport SpinnerLoading from '../loading/spinnerLoading';\nimport Checkbox from '../checkbox';\nimport FloatingMenu, { Align } from '../floatingMenu';\nimport VirtualRow from './virtualRow';\nimport { useVirtualWindow } from './useVirtualWindow';\nimport { useSelection } from './useSelection';\nimport { useColumns } from './useColumns';\nimport { useRowDrag } from './useRowDrag';\nimport type { VirtualListProps, VirtualListHandle } from './virtualList.types';\n\n// Pure helpers live in ./virtualList.utils; re-exported here so existing\n// imports (and unit tests) keep working against the component entry point.\nexport {\n buildOffsets,\n findStartIndex,\n getVisibleRange,\n resolveReorderTarget,\n resolveTreeDropTarget,\n lastDescendantIndex,\n buildColumnTemplate,\n} from './virtualList.utils';\n\n// ─── Orchestrator ─────────────────────────────────────────────────────────────\n// VirtualListInner wires four focused hooks together and renders. Each concern\n// lives in its own module:\n// useVirtualWindow — generic scroll / measurement / windowing (all modes)\n// useSelection — multi-row selection\n// useColumns — table mode: columns, visibility, persistence, fit widths\n// useRowDrag — reorder + tree drag-and-drop (mouse + touch)\n\nfunction VirtualListInner<T>({\n items,\n renderRow,\n columns,\n height = '100%',\n estimatedRowHeight = 40,\n overscan = 3,\n rowGap = 0,\n rowPadding,\n selectedKey,\n getItemKey,\n onRowClick,\n visibleColumnKeys,\n onVisibleColumnsChange,\n persistColumnsKey,\n showColumnToggle,\n onLoadMore,\n loadMoreThreshold = 100,\n isLoading = false,\n multiSelect = false,\n selectedKeys,\n onSelectionChange,\n reorderable = false,\n onReorder,\n longPressDelay = 400,\n treeReorder = false,\n getItemDepth,\n isGroup,\n onTreeDrop,\n treeIndentPx = 24,\n dragHandle = false,\n showDivider = true,\n rowHover = true,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: VirtualListProps<T>, ref: React.ForwardedRef<VirtualListHandle>) {\n const getKey = useCallback(\n (item: T, index: number): string | number => (getItemKey ? getItemKey(item, index) : index),\n [getItemKey],\n );\n const keys = useMemo(() => items.map((item, i) => getKey(item, i)), [items, getKey]);\n const depths = useMemo(\n () => (getItemDepth ? items.map((item, i) => getItemDepth(item, i)) : []),\n [items, getItemDepth],\n );\n const isGroupAt = useCallback(\n (i: number) => (isGroup ? isGroup(items[i], i) : false),\n [isGroup, items],\n );\n\n const win = useVirtualWindow<T>({\n items, keys, getItemKey, estimatedRowHeight, rowGap, overscan,\n onLoadMore, loadMoreThreshold,\n });\n const { rootRef, headerRef, rowObserver, keysRef, offsets, totalHeight, startIndex, endIndex } = win;\n\n const selection = useSelection<T>({ items, getKey, multiSelect, selectedKeys, onSelectionChange });\n const { effectiveSelectedKeys } = selection;\n\n const cols = useColumns<T>({\n columns, items, multiSelect, visibleColumnKeys, onVisibleColumnsChange, persistColumnsKey,\n showColumnToggle, rootRef, startIndex, endIndex,\n containerHeight: win.containerHeight, containerWidth: win.containerWidth,\n });\n const {\n hasColumns, visibleColumns, columnTemplate, shouldShowToggle, effectiveVisible, manuallyHiddenCount,\n toggleOpen, setToggleOpen, handleToggleColumn, recalculateColumns,\n } = cols;\n\n // Compose the forwarded handle from both hooks: scroll methods come from the\n // windowing engine, column controls from the column hook.\n useImperativeHandle(\n ref,\n () => ({ ...win.scrollApi, recalculateColumns }),\n [win.scrollApi, recalculateColumns],\n );\n\n const drag = useRowDrag({\n reorderable, treeReorder, onReorder, onTreeDrop, longPressDelay, dragHandle, treeIndentPx,\n keys, depths, isGroupAt, rootRef, keysRef,\n });\n\n const rowPaddingValue = typeof rowPadding === 'number' ? `${rowPadding}px` : rowPadding;\n\n const renderRowAt = (i: number) => {\n const item = items[i];\n const key = getKey(item, i);\n const isSelected = (selectedKey != null && key === selectedKey) || effectiveSelectedKeys.has(key);\n const dragProps = drag.getRowDragProps(i, key);\n\n return (\n <VirtualRow\n key={key}\n index={i}\n top={offsets[i]}\n padding={rowPaddingValue}\n columnTemplate={columnTemplate}\n isSelected={isSelected}\n showDivider={showDivider}\n hover={rowHover}\n onClick={() => {\n if (drag.consumeSuppressedClick()) return;\n onRowClick?.(item, i);\n }}\n observer={rowObserver}\n ariaRowIndex={hasColumns ? i + 2 : undefined}\n ariaPosInSet={hasColumns ? undefined : i + 1}\n ariaSetSize={hasColumns ? undefined : items.length}\n rowRole={hasColumns ? 'row' : 'listitem'}\n reserveToggleGutter={shouldShowToggle}\n {...dragProps}\n dropIndicatorClassName={classNames?.dropIndicator}\n dropIndicatorStyle={slotStyles?.dropIndicator}\n rowClassName={classNames?.row}\n rowStyle={slotStyles?.row}\n >\n {hasColumns\n ? <>\n {multiSelect && (\n <div\n className={cx(styles.virtualListSelectCell, classNames?.selectCell)}\n style={slotStyles?.selectCell}\n role=\"gridcell\"\n onClick={(e) => e.stopPropagation()}\n >\n <Checkbox\n selected={effectiveSelectedKeys.has(key)}\n onToggle={() => selection.handleRowSelect(key)}\n aria-label=\"Select row\"\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <div\n key={col.key}\n className={cx(styles.virtualListCell, classNames?.cell)}\n style={slotStyles?.cell}\n role=\"gridcell\"\n data-fit-key={col.width.type === 'fit' ? col.key : undefined}\n >\n {col.renderCell(item, i)}\n </div>\n ))}\n </>\n : renderRow?.(item, i)}\n </VirtualRow>\n );\n };\n\n const visibleRows: React.ReactNode[] = [];\n for (let i = startIndex; i <= endIndex; i++) visibleRows.push(renderRowAt(i));\n\n // Keep the row being touch-dragged mounted even if it scrolls out of the\n // window. Touch events are dispatched to the element under the finger at\n // touchstart; if that row unmounts, the browser stops delivering touchmove\n // and the drag freezes. Pinning its DOM node keeps the gesture alive.\n const draggedIndex = drag.draggingKey != null ? keys.indexOf(drag.draggingKey) : -1;\n if (draggedIndex >= 0 && (draggedIndex < startIndex || draggedIndex > endIndex)) {\n visibleRows.push(renderRowAt(draggedIndex));\n }\n\n return (\n <div\n {...rest}\n ref={rootRef}\n className={cx(styles.virtualList, drag.draggingKey != null && styles.virtualListReordering, className, classNames?.root)}\n style={{ height, ...style, ...slotStyles?.root }}\n onScroll={win.handleScroll}\n role={hasColumns ? 'grid' : 'list'}\n aria-rowcount={hasColumns ? items.length + 1 : undefined}\n >\n {hasColumns && (\n <div\n ref={headerRef}\n className={cx(styles.virtualListHeader, classNames?.header)}\n style={{ gridTemplateColumns: columnTemplate, ...(shouldShowToggle ? { paddingRight: 32 } : {}), ...slotStyles?.header }}\n role=\"row\"\n aria-rowindex={1}\n >\n {multiSelect && (\n <div\n className={cx(styles.virtualListSelectCell, classNames?.selectCell)}\n style={slotStyles?.selectCell}\n role=\"columnheader\"\n >\n <Checkbox\n selected={selection.allSelected || selection.someSelected}\n onToggle={selection.handleSelectAll}\n aria-label=\"Select all rows\"\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <div\n key={col.key}\n className={cx(styles.virtualListHeaderCell, classNames?.headerCell)}\n style={slotStyles?.headerCell}\n role=\"columnheader\"\n data-fit-key={col.width.type === 'fit' ? col.key : undefined}\n >\n {col.label}\n </div>\n ))}\n {shouldShowToggle && (\n <div className={styles.virtualListToggleWrapper}>\n <FloatingMenu\n isOpen={toggleOpen}\n onOpenChange={setToggleOpen}\n align={Align.Right}\n content={\n <div\n className={cx(styles.virtualListTogglePopover, classNames?.togglePopover)}\n style={slotStyles?.togglePopover}\n >\n {columns!.filter((col) => !col.hideFromToggle).map((col) => (\n <Checkbox\n key={col.key}\n className={cx(styles.virtualListToggleItem, classNames?.toggleItem)}\n style={slotStyles?.toggleItem}\n selected={effectiveVisible.has(col.key)}\n onToggle={() => handleToggleColumn(col.key)}\n disabled={col.lockVisible}\n cursorDefault={false}\n >\n {col.toggleLabel ?? col.label}\n </Checkbox>\n ))}\n </div>\n }\n >\n <button\n type=\"button\"\n className={cx(styles.virtualListHeaderToggle, classNames?.headerToggle)}\n style={slotStyles?.headerToggle}\n aria-label=\"Toggle column visibility\"\n >\n <FontAwesomeIcon\n icon={faGear}\n style={slotStyles?.headerToggle as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n </button>\n </FloatingMenu>\n {manuallyHiddenCount > 0 && (\n <span\n className={cx(styles.virtualListColumnChip, classNames?.columnChip)}\n style={slotStyles?.columnChip}\n data-column-hidden-count={manuallyHiddenCount}\n aria-label={`${manuallyHiddenCount} columns hidden`}\n >\n {manuallyHiddenCount}\n </span>\n )}\n </div>\n )}\n </div>\n )}\n {isLoading ? (\n <div className={styles.virtualListLoadingFull}>\n <SpinnerLoading className={styles.virtualListSpinner} />\n </div>\n ) : (\n <div\n className={cx(styles.virtualListBody, classNames?.body)}\n style={{ height: totalHeight, ...slotStyles?.body }}\n >\n {visibleRows}\n </div>\n )}\n {win.showLoadMoreSpinner && (\n <div\n className={cx(styles.virtualListLoadingIndicator, classNames?.loadingIndicator)}\n style={slotStyles?.loadingIndicator}\n >\n <SpinnerLoading className={styles.virtualListSpinner} />\n </div>\n )}\n </div>\n );\n}\n\n// forwardRef erases the generic, so cast back to a generic-preserving signature.\nconst VirtualList = React.forwardRef(VirtualListInner) as <T>(\n props: VirtualListProps<T> & { ref?: React.Ref<VirtualListHandle> },\n) => React.ReactElement | null;\n\nexport default VirtualList;\n"],"mappings":"kyBAoCA,SAAS,EAAoB,CAC3B,QACA,YACA,UACA,SAAS,OACT,sBAAqB,GACrB,YAAW,EACX,UAAS,EACT,aACA,cACA,aACA,cACA,qBACA,0BACA,qBACA,oBACA,aACA,qBAAoB,IACpB,aAAY,GACZ,cAAc,GACd,gBACA,qBACA,eAAc,GACd,aACA,kBAAiB,IACjB,cAAc,GACd,eACA,UACA,aACA,eAAe,GACf,aAAa,GACb,cAAc,GACd,WAAW,GACX,YACA,QACA,aACA,OAAQ,EACR,GAAG,IACmB,GAA4C,CAClE,IAAM,EAAS,GACZ,EAAS,IAAoC,EAAa,EAAW,EAAM,CAAK,EAAI,EACrF,CAAC,CAAU,CACb,EACM,EAAO,MAAc,EAAM,KAAK,EAAM,IAAM,EAAO,EAAM,CAAC,CAAC,EAAG,CAAC,EAAO,CAAM,CAAC,EAC7E,EAAS,MACN,EAAe,EAAM,KAAK,EAAM,IAAM,EAAa,EAAM,CAAC,CAAC,EAAI,CAAC,EACvE,CAAC,EAAO,CAAY,CACtB,EACM,GAAY,EACf,GAAe,EAAU,EAAQ,EAAM,GAAI,CAAC,EAAI,GACjD,CAAC,EAAS,CAAK,CACjB,EAEM,EAAM,EAAoB,CAC9B,QAAO,OAAM,aAAY,sBAAoB,UAAQ,YACrD,aAAY,oBACd,CAAC,EACK,CAAE,UAAS,aAAW,eAAa,WAAS,WAAS,eAAa,aAAY,YAAa,EAE3F,EAAY,EAAgB,CAAE,QAAO,SAAQ,cAAa,gBAAc,oBAAkB,CAAC,EAC3F,CAAE,yBAA0B,EAO5B,CACJ,aAAY,iBAAgB,iBAAgB,mBAAkB,oBAAkB,sBAChF,cAAY,iBAAe,sBAAoB,sBAPpC,EAAc,CACzB,UAAS,QAAO,cAAa,qBAAmB,0BAAwB,qBACxE,oBAAkB,UAAS,aAAY,WACvC,gBAAiB,EAAI,gBAAiB,eAAgB,EAAI,cAC5D,CAII,EAIJ,GACE,QACO,CAAE,GAAG,EAAI,UAAW,oBAAmB,GAC9C,CAAC,EAAI,UAAW,CAAkB,CACpC,EAEA,IAAM,EAAO,GAAW,CACtB,eAAa,cAAa,aAAW,aAAY,kBAAgB,aAAY,eAC7E,OAAM,SAAQ,aAAW,UAAS,UACpC,CAAC,EAEK,GAAkB,OAAO,GAAe,SAAW,GAAG,EAAW,IAAM,EAEvE,EAAe,GAAc,CACjC,IAAM,EAAO,EAAM,GACb,EAAM,EAAO,EAAM,CAAC,EACpB,EAAc,GAAe,MAAQ,IAAQ,GAAgB,EAAsB,IAAI,CAAG,EAC1F,EAAY,EAAK,gBAAgB,EAAG,CAAG,EAE7C,OACE,EAAC,GAAD,CAEE,MAAO,EACP,IAAK,GAAQ,GACb,QAAS,GACO,iBACJ,aACC,cACb,MAAO,EACP,YAAe,CACT,EAAK,uBAAuB,GAChC,KAAa,EAAM,CAAC,CACtB,EACA,SAAU,GACV,aAAc,EAAa,EAAI,EAAI,IAAA,GACnC,aAAc,EAAa,IAAA,GAAY,EAAI,EAC3C,YAAa,EAAa,IAAA,GAAY,EAAM,OAC5C,QAAS,EAAa,MAAQ,WAC9B,oBAAqB,EACrB,GAAI,EACJ,uBAAwB,GAAY,cACpC,mBAAoB,GAAY,cAChC,aAAc,GAAY,IAC1B,SAAU,GAAY,aAErB,EACG,EAAA,EAAA,CAAA,SAAA,CACG,GACC,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,sBAAuB,GAAY,UAAU,EAClE,MAAO,GAAY,WACnB,KAAK,WACL,QAAU,GAAM,EAAE,gBAAgB,WAElC,EAAC,EAAD,CACE,SAAU,EAAsB,IAAI,CAAG,EACvC,aAAgB,EAAU,gBAAgB,CAAG,EAC7C,aAAW,YACZ,CAAA,CACE,CAAA,EAEN,EAAe,IAAK,GACnB,EAAC,MAAD,CAEE,UAAW,EAAG,EAAO,gBAAiB,GAAY,IAAI,EACtD,MAAO,GAAY,KACnB,KAAK,WACL,eAAc,EAAI,MAAM,OAAS,MAAQ,EAAI,IAAM,IAAA,YAElD,EAAI,WAAW,EAAM,CAAC,CACpB,EAPE,EAAI,GAON,CACN,CACD,CAAA,CAAA,EACF,IAAY,EAAM,CAAC,CACb,EArDL,CAqDK,CAEhB,EAEM,EAAiC,CAAC,EACxC,IAAK,IAAI,EAAI,EAAY,GAAK,EAAU,IAAK,EAAY,KAAK,EAAY,CAAC,CAAC,EAM5E,IAAM,EAAe,EAAK,aAAe,KAAwC,GAAjC,EAAK,QAAQ,EAAK,WAAW,EAK7E,OAJI,GAAgB,IAAM,EAAe,GAAc,EAAe,IACpE,EAAY,KAAK,EAAY,CAAY,CAAC,EAI1C,EAAC,MAAD,CACE,GAAI,GACJ,IAAK,EACL,UAAW,EAAG,EAAO,YAAa,EAAK,aAAe,MAAQ,EAAO,sBAAuB,EAAW,GAAY,IAAI,EACvH,MAAO,CAAE,SAAQ,GAAG,EAAO,GAAG,GAAY,IAAK,EAC/C,SAAU,EAAI,aACd,KAAM,EAAa,OAAS,OAC5B,gBAAe,EAAa,EAAM,OAAS,EAAI,IAAA,YAPjD,CASG,GACC,EAAC,MAAD,CACE,IAAK,GACL,UAAW,EAAG,EAAO,kBAAmB,GAAY,MAAM,EAC1D,MAAO,CAAE,oBAAqB,EAAgB,GAAI,EAAmB,CAAE,aAAc,EAAG,EAAI,CAAC,EAAI,GAAG,GAAY,MAAO,EACvH,KAAK,MACL,gBAAe,WALjB,CAOG,GACC,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,sBAAuB,GAAY,UAAU,EAClE,MAAO,GAAY,WACnB,KAAK,wBAEL,EAAC,EAAD,CACE,SAAU,EAAU,aAAe,EAAU,aAC7C,SAAU,EAAU,gBACpB,aAAW,iBACZ,CAAA,CACE,CAAA,EAEN,EAAe,IAAK,GACnB,EAAC,MAAD,CAEE,UAAW,EAAG,EAAO,sBAAuB,GAAY,UAAU,EAClE,MAAO,GAAY,WACnB,KAAK,eACL,eAAc,EAAI,MAAM,OAAS,MAAQ,EAAI,IAAM,IAAA,YAElD,EAAI,KACF,EAPE,EAAI,GAON,CACN,EACA,GACC,EAAC,MAAD,CAAK,UAAW,EAAO,kCAAvB,CACE,EAAC,EAAD,CACE,OAAQ,GACR,aAAc,GACd,MAAO,EAAM,MACb,QACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,yBAA0B,GAAY,aAAa,EACxE,MAAO,GAAY,uBAElB,EAAS,OAAQ,GAAQ,CAAC,EAAI,cAAc,EAAE,IAAK,GAClD,EAAC,EAAD,CAEE,UAAW,EAAG,EAAO,sBAAuB,GAAY,UAAU,EAClE,MAAO,GAAY,WACnB,SAAU,GAAiB,IAAI,EAAI,GAAG,EACtC,aAAgB,GAAmB,EAAI,GAAG,EAC1C,SAAU,EAAI,YACd,cAAe,YAEd,EAAI,aAAe,EAAI,KAChB,EATH,EAAI,GASD,CACX,CACE,CAAA,WAGP,EAAC,SAAD,CACE,KAAK,SACL,UAAW,EAAG,EAAO,wBAAyB,GAAY,YAAY,EACtE,MAAO,GAAY,aACnB,aAAW,oCAEX,EAAC,GAAD,CACE,KAAM,GACN,MAAO,GAAY,YACpB,CAAA,CACK,CAAA,CACI,CAAA,EACb,EAAsB,GACrB,EAAC,OAAD,CACE,UAAW,EAAG,EAAO,sBAAuB,GAAY,UAAU,EAClE,MAAO,GAAY,WACnB,2BAA0B,EAC1B,aAAY,GAAG,EAAoB,0BAElC,CACG,CAAA,CAEL,GAEJ,IAEN,GACC,EAAC,MAAD,CAAK,UAAW,EAAO,gCACrB,EAAC,EAAD,CAAgB,UAAW,EAAO,kBAAqB,CAAA,CACpD,CAAA,EAEL,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,gBAAiB,GAAY,IAAI,EACtD,MAAO,CAAE,OAAQ,GAAa,GAAG,GAAY,IAAK,WAEjD,CACE,CAAA,EAEN,EAAI,qBACH,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,4BAA6B,GAAY,gBAAgB,EAC9E,MAAO,GAAY,0BAEnB,EAAC,EAAD,CAAgB,UAAW,EAAO,kBAAqB,CAAA,CACpD,CAAA,CAEJ,GAET,CAGA,IAAM,EAAc,EAAM,WAAW,CAAgB"}
1
+ {"version":3,"file":"virtualList.mjs","names":[],"sources":["../../../../package/common/virtualList/virtualList.tsx"],"sourcesContent":["import React, { useMemo, useCallback, useImperativeHandle } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faGear } from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './virtualList.module.pcss';\nimport SpinnerLoading from '../loading/spinnerLoading';\nimport Checkbox from '../checkbox';\nimport FloatingMenu, { Align } from '../floatingMenu';\nimport VirtualRow from './virtualRow';\nimport { useVirtualWindow } from './useVirtualWindow';\nimport { useSelection } from './useSelection';\nimport { useColumns } from './useColumns';\nimport { useRowDrag } from './useRowDrag';\nimport type { VirtualListProps, VirtualListHandle } from './virtualList.types';\n\n// Pure helpers live in ./virtualList.utils; re-exported here so existing\n// imports (and unit tests) keep working against the component entry point.\nexport {\n buildOffsets,\n findStartIndex,\n getVisibleRange,\n resolveReorderTarget,\n resolveTreeDropTarget,\n lastDescendantIndex,\n buildColumnTemplate,\n} from './virtualList.utils';\n\n// ─── Orchestrator ─────────────────────────────────────────────────────────────\n// VirtualListInner wires four focused hooks together and renders. Each concern\n// lives in its own module:\n// useVirtualWindow — generic scroll / measurement / windowing (all modes)\n// useSelection — multi-row selection\n// useColumns — table mode: columns, visibility, persistence, fit widths\n// useRowDrag — reorder + tree drag-and-drop (mouse + touch)\n\nfunction VirtualListInner<T>({\n items,\n renderRow,\n columns,\n height = '100%',\n estimatedRowHeight = 40,\n overscan = 3,\n rowGap = 0,\n rowPadding,\n selectedKey,\n getItemKey,\n onRowClick,\n visibleColumnKeys,\n onVisibleColumnsChange,\n persistColumnsKey,\n showColumnToggle,\n onLoadMore,\n loadMoreThreshold = 100,\n isLoading = false,\n multiSelect = false,\n selectedKeys,\n onSelectionChange,\n reorderable = false,\n onReorder,\n longPressDelay = 400,\n treeReorder = false,\n getItemDepth,\n isGroup,\n onTreeDrop,\n treeIndentPx = 24,\n dragHandle = false,\n showDivider = true,\n rowHover = true,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: VirtualListProps<T>, ref: React.ForwardedRef<VirtualListHandle>) {\n const getKey = useCallback(\n (item: T, index: number): string | number => (getItemKey ? getItemKey(item, index) : index),\n [getItemKey],\n );\n const keys = useMemo(() => items.map((item, i) => getKey(item, i)), [items, getKey]);\n const depths = useMemo(\n () => (getItemDepth ? items.map((item, i) => getItemDepth(item, i)) : []),\n [items, getItemDepth],\n );\n const isGroupAt = useCallback(\n (i: number) => (isGroup ? isGroup(items[i], i) : false),\n [isGroup, items],\n );\n\n const win = useVirtualWindow<T>({\n items, keys, getItemKey, estimatedRowHeight, rowGap, overscan,\n onLoadMore, loadMoreThreshold, isLoading,\n });\n const { rootRef, headerRef, rowObserver, keysRef, offsets, totalHeight, startIndex, endIndex } = win;\n\n const selection = useSelection<T>({ items, getKey, multiSelect, selectedKeys, onSelectionChange });\n const { effectiveSelectedKeys } = selection;\n\n const cols = useColumns<T>({\n columns, items, multiSelect, visibleColumnKeys, onVisibleColumnsChange, persistColumnsKey,\n showColumnToggle, rootRef, startIndex, endIndex,\n containerHeight: win.containerHeight, containerWidth: win.containerWidth,\n });\n const {\n hasColumns, visibleColumns, columnTemplate, shouldShowToggle, effectiveVisible, manuallyHiddenCount,\n toggleOpen, setToggleOpen, handleToggleColumn, recalculateColumns,\n } = cols;\n\n // Compose the forwarded handle from both hooks: scroll methods come from the\n // windowing engine, column controls from the column hook.\n useImperativeHandle(\n ref,\n () => ({ ...win.scrollApi, recalculateColumns }),\n [win.scrollApi, recalculateColumns],\n );\n\n const drag = useRowDrag({\n reorderable, treeReorder, onReorder, onTreeDrop, longPressDelay, dragHandle, treeIndentPx,\n keys, depths, isGroupAt, rootRef, keysRef,\n });\n\n const rowPaddingValue = typeof rowPadding === 'number' ? `${rowPadding}px` : rowPadding;\n\n const renderRowAt = (i: number) => {\n const item = items[i];\n const key = getKey(item, i);\n const isSelected = (selectedKey != null && key === selectedKey) || effectiveSelectedKeys.has(key);\n const dragProps = drag.getRowDragProps(i, key);\n\n return (\n <VirtualRow\n key={key}\n index={i}\n top={offsets[i]}\n padding={rowPaddingValue}\n columnTemplate={columnTemplate}\n isSelected={isSelected}\n showDivider={showDivider}\n hover={rowHover}\n onClick={() => {\n if (drag.consumeSuppressedClick()) return;\n onRowClick?.(item, i);\n }}\n observer={rowObserver}\n ariaRowIndex={hasColumns ? i + 2 : undefined}\n ariaPosInSet={hasColumns ? undefined : i + 1}\n ariaSetSize={hasColumns ? undefined : items.length}\n rowRole={hasColumns ? 'row' : 'listitem'}\n reserveToggleGutter={shouldShowToggle}\n {...dragProps}\n dropIndicatorClassName={classNames?.dropIndicator}\n dropIndicatorStyle={slotStyles?.dropIndicator}\n rowClassName={classNames?.row}\n rowStyle={slotStyles?.row}\n >\n {hasColumns\n ? <>\n {multiSelect && (\n <div\n className={cx(styles.virtualListSelectCell, classNames?.selectCell)}\n style={slotStyles?.selectCell}\n role=\"gridcell\"\n onClick={(e) => e.stopPropagation()}\n >\n <Checkbox\n selected={effectiveSelectedKeys.has(key)}\n onToggle={() => selection.handleRowSelect(key)}\n aria-label=\"Select row\"\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <div\n key={col.key}\n className={cx(styles.virtualListCell, classNames?.cell)}\n style={slotStyles?.cell}\n role=\"gridcell\"\n data-fit-key={col.width.type === 'fit' ? col.key : undefined}\n >\n {col.renderCell(item, i)}\n </div>\n ))}\n </>\n : renderRow?.(item, i)}\n </VirtualRow>\n );\n };\n\n const visibleRows: React.ReactNode[] = [];\n for (let i = startIndex; i <= endIndex; i++) visibleRows.push(renderRowAt(i));\n\n // Keep the row being touch-dragged mounted even if it scrolls out of the\n // window. Touch events are dispatched to the element under the finger at\n // touchstart; if that row unmounts, the browser stops delivering touchmove\n // and the drag freezes. Pinning its DOM node keeps the gesture alive.\n const draggedIndex = drag.draggingKey != null ? keys.indexOf(drag.draggingKey) : -1;\n if (draggedIndex >= 0 && (draggedIndex < startIndex || draggedIndex > endIndex)) {\n visibleRows.push(renderRowAt(draggedIndex));\n }\n\n return (\n <div\n {...rest}\n ref={rootRef}\n className={cx(styles.virtualList, drag.draggingKey != null && styles.virtualListReordering, className, classNames?.root)}\n style={{ height, ...style, ...slotStyles?.root }}\n onScroll={win.handleScroll}\n role={hasColumns ? 'grid' : 'list'}\n aria-rowcount={hasColumns ? items.length + 1 : undefined}\n >\n {hasColumns && (\n <div\n ref={headerRef}\n className={cx(styles.virtualListHeader, classNames?.header)}\n style={{ gridTemplateColumns: columnTemplate, ...(shouldShowToggle ? { paddingRight: 32 } : {}), ...slotStyles?.header }}\n role=\"row\"\n aria-rowindex={1}\n >\n {multiSelect && (\n <div\n className={cx(styles.virtualListSelectCell, classNames?.selectCell)}\n style={slotStyles?.selectCell}\n role=\"columnheader\"\n >\n <Checkbox\n selected={selection.allSelected || selection.someSelected}\n onToggle={selection.handleSelectAll}\n aria-label=\"Select all rows\"\n />\n </div>\n )}\n {visibleColumns.map((col) => (\n <div\n key={col.key}\n className={cx(styles.virtualListHeaderCell, classNames?.headerCell)}\n style={slotStyles?.headerCell}\n role=\"columnheader\"\n data-fit-key={col.width.type === 'fit' ? col.key : undefined}\n >\n {col.label}\n </div>\n ))}\n {shouldShowToggle && (\n <div className={styles.virtualListToggleWrapper}>\n <FloatingMenu\n isOpen={toggleOpen}\n onOpenChange={setToggleOpen}\n align={Align.Right}\n dontCloseOnChildClick\n content={\n <div\n className={cx(styles.virtualListTogglePopover, classNames?.togglePopover)}\n style={slotStyles?.togglePopover}\n >\n {columns!.filter((col) => !col.hideFromToggle).map((col) => (\n <Checkbox\n key={col.key}\n className={cx(styles.virtualListToggleItem, classNames?.toggleItem)}\n style={slotStyles?.toggleItem}\n selected={effectiveVisible.has(col.key)}\n onToggle={() => handleToggleColumn(col.key)}\n disabled={col.lockVisible}\n cursorDefault={false}\n >\n {col.toggleLabel ?? col.label}\n </Checkbox>\n ))}\n </div>\n }\n >\n <button\n type=\"button\"\n className={cx(styles.virtualListHeaderToggle, classNames?.headerToggle)}\n style={slotStyles?.headerToggle}\n aria-label=\"Toggle column visibility\"\n >\n <FontAwesomeIcon\n icon={faGear}\n style={slotStyles?.headerToggle as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n </button>\n </FloatingMenu>\n {manuallyHiddenCount > 0 && (\n <span\n className={cx(styles.virtualListColumnChip, classNames?.columnChip)}\n style={slotStyles?.columnChip}\n data-column-hidden-count={manuallyHiddenCount}\n aria-label={`${manuallyHiddenCount} columns hidden`}\n >\n {manuallyHiddenCount}\n </span>\n )}\n </div>\n )}\n </div>\n )}\n {isLoading ? (\n <div className={styles.virtualListLoadingFull}>\n <SpinnerLoading className={styles.virtualListSpinner} />\n </div>\n ) : (\n <div\n className={cx(styles.virtualListBody, classNames?.body)}\n style={{ height: totalHeight, ...slotStyles?.body }}\n >\n {visibleRows}\n </div>\n )}\n {win.showLoadMoreSpinner && (\n <div\n className={cx(styles.virtualListLoadingIndicator, classNames?.loadingIndicator)}\n style={slotStyles?.loadingIndicator}\n >\n <SpinnerLoading className={styles.virtualListSpinner} />\n </div>\n )}\n </div>\n );\n}\n\n// forwardRef erases the generic, so cast back to a generic-preserving signature.\nconst VirtualList = React.forwardRef(VirtualListInner) as <T>(\n props: VirtualListProps<T> & { ref?: React.Ref<VirtualListHandle> },\n) => React.ReactElement | null;\n\nexport default VirtualList;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"./virtualList.module.mjs";import{useLayoutEffect as t,useRef as n}from"react";import r from"classnames";import{jsx as i,jsxs as a}from"react/jsx-runtime";function o({index:o,top:s,padding:c,columnTemplate:l,isSelected:u,showDivider:d,hover:f,onClick:p,observer:m,ariaRowIndex:h,ariaPosInSet:g,ariaSetSize:_,rowRole:v,reorderable:y,draggable:b,isDragging:x,reserveToggleGutter:S,onMouseDown:C,onDragStart:w,onDragOver:T,onDragEnd:E,onDrop:D,onTouchStart:O,dropPosition:k,dropIndentPx:A,dropIndicatorClassName:j,dropIndicatorStyle:M,rowClassName:N,rowStyle:P,children:F}){let I=n(null);return t(()=>{let e=I.current;if(!(!e||!m))return m.observe(e),()=>m.unobserve(e)},[m]),a(`div`,{ref:I,"data-index":o,className:r(e.virtualListRow,u&&e.virtualListRowSelected,!d&&e.virtualListRowNoDivider,!f&&e.virtualListRowNoHover,y&&e.virtualListRowDraggable,x&&e.virtualListRowDragging,k===`inside`&&e.virtualListRowDropInside,N),style:{position:`absolute`,top:0,left:0,right:0,transform:`translateY(${s}px)`,...c==null?{}:{padding:c},...l?{display:`grid`,gridTemplateColumns:l}:{},...S?{paddingRight:32}:{},...P},onClick:p,draggable:b,onMouseDown:C,onDragStart:w,onDragOver:T,onDragEnd:E,onDrop:D??(b?e=>e.preventDefault():void 0),onTouchStart:O,onContextMenu:b?e=>e.preventDefault():void 0,"aria-selected":u,"aria-rowindex":h,"aria-posinset":g,"aria-setsize":_,role:v,children:[(k===`before`||k===`after`)&&i(`div`,{"data-drop-line":k,"aria-hidden":!0,className:r(e.virtualListDropLine,k===`before`?e.virtualListDropLineBefore:e.virtualListDropLineAfter,j),style:{left:A??0,...M}}),F]})}export{o as default};
1
+ import e from"./virtualList.module.mjs";import{useLayoutEffect as t,useRef as n}from"react";import r from"classnames";import{jsx as i,jsxs as a}from"react/jsx-runtime";function o({index:o,top:s,padding:c,columnTemplate:l,isSelected:u,showDivider:d,hover:f,onClick:p,observer:m,ariaRowIndex:h,ariaPosInSet:g,ariaSetSize:_,rowRole:v,reorderable:y,mouseDragEnabled:b,draggable:x,isDragging:S,reserveToggleGutter:C,onMouseDown:w,onMouseOver:T,onMouseLeave:E,onDragStart:D,onDragOver:O,onDragEnd:k,onDrop:A,onTouchStart:j,dropPosition:M,dropIndentPx:N,dropIndicatorClassName:P,dropIndicatorStyle:F,rowClassName:I,rowStyle:L,children:R}){let z=n(null);return t(()=>{let e=z.current;if(!(!e||!m))return m.observe(e),()=>m.unobserve(e)},[m]),a(`div`,{ref:z,"data-index":o,className:r(e.virtualListRow,u&&e.virtualListRowSelected,!d&&e.virtualListRowNoDivider,!f&&e.virtualListRowNoHover,y&&e.virtualListRowDraggable,S&&e.virtualListRowDragging,M===`inside`&&e.virtualListRowDropInside,I),style:{position:`absolute`,top:0,left:0,right:0,transform:`translateY(${s}px)`,...c==null?{}:{padding:c},...l?{display:`grid`,gridTemplateColumns:l}:{},...C?{paddingRight:32}:{},...L},onClick:p,draggable:x,onMouseDown:w,onMouseOver:T,onMouseLeave:E,onDragStart:D,onDragOver:O,onDragEnd:k,onDrop:A??(b?e=>e.preventDefault():void 0),onTouchStart:j,onContextMenu:b?e=>e.preventDefault():void 0,"aria-selected":u,"aria-rowindex":h,"aria-posinset":g,"aria-setsize":_,role:v,children:[(M===`before`||M===`after`)&&i(`div`,{"data-drop-line":M,"aria-hidden":!0,className:r(e.virtualListDropLine,M===`before`?e.virtualListDropLineBefore:e.virtualListDropLineAfter,P),style:{left:N??0,...F}}),R]})}export{o as default};
2
2
  //# sourceMappingURL=virtualRow.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtualRow.mjs","names":[],"sources":["../../../../package/common/virtualList/virtualRow.tsx"],"sourcesContent":["import React, { useRef, useLayoutEffect } from 'react';\nimport cx from 'classnames';\n\nimport styles from './virtualList.module.pcss';\nimport type { TreeDropPosition } from './virtualList.types';\n\nexport interface VirtualRowProps {\n index: number;\n top: number;\n /** Padding applied to the row (already normalised to a CSS string). */\n padding?: string;\n columnTemplate: string | undefined;\n isSelected: boolean;\n showDivider: boolean;\n hover: boolean;\n onClick: () => void;\n observer: ResizeObserver | null;\n ariaRowIndex?: number;\n ariaPosInSet?: number;\n ariaSetSize?: number;\n rowRole: 'row' | 'listitem';\n reorderable?: boolean;\n draggable?: boolean;\n isDragging?: boolean;\n reserveToggleGutter?: boolean;\n onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;\n onDragStart?: (e: React.DragEvent<HTMLDivElement>) => void;\n onDragOver?: (e: React.DragEvent<HTMLDivElement>) => void;\n onDragEnd?: () => void;\n onDrop?: (e: React.DragEvent<HTMLDivElement>) => void;\n onTouchStart?: (e: React.TouchEvent<HTMLDivElement>) => void;\n dropPosition?: TreeDropPosition;\n dropIndentPx?: number;\n dropIndicatorClassName?: string;\n dropIndicatorStyle?: React.CSSProperties;\n rowClassName?: string;\n rowStyle?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/**\n * A single virtualized row: absolutely positioned at its `top`, optionally a\n * grid (table mode), registering itself with the shared ResizeObserver and\n * carrying all the drag / drop-indicator wiring the parent assigns it.\n */\nfunction VirtualRow({\n index,\n top,\n padding,\n columnTemplate,\n isSelected,\n showDivider,\n hover,\n onClick,\n observer,\n ariaRowIndex,\n ariaPosInSet,\n ariaSetSize,\n rowRole,\n reorderable,\n draggable,\n isDragging,\n reserveToggleGutter,\n onMouseDown,\n onDragStart,\n onDragOver,\n onDragEnd,\n onDrop,\n onTouchStart,\n dropPosition,\n dropIndentPx,\n dropIndicatorClassName,\n dropIndicatorStyle,\n rowClassName,\n rowStyle,\n children,\n}: VirtualRowProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n // A single observer is shared across all rows (created by the parent); each\n // row just registers/unregisters its element. The parent reads the row index\n // back from the `data-index` attribute when the observer fires.\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el || !observer) return;\n observer.observe(el);\n return () => observer.unobserve(el);\n }, [observer]);\n\n return (\n <div\n ref={ref}\n data-index={index}\n className={cx(\n styles.virtualListRow,\n isSelected && styles.virtualListRowSelected,\n !showDivider && styles.virtualListRowNoDivider,\n !hover && styles.virtualListRowNoHover,\n reorderable && styles.virtualListRowDraggable,\n isDragging && styles.virtualListRowDragging,\n dropPosition === 'inside' && styles.virtualListRowDropInside,\n rowClassName,\n )}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n transform: `translateY(${top}px)`,\n ...(padding != null ? { padding } : {}),\n ...(columnTemplate ? { display: 'grid', gridTemplateColumns: columnTemplate } : {}),\n // Match the header's reserved gutter for the column-toggle cog so row\n // cells line up with their header cells instead of drifting under it.\n // Applied after `padding` so the alignment gutter always wins on the right.\n ...(reserveToggleGutter ? { paddingRight: 32 } : {}),\n ...rowStyle,\n }}\n onClick={onClick}\n draggable={draggable}\n onMouseDown={onMouseDown}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n onDrop={onDrop ?? (draggable ? (e) => e.preventDefault() : undefined)}\n onTouchStart={onTouchStart}\n onContextMenu={draggable ? (e) => e.preventDefault() : undefined}\n aria-selected={isSelected}\n aria-rowindex={ariaRowIndex}\n aria-posinset={ariaPosInSet}\n aria-setsize={ariaSetSize}\n role={rowRole}\n >\n {(dropPosition === 'before' || dropPosition === 'after') && (\n <div\n data-drop-line={dropPosition}\n aria-hidden\n className={cx(\n styles.virtualListDropLine,\n dropPosition === 'before' ? styles.virtualListDropLineBefore : styles.virtualListDropLineAfter,\n dropIndicatorClassName,\n )}\n style={{ left: dropIndentPx ?? 0, ...dropIndicatorStyle }}\n />\n )}\n {children}\n </div>\n );\n}\n\nexport default VirtualRow;\n"],"mappings":"wKA6CA,SAAS,EAAW,CAClB,QACA,MACA,UACA,iBACA,aACA,cACA,QACA,UACA,WACA,eACA,eACA,cACA,UACA,cACA,YACA,aACA,sBACA,cACA,cACA,aACA,YACA,SACA,eACA,eACA,eACA,yBACA,qBACA,eACA,WACA,YACkB,CAClB,IAAM,EAAM,EAAuB,IAAI,EAYvC,OAPA,MAAsB,CACpB,IAAM,EAAK,EAAI,QACX,MAAC,GAAM,CAAC,GAEZ,OADA,EAAS,QAAQ,CAAE,MACN,EAAS,UAAU,CAAE,CACpC,EAAG,CAAC,CAAQ,CAAC,EAGX,EAAC,MAAD,CACO,MACL,aAAY,EACZ,UAAW,EACT,EAAO,eACP,GAAc,EAAO,uBACrB,CAAC,GAAe,EAAO,wBACvB,CAAC,GAAS,EAAO,sBACjB,GAAe,EAAO,wBACtB,GAAc,EAAO,uBACrB,IAAiB,UAAY,EAAO,yBACpC,CACF,EACA,MAAO,CACL,SAAU,WACV,IAAK,EACL,KAAM,EACN,MAAO,EACP,UAAW,cAAc,EAAI,KAC7B,GAAI,GAAW,KAAqB,CAAC,EAAf,CAAE,SAAQ,EAChC,GAAI,EAAiB,CAAE,QAAS,OAAQ,oBAAqB,CAAe,EAAI,CAAC,EAIjF,GAAI,EAAsB,CAAE,aAAc,EAAG,EAAI,CAAC,EAClD,GAAG,CACL,EACS,UACE,YACE,cACA,cACD,aACD,YACX,OAAQ,IAAW,EAAa,GAAM,EAAE,eAAe,EAAI,IAAA,IAC7C,eACd,cAAe,EAAa,GAAM,EAAE,eAAe,EAAI,IAAA,GACvD,gBAAe,EACf,gBAAe,EACf,gBAAe,EACf,eAAc,EACd,KAAM,WAxCR,EA0CI,IAAiB,UAAY,IAAiB,UAC9C,EAAC,MAAD,CACE,iBAAgB,EAChB,cAAA,GACA,UAAW,EACT,EAAO,oBACP,IAAiB,SAAW,EAAO,0BAA4B,EAAO,yBACtE,CACF,EACA,MAAO,CAAE,KAAM,GAAgB,EAAG,GAAG,CAAmB,CACzD,CAAA,EAEF,CACE,GAET"}
1
+ {"version":3,"file":"virtualRow.mjs","names":[],"sources":["../../../../package/common/virtualList/virtualRow.tsx"],"sourcesContent":["import React, { useRef, useLayoutEffect } from 'react';\nimport cx from 'classnames';\n\nimport styles from './virtualList.module.pcss';\nimport type { TreeDropPosition } from './virtualList.types';\n\nexport interface VirtualRowProps {\n index: number;\n top: number;\n /** Padding applied to the row (already normalised to a CSS string). */\n padding?: string;\n columnTemplate: string | undefined;\n isSelected: boolean;\n showDivider: boolean;\n hover: boolean;\n onClick: () => void;\n observer: ResizeObserver | null;\n ariaRowIndex?: number;\n ariaPosInSet?: number;\n ariaSetSize?: number;\n rowRole: 'row' | 'listitem';\n reorderable?: boolean;\n /**\n * Native mouse DnD is active for the list. Distinct from `draggable`, which in\n * `dragHandle` mode is only set on the row the pointer has armed.\n */\n mouseDragEnabled?: boolean;\n draggable?: boolean;\n isDragging?: boolean;\n reserveToggleGutter?: boolean;\n onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;\n onMouseOver?: (e: React.MouseEvent<HTMLDivElement>) => void;\n onMouseLeave?: (e: React.MouseEvent<HTMLDivElement>) => void;\n onDragStart?: (e: React.DragEvent<HTMLDivElement>) => void;\n onDragOver?: (e: React.DragEvent<HTMLDivElement>) => void;\n onDragEnd?: () => void;\n onDrop?: (e: React.DragEvent<HTMLDivElement>) => void;\n onTouchStart?: (e: React.TouchEvent<HTMLDivElement>) => void;\n dropPosition?: TreeDropPosition;\n dropIndentPx?: number;\n dropIndicatorClassName?: string;\n dropIndicatorStyle?: React.CSSProperties;\n rowClassName?: string;\n rowStyle?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/**\n * A single virtualized row: absolutely positioned at its `top`, optionally a\n * grid (table mode), registering itself with the shared ResizeObserver and\n * carrying all the drag / drop-indicator wiring the parent assigns it.\n */\nfunction VirtualRow({\n index,\n top,\n padding,\n columnTemplate,\n isSelected,\n showDivider,\n hover,\n onClick,\n observer,\n ariaRowIndex,\n ariaPosInSet,\n ariaSetSize,\n rowRole,\n reorderable,\n mouseDragEnabled,\n draggable,\n isDragging,\n reserveToggleGutter,\n onMouseDown,\n onMouseOver,\n onMouseLeave,\n onDragStart,\n onDragOver,\n onDragEnd,\n onDrop,\n onTouchStart,\n dropPosition,\n dropIndentPx,\n dropIndicatorClassName,\n dropIndicatorStyle,\n rowClassName,\n rowStyle,\n children,\n}: VirtualRowProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n // A single observer is shared across all rows (created by the parent); each\n // row just registers/unregisters its element. The parent reads the row index\n // back from the `data-index` attribute when the observer fires.\n useLayoutEffect(() => {\n const el = ref.current;\n if (!el || !observer) return;\n observer.observe(el);\n return () => observer.unobserve(el);\n }, [observer]);\n\n return (\n <div\n ref={ref}\n data-index={index}\n className={cx(\n styles.virtualListRow,\n isSelected && styles.virtualListRowSelected,\n !showDivider && styles.virtualListRowNoDivider,\n !hover && styles.virtualListRowNoHover,\n reorderable && styles.virtualListRowDraggable,\n isDragging && styles.virtualListRowDragging,\n dropPosition === 'inside' && styles.virtualListRowDropInside,\n rowClassName,\n )}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n transform: `translateY(${top}px)`,\n ...(padding != null ? { padding } : {}),\n ...(columnTemplate ? { display: 'grid', gridTemplateColumns: columnTemplate } : {}),\n // Match the header's reserved gutter for the column-toggle cog so row\n // cells line up with their header cells instead of drifting under it.\n // Applied after `padding` so the alignment gutter always wins on the right.\n ...(reserveToggleGutter ? { paddingRight: 32 } : {}),\n ...rowStyle,\n }}\n onClick={onClick}\n draggable={draggable}\n onMouseDown={onMouseDown}\n onMouseOver={onMouseOver}\n onMouseLeave={onMouseLeave}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n onDrop={onDrop ?? (mouseDragEnabled ? (e) => e.preventDefault() : undefined)}\n onTouchStart={onTouchStart}\n onContextMenu={mouseDragEnabled ? (e) => e.preventDefault() : undefined}\n aria-selected={isSelected}\n aria-rowindex={ariaRowIndex}\n aria-posinset={ariaPosInSet}\n aria-setsize={ariaSetSize}\n role={rowRole}\n >\n {(dropPosition === 'before' || dropPosition === 'after') && (\n <div\n data-drop-line={dropPosition}\n aria-hidden\n className={cx(\n styles.virtualListDropLine,\n dropPosition === 'before' ? styles.virtualListDropLineBefore : styles.virtualListDropLineAfter,\n dropIndicatorClassName,\n )}\n style={{ left: dropIndentPx ?? 0, ...dropIndicatorStyle }}\n />\n )}\n {children}\n </div>\n );\n}\n\nexport default VirtualRow;\n"],"mappings":"wKAoDA,SAAS,EAAW,CAClB,QACA,MACA,UACA,iBACA,aACA,cACA,QACA,UACA,WACA,eACA,eACA,cACA,UACA,cACA,mBACA,YACA,aACA,sBACA,cACA,cACA,eACA,cACA,aACA,YACA,SACA,eACA,eACA,eACA,yBACA,qBACA,eACA,WACA,YACkB,CAClB,IAAM,EAAM,EAAuB,IAAI,EAYvC,OAPA,MAAsB,CACpB,IAAM,EAAK,EAAI,QACX,MAAC,GAAM,CAAC,GAEZ,OADA,EAAS,QAAQ,CAAE,MACN,EAAS,UAAU,CAAE,CACpC,EAAG,CAAC,CAAQ,CAAC,EAGX,EAAC,MAAD,CACO,MACL,aAAY,EACZ,UAAW,EACT,EAAO,eACP,GAAc,EAAO,uBACrB,CAAC,GAAe,EAAO,wBACvB,CAAC,GAAS,EAAO,sBACjB,GAAe,EAAO,wBACtB,GAAc,EAAO,uBACrB,IAAiB,UAAY,EAAO,yBACpC,CACF,EACA,MAAO,CACL,SAAU,WACV,IAAK,EACL,KAAM,EACN,MAAO,EACP,UAAW,cAAc,EAAI,KAC7B,GAAI,GAAW,KAAqB,CAAC,EAAf,CAAE,SAAQ,EAChC,GAAI,EAAiB,CAAE,QAAS,OAAQ,oBAAqB,CAAe,EAAI,CAAC,EAIjF,GAAI,EAAsB,CAAE,aAAc,EAAG,EAAI,CAAC,EAClD,GAAG,CACL,EACS,UACE,YACE,cACA,cACC,eACD,cACD,aACD,YACX,OAAQ,IAAW,EAAoB,GAAM,EAAE,eAAe,EAAI,IAAA,IACpD,eACd,cAAe,EAAoB,GAAM,EAAE,eAAe,EAAI,IAAA,GAC9D,gBAAe,EACf,gBAAe,EACf,gBAAe,EACf,eAAc,EACd,KAAM,WA1CR,EA4CI,IAAiB,UAAY,IAAiB,UAC9C,EAAC,MAAD,CACE,iBAAgB,EAChB,cAAA,GACA,UAAW,EACT,EAAO,oBACP,IAAiB,SAAW,EAAO,0BAA4B,EAAO,yBACtE,CACF,EACA,MAAO,CAAE,KAAM,GAAgB,EAAG,GAAG,CAAmB,CACzD,CAAA,EAEF,CACE,GAET"}
@@ -1 +1 @@
1
- import{AccordionStyleType as e}from"./common/accordion/accordion.types.mjs";import t from"./common/configProvider/configProvider.mjs";import{useComponentDefaults as n}from"./common/configProvider/useComponentDefaults.mjs";import r from"./common/accordion/accordion.mjs";import i from"./common/loading/spinnerLoading/index.mjs";import{ButtonSize as a,ButtonStyleType as o,ButtonType as s}from"./common/button/button.types.mjs";import c from"./common/ripple/ripple.mjs";import l from"./common/button/button.mjs";import u from"./common/actionButtons/actionButtons.mjs";import d from"./common/interactableDiv/index.mjs";import f from"./common/actionIcon/actionIcon.mjs";import{AlertStyleType as p}from"./common/alert/alert.types.mjs";import m from"./common/alert/alert.mjs";import h from"./common/animatedLogo/animatedLogo.mjs";import{AnimatedTextUnit as g,AnimatedTextVariant as _}from"./common/animatedText/animatedText.types.mjs";import v from"./common/animatedText/animatedText.mjs";import{BadgePosition as y,BadgeStyleType as b}from"./common/badge/badge.types.mjs";import x from"./common/badge/badge.mjs";import S from"./common/avatar/avatar.mjs";import C from"./common/avatar/avatarGroup.mjs";import w from"./common/bodyEnd/bodyEnd.mjs";import{Align as T}from"./common/floatingMenu/floatingMenu.types.mjs";import E from"./common/floatingMenu/floatingMenu.mjs";import D from"./common/breadcrumb/breadcrumb.mjs";import{CardStyleType as O}from"./common/card/card.types.mjs";import k from"./common/card/Card.mjs";import A from"./common/card/CardHeader.mjs";import j from"./common/card/CardMedia.mjs";import M from"./common/card/CardContent.mjs";import N from"./common/card/CardActions.mjs";import P from"./common/carousel/carousel.mjs";import F from"./common/checkbox/checkbox.mjs";import{ChipStyleType as I}from"./common/chip/chip.types.mjs";import L from"./common/chip/chip.mjs";import R from"./common/chip/chipContainer.mjs";import z from"./common/tooltip/tooltip.mjs";import{InputType as B}from"./common/input/input.types.mjs";import V from"./common/input/input.mjs";import H from"./common/colorPicker/colorPicker.mjs";import U from"./common/modal/modal.mjs";import W from"./common/confirmModal/confirmModal.mjs";import{getLocale as G,mapLocale as K,setLocale as q}from"./services/localization.mjs";import J from"./common/infiniteBlock/infiniteBlock.mjs";import Y from"./common/dropdown/dropdown.mjs";import X from"./common/datePicker/datePicker.mjs";import{DividerTextPosition as Z}from"./common/divider/divider.types.mjs";import Q from"./common/divider/divider.mjs";import $ from"./common/drawer/drawer.mjs";import{DropZoneReturnType as ee,DropZoneStatus as te}from"./common/dropZone/dropZone.types.mjs";import ne from"./common/dropZone/dropZone.mjs";import re from"./common/emptyState/emptyState.mjs";import ie from"./common/fab/fab.mjs";import ae from"./common/iconPicker/iconPicker.mjs";import oe from"./common/idleManager/idleManager.mjs";import se from"./common/inputDropdown/inputDropdown.mjs";import ce from"./common/kanbanBoard/KanbanColumn.mjs";import le from"./common/kanbanBoard/KanbanBoard.mjs";import ue from"./common/searchInput/searchInput.mjs";import de from"./common/klipyPicker/klipyPicker.mjs";import fe from"./common/loading/iconLoading/index.mjs";import pe from"./common/numberInput/index.mjs";import me from"./common/optionPicker/optionPicker.mjs";import he from"./common/overscroll/overscroll.mjs";import{PopoverAlign as ge,PopoverPlacement as _e,PopoverTrigger as ve}from"./common/popover/popover.types.mjs";import ye from"./common/popover/popover.mjs";import be from"./common/progressBar/progressBar.mjs";import{RadioGroupOrientation as xe}from"./common/radioGroup/radioGroup.types.mjs";import Se from"./common/radioGroup/radioGroup.mjs";import Ce from"./common/rating/rating.mjs";import we from"./common/roomDrawer/roomDrawer.mjs";import Te from"./common/roomViewer/roomViewer.mjs";import Ee from"./common/scrollbarProvider/index.mjs";import{SectionHeaderSize as De}from"./common/sectionHeader/sectionHeader.types.mjs";import Oe from"./common/sectionHeader/sectionHeader.mjs";import{SkeletonAnimation as ke,SkeletonVariant as Ae}from"./common/skeleton/skeleton.types.mjs";import je from"./common/skeleton/skeleton.mjs";import Me from"./common/slider/slider.mjs";import{StepperAlignment as Ne,StepperCollapse as Pe,StepperLabelPlacement as Fe,StepperStyleType as Ie}from"./common/stepper/stepper.types.mjs";import Le from"./common/stepper/stepper.mjs";import Re from"./common/sticky/sticky.mjs";import ze from"./common/switch/switch.mjs";import Be from"./common/tabHeader/tabHeader.mjs";import Ve from"./common/textarea/textarea.mjs";import{defaultTheme as He}from"./common/themeProvider/defaultTheme.mjs";import Ue from"./common/themeProvider/themeProvider.mjs";import{useTheme as We}from"./common/themeProvider/useTheme.mjs";import Ge from"./common/timeInput/timeInput.mjs";import{showToast as Ke}from"./common/toast/toastService.mjs";import qe from"./common/toast/toastProvider.mjs";import Je from"./common/virtualList/virtualList.mjs";import Ye from"./common/wizard/wizard.mjs";import Xe from"./services/formValidation/FormValidatorGroupWithForm.mjs";import Ze from"./services/formValidation/validatableComponent.mjs";import{useFormValidatorGroup as Qe}from"./services/formValidation/useFormValidatorGroup.mjs";import{FormValidator as $e,Validators as et,useFormValidator as tt}from"./services/formValidation/index.mjs";import{hasEightPasswordChars as nt,hasOnePasswordDigit as rt,hasOnePasswordLetter as it,isBic as at,isDate as ot,isEmail as st,isISODate as ct,isNumber as lt,isPassword as ut,isURL as dt}from"@ahrowe/form-validation";export{r as Accordion,e as AccordionStyleType,u as ActionButtons,f as ActionIcon,m as Alert,p as AlertStyleType,T as Align,h as AnimatedLogo,v as AnimatedText,g as AnimatedTextUnit,_ as AnimatedTextVariant,S as Avatar,C as AvatarGroup,x as Badge,y as BadgePosition,b as BadgeStyleType,w as BodyEnd,D as Breadcrumb,l as Button,a as ButtonSize,o as ButtonStyleType,s as ButtonType,k as Card,N as CardActions,M as CardContent,A as CardHeader,j as CardMedia,O as CardStyleType,P as Carousel,F as Checkbox,L as Chip,R as ChipContainer,I as ChipStyleType,H as ColorPicker,t as ConfigProvider,W as ConfirmModal,X as DatePicker,Q as Divider,Z as DividerTextPosition,$ as Drawer,ne as DropZone,ee as DropZoneReturnType,te as DropZoneStatus,Y as Dropdown,re as EmptyState,ie as Fab,E as FloatingMenu,$e as FormValidator,Xe as FormValidatorGroup,fe as IconLoading,ae as IconPicker,oe as IdleManager,J as InfiniteBlock,V as Input,se as InputDropdown,B as InputType,d as InteractableDiv,le as KanbanBoard,ce as KanbanColumn,de as KlipyPicker,U as Modal,pe as NumberInput,me as OptionPicker,he as Overscroll,ye as Popover,ge as PopoverAlign,_e as PopoverPlacement,ve as PopoverTrigger,be as ProgressBar,Se as RadioGroup,xe as RadioGroupOrientation,Ce as Rating,c as Ripple,we as RoomDrawer,Te as RoomViewer,Ee as ScrollbarProvider,ue as SearchInput,Oe as SectionHeader,De as SectionHeaderSize,je as Skeleton,ke as SkeletonAnimation,Ae as SkeletonVariant,Me as Slider,i as SpinnerLoading,Le as Stepper,Ne as StepperAlignment,Pe as StepperCollapse,Fe as StepperLabelPlacement,Ie as StepperStyleType,Re as Sticky,ze as Switch,Be as TabHeader,Ve as Textarea,Ue as ThemeProvider,Ge as TimeInput,qe as ToastProvider,z as Tooltip,Ze as ValidatableComponent,et as Validators,Je as VirtualList,Ye as Wizard,He as defaultTheme,G as getLocale,nt as hasEightPasswordChars,rt as hasOnePasswordDigit,it as hasOnePasswordLetter,at as isBic,ot as isDate,st as isEmail,ct as isISODate,lt as isNumber,ut as isPassword,dt as isURL,K as mapLocale,q as setLocale,Ke as showToast,n as useComponentDefaults,tt as useFormValidator,Qe as useFormValidatorGroup,We as useTheme};
1
+ import{AccordionStyleType as e}from"./common/accordion/accordion.types.mjs";import t from"./common/configProvider/configProvider.mjs";import{useComponentDefaults as n}from"./common/configProvider/useComponentDefaults.mjs";import r from"./common/accordion/accordion.mjs";import i from"./common/loading/spinnerLoading/index.mjs";import{ButtonSize as a,ButtonStyleType as o,ButtonType as s}from"./common/button/button.types.mjs";import c from"./common/ripple/ripple.mjs";import l from"./common/button/button.mjs";import u from"./common/actionButtons/actionButtons.mjs";import d from"./common/interactableDiv/index.mjs";import f from"./common/actionIcon/actionIcon.mjs";import{AlertStyleType as p}from"./common/alert/alert.types.mjs";import m from"./common/alert/alert.mjs";import h from"./common/animatedLogo/animatedLogo.mjs";import{AnimatedTextUnit as g,AnimatedTextVariant as _}from"./common/animatedText/animatedText.types.mjs";import v from"./common/animatedText/animatedText.mjs";import{BadgePosition as y,BadgeStyleType as b}from"./common/badge/badge.types.mjs";import x from"./common/badge/badge.mjs";import S from"./common/avatar/avatar.mjs";import C from"./common/avatar/avatarGroup.mjs";import w from"./common/bodyEnd/bodyEnd.mjs";import{Align as T}from"./common/floatingMenu/floatingMenu.types.mjs";import E from"./common/floatingMenu/floatingMenu.mjs";import D from"./common/breadcrumb/breadcrumb.mjs";import{ButtonGroupOrientation as O}from"./common/buttonGroup/buttonGroup.types.mjs";import k from"./common/buttonGroup/buttonGroup.mjs";import{CardStyleType as A}from"./common/card/card.types.mjs";import j from"./common/card/Card.mjs";import M from"./common/card/CardHeader.mjs";import N from"./common/card/CardMedia.mjs";import P from"./common/card/CardContent.mjs";import F from"./common/card/CardActions.mjs";import I from"./common/carousel/carousel.mjs";import L from"./common/checkbox/checkbox.mjs";import{ChipStyleType as R}from"./common/chip/chip.types.mjs";import z from"./common/chip/chip.mjs";import B from"./common/chip/chipContainer.mjs";import V from"./common/tooltip/tooltip.mjs";import{InputIconPosition as H,InputType as U}from"./common/input/input.types.mjs";import W from"./common/input/input.mjs";import G from"./common/colorPicker/colorPicker.mjs";import K from"./common/modal/modal.mjs";import q from"./common/confirmModal/confirmModal.mjs";import{getLocale as J,mapLocale as Y,setLocale as X}from"./services/localization.mjs";import Z from"./common/infiniteBlock/infiniteBlock.mjs";import Q from"./common/dropdown/dropdown.mjs";import $ from"./common/datePicker/datePicker.mjs";import{DividerOrientation as ee,DividerTextPosition as te}from"./common/divider/divider.types.mjs";import ne from"./common/divider/divider.mjs";import re from"./common/drawer/drawer.mjs";import{DropZoneReturnType as ie,DropZoneStatus as ae}from"./common/dropZone/dropZone.types.mjs";import oe from"./common/dropZone/dropZone.mjs";import se from"./common/emptyState/emptyState.mjs";import ce from"./common/fab/fab.mjs";import le from"./common/iconPicker/iconPicker.mjs";import ue from"./common/idleManager/idleManager.mjs";import de from"./common/inputDropdown/inputDropdown.mjs";import fe from"./common/kanbanBoard/KanbanColumn.mjs";import pe from"./common/kanbanBoard/KanbanBoard.mjs";import me from"./common/searchInput/searchInput.mjs";import he from"./common/klipyPicker/klipyPicker.mjs";import ge from"./common/loading/iconLoading/index.mjs";import _e from"./common/numberInput/index.mjs";import ve from"./common/optionPicker/optionPicker.mjs";import ye from"./common/overscroll/overscroll.mjs";import{PopoverAlign as be,PopoverPlacement as xe,PopoverTrigger as Se}from"./common/popover/popover.types.mjs";import Ce from"./common/popover/popover.mjs";import we from"./common/progressBar/progressBar.mjs";import{RadioGroupOrientation as Te}from"./common/radioGroup/radioGroup.types.mjs";import Ee from"./common/radioGroup/radioGroup.mjs";import De from"./common/rating/rating.mjs";import Oe from"./common/roomDrawer/roomDrawer.mjs";import ke from"./common/roomViewer/roomViewer.mjs";import Ae from"./common/scrollbarProvider/index.mjs";import{SectionHeaderSize as je}from"./common/sectionHeader/sectionHeader.types.mjs";import Me from"./common/sectionHeader/sectionHeader.mjs";import{SkeletonAnimation as Ne,SkeletonVariant as Pe}from"./common/skeleton/skeleton.types.mjs";import Fe from"./common/skeleton/skeleton.mjs";import Ie from"./common/slider/slider.mjs";import Le from"./common/splitButton/splitButton.mjs";import{StepperAlignment as Re,StepperCollapse as ze,StepperLabelPlacement as Be,StepperStyleType as Ve}from"./common/stepper/stepper.types.mjs";import He from"./common/stepper/stepper.mjs";import Ue from"./common/sticky/sticky.mjs";import We from"./common/switch/switch.mjs";import Ge from"./common/tabHeader/tabHeader.mjs";import Ke from"./common/textarea/textarea.mjs";import{defaultTheme as qe}from"./common/themeProvider/defaultTheme.mjs";import Je from"./common/themeProvider/themeProvider.mjs";import{useTheme as Ye}from"./common/themeProvider/useTheme.mjs";import Xe from"./common/timeInput/timeInput.mjs";import{showToast as Ze}from"./common/toast/toastService.mjs";import Qe from"./common/toast/toastProvider.mjs";import $e from"./common/virtualList/virtualList.mjs";import et from"./common/wizard/wizard.mjs";import tt from"./services/formValidation/FormValidatorGroupWithForm.mjs";import nt from"./services/formValidation/validatableComponent.mjs";import{useFormValidatorGroup as rt}from"./services/formValidation/useFormValidatorGroup.mjs";import{FormValidator as it,Validators as at,useFormValidator as ot}from"./services/formValidation/index.mjs";import{hasEightPasswordChars as st,hasOnePasswordDigit as ct,hasOnePasswordLetter as lt,isBic as ut,isDate as dt,isEmail as ft,isISODate as pt,isNumber as mt,isPassword as ht,isURL as gt}from"@ahrowe/form-validation";export{r as Accordion,e as AccordionStyleType,u as ActionButtons,f as ActionIcon,m as Alert,p as AlertStyleType,T as Align,h as AnimatedLogo,v as AnimatedText,g as AnimatedTextUnit,_ as AnimatedTextVariant,S as Avatar,C as AvatarGroup,x as Badge,y as BadgePosition,b as BadgeStyleType,w as BodyEnd,D as Breadcrumb,l as Button,k as ButtonGroup,O as ButtonGroupOrientation,a as ButtonSize,o as ButtonStyleType,s as ButtonType,j as Card,F as CardActions,P as CardContent,M as CardHeader,N as CardMedia,A as CardStyleType,I as Carousel,L as Checkbox,z as Chip,B as ChipContainer,R as ChipStyleType,G as ColorPicker,t as ConfigProvider,q as ConfirmModal,$ as DatePicker,ne as Divider,ee as DividerOrientation,te as DividerTextPosition,re as Drawer,oe as DropZone,ie as DropZoneReturnType,ae as DropZoneStatus,Q as Dropdown,se as EmptyState,ce as Fab,E as FloatingMenu,it as FormValidator,tt as FormValidatorGroup,ge as IconLoading,le as IconPicker,ue as IdleManager,Z as InfiniteBlock,W as Input,de as InputDropdown,H as InputIconPosition,U as InputType,d as InteractableDiv,pe as KanbanBoard,fe as KanbanColumn,he as KlipyPicker,K as Modal,_e as NumberInput,ve as OptionPicker,ye as Overscroll,Ce as Popover,be as PopoverAlign,xe as PopoverPlacement,Se as PopoverTrigger,we as ProgressBar,Ee as RadioGroup,Te as RadioGroupOrientation,De as Rating,c as Ripple,Oe as RoomDrawer,ke as RoomViewer,Ae as ScrollbarProvider,me as SearchInput,Me as SectionHeader,je as SectionHeaderSize,Fe as Skeleton,Ne as SkeletonAnimation,Pe as SkeletonVariant,Ie as Slider,i as SpinnerLoading,Le as SplitButton,He as Stepper,Re as StepperAlignment,ze as StepperCollapse,Be as StepperLabelPlacement,Ve as StepperStyleType,Ue as Sticky,We as Switch,Ge as TabHeader,Ke as Textarea,Je as ThemeProvider,Xe as TimeInput,Qe as ToastProvider,V as Tooltip,nt as ValidatableComponent,at as Validators,$e as VirtualList,et as Wizard,qe as defaultTheme,J as getLocale,st as hasEightPasswordChars,ct as hasOnePasswordDigit,lt as hasOnePasswordLetter,ut as isBic,dt as isDate,ft as isEmail,pt as isISODate,mt as isNumber,ht as isPassword,gt as isURL,Y as mapLocale,X as setLocale,Ze as showToast,n as useComponentDefaults,ot as useFormValidator,rt as useFormValidatorGroup,Ye as useTheme};