@prismiq/react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/{CustomSQLEditor-DYeId0Gp.d.ts → ChatBubble-ARocmvZD.d.cts} +48 -4
  2. package/dist/{CustomSQLEditor-BXB4rf1q.d.cts → ChatBubble-BN_CjIpk.d.ts} +48 -4
  3. package/dist/{DashboardDialog-B3vYC5Gs.d.ts → DashboardDialog-UhUGXx2h.d.ts} +6 -4
  4. package/dist/{DashboardDialog-LHmrtNQU.d.cts → DashboardDialog-Z-HypxmG.d.cts} +6 -4
  5. package/dist/{accessibility-2yy5yqRR.d.cts → accessibility-Bu2mNtaB.d.cts} +1 -1
  6. package/dist/{accessibility-2yy5yqRR.d.ts → accessibility-Bu2mNtaB.d.ts} +1 -1
  7. package/dist/charts/index.cjs +27 -27
  8. package/dist/charts/index.d.cts +2 -2
  9. package/dist/charts/index.d.ts +2 -2
  10. package/dist/charts/index.js +2 -2
  11. package/dist/{chunk-NK7HKX2J.cjs → chunk-73TPDGXB.cjs} +7 -7
  12. package/dist/{chunk-NK7HKX2J.cjs.map → chunk-73TPDGXB.cjs.map} +1 -1
  13. package/dist/{chunk-FEABEF3J.cjs → chunk-FKXCINUF.cjs} +551 -299
  14. package/dist/chunk-FKXCINUF.cjs.map +1 -0
  15. package/dist/{chunk-2H5WTH4K.js → chunk-FQ23KG6G.js} +3 -3
  16. package/dist/{chunk-2H5WTH4K.js.map → chunk-FQ23KG6G.js.map} +1 -1
  17. package/dist/{chunk-UPYINBZU.js → chunk-GELI7MDZ.js} +982 -51
  18. package/dist/chunk-GELI7MDZ.js.map +1 -0
  19. package/dist/{chunk-WWTT2OJ5.js → chunk-HKZFEXT6.js} +27 -9
  20. package/dist/chunk-HKZFEXT6.js.map +1 -0
  21. package/dist/{chunk-MOAEEF5P.js → chunk-JBJ5LEAG.js} +362 -110
  22. package/dist/chunk-JBJ5LEAG.js.map +1 -0
  23. package/dist/{chunk-4AVL6GQK.cjs → chunk-KXB2IZI2.cjs} +36 -9
  24. package/dist/chunk-KXB2IZI2.cjs.map +1 -0
  25. package/dist/{chunk-EX74SI67.js → chunk-LBE6GIBC.js} +36 -9
  26. package/dist/chunk-LBE6GIBC.js.map +1 -0
  27. package/dist/{chunk-NY6TZLST.cjs → chunk-PG7QBH3G.cjs} +988 -53
  28. package/dist/chunk-PG7QBH3G.cjs.map +1 -0
  29. package/dist/{chunk-MDXGGZSW.cjs → chunk-ZYVN6XAZ.cjs} +35 -37
  30. package/dist/chunk-ZYVN6XAZ.cjs.map +1 -0
  31. package/dist/components/index.cjs +63 -55
  32. package/dist/components/index.d.cts +2 -2
  33. package/dist/components/index.d.ts +2 -2
  34. package/dist/components/index.js +2 -2
  35. package/dist/dashboard/index.cjs +36 -36
  36. package/dist/dashboard/index.d.cts +7 -5
  37. package/dist/dashboard/index.d.ts +7 -5
  38. package/dist/dashboard/index.js +4 -4
  39. package/dist/export/index.cjs +7 -7
  40. package/dist/export/index.d.cts +6 -4
  41. package/dist/export/index.d.ts +6 -4
  42. package/dist/export/index.js +1 -1
  43. package/dist/{index-C-Qcuu4Y.d.cts → index-B8DelfpL.d.cts} +2 -2
  44. package/dist/{index-rPc7ijt8.d.ts → index-RbfYPQD_.d.ts} +2 -2
  45. package/dist/index.cjs +150 -134
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +97 -9
  48. package/dist/index.d.ts +97 -9
  49. package/dist/index.js +7 -7
  50. package/dist/index.js.map +1 -1
  51. package/dist/{types-WrCbOeAV.d.cts → types-ccB9Ps3k.d.cts} +59 -1
  52. package/dist/{types-WrCbOeAV.d.ts → types-ccB9Ps3k.d.ts} +59 -1
  53. package/dist/utils/index.cjs +15 -15
  54. package/dist/utils/index.d.cts +5 -21
  55. package/dist/utils/index.d.ts +5 -21
  56. package/dist/utils/index.js +1 -1
  57. package/package.json +3 -7
  58. package/dist/chunk-4AVL6GQK.cjs.map +0 -1
  59. package/dist/chunk-EX74SI67.js.map +0 -1
  60. package/dist/chunk-FEABEF3J.cjs.map +0 -1
  61. package/dist/chunk-MDXGGZSW.cjs.map +0 -1
  62. package/dist/chunk-MOAEEF5P.js.map +0 -1
  63. package/dist/chunk-NY6TZLST.cjs.map +0 -1
  64. package/dist/chunk-UPYINBZU.js.map +0 -1
  65. package/dist/chunk-WWTT2OJ5.js.map +0 -1
@@ -314,14 +314,18 @@ function formatDateWithPattern(date, pattern) {
314
314
  result = result.replace(/__QUARTER_PLACEHOLDER__/g, `Q${quarter}`);
315
315
  result = result.replace(/yyyy/g, String(year).padStart(4, "0"));
316
316
  result = result.replace(/yy/g, String(year % 100).padStart(2, "0"));
317
- result = result.replace(/MMMM/g, monthNamesFull[month - 1] || "");
318
- result = result.replace(/MMM/g, monthNamesShort[month - 1] || "");
317
+ result = result.replace(/MMMM/g, "\xAB1\xBB");
318
+ result = result.replace(/MMM/g, "\xAB2\xBB");
319
319
  result = result.replace(/MM/g, String(month).padStart(2, "0"));
320
320
  result = result.replace(/M/g, String(month));
321
- result = result.replace(/dddd/g, dayNamesFull[date.getDay()] || "");
322
- result = result.replace(/ddd/g, dayNamesShort[date.getDay()] || "");
321
+ result = result.replace(/dddd/g, "\xAB3\xBB");
322
+ result = result.replace(/ddd/g, "\xAB4\xBB");
323
323
  result = result.replace(/dd/g, String(day).padStart(2, "0"));
324
324
  result = result.replace(/d/g, String(day));
325
+ result = result.replace(/«1»/g, monthNamesFull[month - 1] || "");
326
+ result = result.replace(/«2»/g, monthNamesShort[month - 1] || "");
327
+ result = result.replace(/«3»/g, dayNamesFull[date.getDay()] || "");
328
+ result = result.replace(/«4»/g, dayNamesShort[date.getDay()] || "");
325
329
  result = result.replace(/HH/g, String(hours).padStart(2, "0"));
326
330
  result = result.replace(/H/g, String(hours));
327
331
  const hours12 = hours % 12 || 12;
@@ -368,8 +372,25 @@ function formatRelativeTime(timestamp) {
368
372
  }
369
373
 
370
374
  // src/utils/pivot.ts
375
+ function formatPivotValue(value, dateFormat) {
376
+ const strValue = String(value);
377
+ if (!dateFormat) {
378
+ return strValue;
379
+ }
380
+ try {
381
+ if (strValue.match(/^\d{4}-\d{2}-\d{2}/)) {
382
+ const formatter = createDateFormatter(dateFormat);
383
+ const formatted = formatter(strValue);
384
+ if (formatted && formatted !== strValue) {
385
+ return formatted;
386
+ }
387
+ }
388
+ } catch {
389
+ }
390
+ return strValue;
391
+ }
371
392
  function pivotQueryResult(result, config) {
372
- const { pivotColumn, valueColumn, dimensionColumns } = config;
393
+ const { pivotColumn, valueColumn, dimensionColumns, pivotColumnFormat } = config;
373
394
  const pivotColIndex = result.columns.indexOf(pivotColumn);
374
395
  const valueColIndex = result.columns.indexOf(valueColumn);
375
396
  if (pivotColIndex === -1 || valueColIndex === -1) {
@@ -378,9 +399,14 @@ function pivotQueryResult(result, config) {
378
399
  );
379
400
  return result;
380
401
  }
381
- const pivotValues = Array.from(
402
+ const rawPivotValues = Array.from(
382
403
  new Set(result.rows.map((row) => String(row[pivotColIndex])))
383
404
  ).sort();
405
+ const pivotValueToDisplay = /* @__PURE__ */ new Map();
406
+ for (const raw of rawPivotValues) {
407
+ pivotValueToDisplay.set(raw, formatPivotValue(raw, pivotColumnFormat));
408
+ }
409
+ const pivotValues = rawPivotValues;
384
410
  const dimIndices = dimensionColumns.map((col) => result.columns.indexOf(col)).filter((idx) => idx !== -1);
385
411
  const grouped = /* @__PURE__ */ new Map();
386
412
  for (const row of result.rows) {
@@ -395,7 +421,8 @@ function pivotQueryResult(result, config) {
395
421
  const value = row[valueColIndex];
396
422
  grouped.get(key).set(pivotValue, value);
397
423
  }
398
- const newColumns = [...dimensionColumns, ...pivotValues];
424
+ const displayColumns = pivotValues.map((pv) => pivotValueToDisplay.get(pv) ?? pv);
425
+ const newColumns = [...dimensionColumns, ...displayColumns];
399
426
  const newRows = [];
400
427
  for (const [_key, valueMap] of grouped.entries()) {
401
428
  const dimValues = valueMap.get("__dim_values__");
@@ -466,5 +493,5 @@ exports.useArrowNavigation = useArrowNavigation;
466
493
  exports.useFocusTrap = useFocusTrap;
467
494
  exports.useFocusVisible = useFocusVisible;
468
495
  exports.useRovingTabIndex = useRovingTabIndex;
469
- //# sourceMappingURL=chunk-4AVL6GQK.cjs.map
470
- //# sourceMappingURL=chunk-4AVL6GQK.cjs.map
496
+ //# sourceMappingURL=chunk-KXB2IZI2.cjs.map
497
+ //# sourceMappingURL=chunk-KXB2IZI2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/accessibility.ts","../src/utils/dateFormat.ts","../src/utils/pivot.ts","../src/utils/columnRef.ts","../src/utils/safeMarkdown.ts"],"names":["useRef","useState","useCallback","useEffect"],"mappings":"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","file":"chunk-KXB2IZI2.cjs","sourcesContent":["'use client';\n\n/**\n * Accessibility utilities for keyboard navigation and screen readers.\n */\n\nimport { useCallback, useEffect, useRef, useState, type RefObject } from 'react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface FocusTrapOptions {\n /** Whether the focus trap is active. */\n active?: boolean;\n /** Whether to focus the first focusable element when activated. */\n autoFocus?: boolean;\n /** Whether to restore focus when deactivated. */\n restoreFocus?: boolean;\n /** Called when Escape is pressed. */\n onEscape?: () => void;\n}\n\nexport interface ArrowNavigationOptions {\n /** Whether navigation wraps around at edges. */\n wrap?: boolean;\n /** Orientation for arrow key mapping. */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /** Callback when active item changes. */\n onActiveChange?: (index: number) => void;\n}\n\nexport interface UseFocusTrapResult {\n /** Ref to attach to the container element. */\n containerRef: RefObject<HTMLElement>;\n /** Activate the focus trap. */\n activate: () => void;\n /** Deactivate the focus trap. */\n deactivate: () => void;\n /** Whether the trap is active. */\n isActive: boolean;\n}\n\nexport interface UseArrowNavigationResult {\n /** Current active index. */\n activeIndex: number;\n /** Set active index. */\n setActiveIndex: (index: number) => void;\n /** Key down handler to attach to container. */\n onKeyDown: (event: React.KeyboardEvent) => void;\n /** Get props for an item. */\n getItemProps: (index: number) => {\n tabIndex: number;\n 'aria-selected': boolean;\n onFocus: () => void;\n };\n}\n\n// ============================================================================\n// Focus Trap Hook\n// ============================================================================\n\n/**\n * Selector for focusable elements.\n */\nconst FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'a[href]',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(', ');\n\n/**\n * Get all focusable elements within a container.\n */\nfunction getFocusableElements(container: HTMLElement): HTMLElement[] {\n const elements = container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);\n return Array.from(elements).filter(\n (el) => !el.hasAttribute('aria-hidden') && el.offsetParent !== null\n );\n}\n\n/**\n * Hook to trap focus within a container.\n *\n * @param options - Focus trap options\n * @returns Focus trap controls\n *\n * @example\n * ```tsx\n * function Modal({ isOpen, onClose }) {\n * const { containerRef, activate, deactivate } = useFocusTrap({\n * active: isOpen,\n * onEscape: onClose,\n * });\n *\n * return (\n * <div ref={containerRef} role=\"dialog\" aria-modal=\"true\">\n * <button onClick={onClose}>Close</button>\n * <input type=\"text\" />\n * </div>\n * );\n * }\n * ```\n */\nexport function useFocusTrap(options: FocusTrapOptions = {}): UseFocusTrapResult {\n const {\n active = true,\n autoFocus = true,\n restoreFocus = true,\n onEscape,\n } = options;\n\n const containerRef = useRef<HTMLElement>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const [isActive, setIsActive] = useState(active);\n\n const activate = useCallback(() => {\n if (!containerRef.current) return;\n\n // Store previously focused element\n previousFocusRef.current = document.activeElement as HTMLElement | null;\n\n // Focus first focusable element\n if (autoFocus) {\n const focusable = getFocusableElements(containerRef.current);\n const firstElement = focusable[0];\n if (firstElement) {\n firstElement.focus();\n }\n }\n\n setIsActive(true);\n }, [autoFocus]);\n\n const deactivate = useCallback(() => {\n setIsActive(false);\n\n // Restore focus\n if (restoreFocus && previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n }, [restoreFocus]);\n\n // Handle focus trap\n useEffect(() => {\n if (!isActive || !containerRef.current) return;\n\n const container = containerRef.current;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onEscape?.();\n return;\n }\n\n if (event.key !== 'Tab') return;\n\n const focusable = getFocusableElements(container);\n if (focusable.length === 0) return;\n\n const firstElement = focusable[0];\n const lastElement = focusable[focusable.length - 1];\n\n // Guard against undefined (though array check above should prevent this)\n if (!firstElement || !lastElement) return;\n\n // Shift+Tab on first element -> focus last\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n return;\n }\n\n // Tab on last element -> focus first\n if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n };\n\n // Handle focus escaping the container\n const handleFocusIn = (event: FocusEvent) => {\n if (!container.contains(event.target as Node)) {\n const focusable = getFocusableElements(container);\n const firstElement = focusable[0];\n if (firstElement) {\n firstElement.focus();\n }\n }\n };\n\n container.addEventListener('keydown', handleKeyDown);\n document.addEventListener('focusin', handleFocusIn);\n\n return () => {\n container.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('focusin', handleFocusIn);\n };\n }, [isActive, onEscape]);\n\n // Auto-activate when active prop changes\n useEffect(() => {\n if (active) {\n activate();\n } else {\n deactivate();\n }\n }, [active, activate, deactivate]);\n\n return {\n containerRef: containerRef as RefObject<HTMLElement>,\n activate,\n deactivate,\n isActive,\n };\n}\n\n// ============================================================================\n// Arrow Navigation Hook\n// ============================================================================\n\n/**\n * Hook for arrow key navigation through a list of items.\n *\n * @param itemCount - Number of items in the list\n * @param options - Navigation options\n * @returns Navigation state and handlers\n *\n * @example\n * ```tsx\n * function Menu({ items }) {\n * const { activeIndex, onKeyDown, getItemProps } = useArrowNavigation(items.length);\n *\n * return (\n * <ul role=\"menu\" onKeyDown={onKeyDown}>\n * {items.map((item, index) => (\n * <li key={index} role=\"menuitem\" {...getItemProps(index)}>\n * {item}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useArrowNavigation(\n itemCount: number,\n options: ArrowNavigationOptions = {}\n): UseArrowNavigationResult {\n const { wrap = true, orientation = 'vertical', onActiveChange } = options;\n\n const [activeIndex, setActiveIndex] = useState(0);\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n let newIndex = activeIndex;\n let handled = false;\n\n // Map arrow keys based on orientation\n const isNext =\n (orientation === 'vertical' && event.key === 'ArrowDown') ||\n (orientation === 'horizontal' && event.key === 'ArrowRight') ||\n (orientation === 'both' && (event.key === 'ArrowDown' || event.key === 'ArrowRight'));\n\n const isPrev =\n (orientation === 'vertical' && event.key === 'ArrowUp') ||\n (orientation === 'horizontal' && event.key === 'ArrowLeft') ||\n (orientation === 'both' && (event.key === 'ArrowUp' || event.key === 'ArrowLeft'));\n\n if (isNext) {\n handled = true;\n if (activeIndex < itemCount - 1) {\n newIndex = activeIndex + 1;\n } else if (wrap) {\n newIndex = 0;\n }\n } else if (isPrev) {\n handled = true;\n if (activeIndex > 0) {\n newIndex = activeIndex - 1;\n } else if (wrap) {\n newIndex = itemCount - 1;\n }\n } else if (event.key === 'Home') {\n handled = true;\n newIndex = 0;\n } else if (event.key === 'End') {\n handled = true;\n newIndex = itemCount - 1;\n }\n\n if (handled) {\n event.preventDefault();\n setActiveIndex(newIndex);\n onActiveChange?.(newIndex);\n }\n },\n [activeIndex, itemCount, wrap, orientation, onActiveChange]\n );\n\n const getItemProps = useCallback(\n (index: number) => ({\n tabIndex: index === activeIndex ? 0 : -1,\n 'aria-selected': index === activeIndex,\n onFocus: () => {\n setActiveIndex(index);\n onActiveChange?.(index);\n },\n }),\n [activeIndex, onActiveChange]\n );\n\n // Update active index setter to also call callback\n const handleSetActiveIndex = useCallback(\n (index: number) => {\n setActiveIndex(index);\n onActiveChange?.(index);\n },\n [onActiveChange]\n );\n\n return {\n activeIndex,\n setActiveIndex: handleSetActiveIndex,\n onKeyDown: handleKeyDown,\n getItemProps,\n };\n}\n\n// ============================================================================\n// Screen Reader Announcements\n// ============================================================================\n\nlet announceElement: HTMLElement | null = null;\n\n/**\n * Get or create the live region element for announcements.\n */\nfunction getAnnounceElement(): HTMLElement {\n if (announceElement) return announceElement;\n\n // Check if we're in a browser environment\n if (typeof document === 'undefined') {\n throw new Error('announceToScreenReader can only be used in browser environment');\n }\n\n announceElement = document.createElement('div');\n announceElement.setAttribute('role', 'status');\n announceElement.setAttribute('aria-live', 'polite');\n announceElement.setAttribute('aria-atomic', 'true');\n announceElement.style.cssText = [\n 'position: absolute',\n 'width: 1px',\n 'height: 1px',\n 'padding: 0',\n 'margin: -1px',\n 'overflow: hidden',\n 'clip: rect(0, 0, 0, 0)',\n 'white-space: nowrap',\n 'border: 0',\n ].join(';');\n announceElement.id = 'prismiq-announcer';\n\n document.body.appendChild(announceElement);\n return announceElement;\n}\n\n/**\n * Announce a message to screen readers.\n *\n * @param message - The message to announce\n * @param priority - Announcement priority ('polite' or 'assertive')\n *\n * @example\n * ```tsx\n * // Announce a status update\n * announceToScreenReader('Results loaded: 42 items');\n *\n * // Urgent announcement\n * announceToScreenReader('Error: Connection lost', 'assertive');\n * ```\n */\nexport function announceToScreenReader(\n message: string,\n priority: 'polite' | 'assertive' = 'polite'\n): void {\n // Skip in SSR\n if (typeof document === 'undefined') return;\n\n const element = getAnnounceElement();\n element.setAttribute('aria-live', priority);\n\n // Clear and set message (this triggers announcement)\n element.textContent = '';\n // Use requestAnimationFrame to ensure the clear happens first\n requestAnimationFrame(() => {\n element.textContent = message;\n });\n}\n\n// ============================================================================\n// Focus Visible\n// ============================================================================\n\n/**\n * CSS for focus-visible styling.\n * Add this to your global styles or use the useFocusVisible hook.\n */\nexport const focusVisibleStyles = `\n /* Hide focus outline for mouse users */\n :focus:not(:focus-visible) {\n outline: none;\n }\n\n /* Show focus outline for keyboard users */\n :focus-visible {\n outline: 2px solid var(--prismiq-color-primary);\n outline-offset: 2px;\n }\n\n /* Prismiq focus ring class */\n .prismiq-focus-ring:focus-visible {\n outline: 2px solid var(--prismiq-color-primary);\n outline-offset: 2px;\n box-shadow: 0 0 0 4px rgba(var(--prismiq-color-primary-rgb), 0.2);\n }\n`;\n\n/**\n * Hook to detect if focus is visible (keyboard navigation).\n */\nexport function useFocusVisible(): boolean {\n const [focusVisible, setFocusVisible] = useState(false);\n\n useEffect(() => {\n // Skip in SSR\n if (typeof window === 'undefined') return;\n\n let hadKeyboardEvent = false;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Tab') {\n hadKeyboardEvent = true;\n }\n };\n\n const handlePointerDown = () => {\n hadKeyboardEvent = false;\n };\n\n const handleFocus = () => {\n setFocusVisible(hadKeyboardEvent);\n };\n\n const handleBlur = () => {\n setFocusVisible(false);\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n document.addEventListener('pointerdown', handlePointerDown, true);\n document.addEventListener('focus', handleFocus, true);\n document.addEventListener('blur', handleBlur, true);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown, true);\n document.removeEventListener('pointerdown', handlePointerDown, true);\n document.removeEventListener('focus', handleFocus, true);\n document.removeEventListener('blur', handleBlur, true);\n };\n }, []);\n\n return focusVisible;\n}\n\n// ============================================================================\n// Skip Link\n// ============================================================================\n\n/**\n * Props for the skip link component.\n */\nexport interface SkipLinkProps {\n /** Target element ID to skip to. */\n targetId: string;\n /** Link text. */\n children?: React.ReactNode;\n}\n\n/**\n * Styles for skip link (visually hidden until focused).\n */\nexport const skipLinkStyles: React.CSSProperties = {\n position: 'absolute',\n left: '-9999px',\n zIndex: 9999,\n padding: '1em',\n backgroundColor: 'var(--prismiq-color-background)',\n color: 'var(--prismiq-color-primary)',\n textDecoration: 'underline',\n // When focused, show the link\n};\n\nexport const skipLinkFocusStyles: React.CSSProperties = {\n ...skipLinkStyles,\n left: 0,\n top: 0,\n};\n\n// ============================================================================\n// Roving Tab Index\n// ============================================================================\n\n/**\n * Hook for implementing roving tabindex pattern.\n *\n * @param itemRefs - Refs to the focusable items\n * @param options - Navigation options\n */\nexport function useRovingTabIndex<T extends HTMLElement>(\n itemRefs: RefObject<T>[],\n options: ArrowNavigationOptions = {}\n): UseArrowNavigationResult {\n const result = useArrowNavigation(itemRefs.length, options);\n\n // Focus the active element when activeIndex changes\n useEffect(() => {\n const activeRef = itemRefs[result.activeIndex];\n if (activeRef?.current) {\n activeRef.current.focus();\n }\n }, [result.activeIndex, itemRefs]);\n\n return result;\n}\n","/**\n * Date formatting utilities for converting .NET format strings to JavaScript date formatters.\n *\n * Supports common .NET date format patterns.\n */\n\n/**\n * Convert .NET date format string to JavaScript date formatter.\n *\n * Common patterns:\n * - dd-MMM-yyyy HH:mm -> 20-Mar-2025 17:00\n * - yyyy-MM-dd -> 2025-03-20\n * - MM/dd/yyyy -> 03/20/2025\n * - yyyy-MM-dd HH:mm:ss -> 2025-03-20 17:00:00\n *\n * @param formatString .NET date format string\n * @returns Formatter function\n */\nexport function createDateFormatter(formatString: string): (value: unknown) => string {\n return (value: unknown): string => {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Parse date from various formats\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'string') {\n date = new Date(value);\n } else if (typeof value === 'number') {\n date = new Date(value);\n } else {\n return String(value);\n }\n\n // Check if date is valid\n if (isNaN(date.getTime())) {\n return String(value);\n }\n\n // Convert .NET format to formatted string\n return formatDateWithPattern(date, formatString);\n };\n}\n\n/**\n * Format date according to .NET format pattern.\n */\nfunction formatDateWithPattern(date: Date, pattern: string): string {\n // Get date components\n const year = date.getFullYear();\n const month = date.getMonth() + 1;\n const day = date.getDate();\n const hours = date.getHours();\n const minutes = date.getMinutes();\n const seconds = date.getSeconds();\n\n // Month names\n const monthNamesShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const monthNamesFull = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n\n // Day names\n const dayNamesShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const dayNamesFull = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\n // Quarter (1-4)\n const quarter = Math.ceil(month / 3);\n\n // Replace tokens\n let result = pattern;\n\n // Quarter - use placeholder to avoid the single-Q pass reprocessing the Q inserted by QQ\n result = result.replace(/QQ/g, '__QUARTER_PLACEHOLDER__');\n result = result.replace(/Q(?!['\"])/g, String(quarter));\n result = result.replace(/__QUARTER_PLACEHOLDER__/g, `Q${quarter}`);\n\n // Year\n result = result.replace(/yyyy/g, String(year).padStart(4, '0'));\n result = result.replace(/yy/g, String(year % 100).padStart(2, '0'));\n\n // Month - use placeholders without pattern letters to avoid subsequent replacements\n // Using «» brackets which won't appear in date format patterns\n result = result.replace(/MMMM/g, '«1»');\n result = result.replace(/MMM/g, '«2»');\n result = result.replace(/MM/g, String(month).padStart(2, '0'));\n result = result.replace(/M/g, String(month));\n\n // Day - use placeholders for day names\n result = result.replace(/dddd/g, '«3»');\n result = result.replace(/ddd/g, '«4»');\n result = result.replace(/dd/g, String(day).padStart(2, '0'));\n result = result.replace(/d/g, String(day));\n\n // Replace month/day name placeholders at the end (after all pattern matching is done)\n result = result.replace(/«1»/g, monthNamesFull[month - 1] || '');\n result = result.replace(/«2»/g, monthNamesShort[month - 1] || '');\n result = result.replace(/«3»/g, dayNamesFull[date.getDay()] || '');\n result = result.replace(/«4»/g, dayNamesShort[date.getDay()] || '');\n\n // Hours (24-hour)\n result = result.replace(/HH/g, String(hours).padStart(2, '0'));\n result = result.replace(/H/g, String(hours));\n\n // Hours (12-hour)\n const hours12 = hours % 12 || 12;\n result = result.replace(/hh/g, String(hours12).padStart(2, '0'));\n result = result.replace(/h/g, String(hours12));\n\n // AM/PM\n const ampm = hours >= 12 ? 'PM' : 'AM';\n result = result.replace(/tt/g, ampm);\n result = result.replace(/t/g, ampm.charAt(0));\n\n // Minutes\n result = result.replace(/mm/g, String(minutes).padStart(2, '0'));\n result = result.replace(/m/g, String(minutes));\n\n // Seconds\n result = result.replace(/ss/g, String(seconds).padStart(2, '0'));\n result = result.replace(/s/g, String(seconds));\n\n return result;\n}\n\n/**\n * Create date formatters from config map.\n *\n * @param dateFormats Map of column name to .NET format string\n * @returns Map of column name to formatter function\n */\nexport function createDateFormatters(\n dateFormats: Record<string, string>\n): Record<string, (value: unknown) => string> {\n const formatters: Record<string, (value: unknown) => string> = {};\n\n for (const [column, format] of Object.entries(dateFormats)) {\n formatters[column] = createDateFormatter(format);\n }\n\n return formatters;\n}\n\n/**\n * Format a Unix timestamp as relative time (e.g., \"5 min ago\").\n *\n * @param timestamp Unix timestamp in seconds\n * @returns Relative time string\n */\nexport function formatRelativeTime(timestamp: number | null | undefined): string {\n if (timestamp === null || timestamp === undefined) {\n return 'Never';\n }\n\n const now = Date.now() / 1000; // Convert to seconds\n const seconds = Math.floor(now - timestamp);\n\n if (seconds < 60) {\n return 'Just now';\n }\n\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) {\n return `${minutes} min ago`;\n }\n\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return `${hours} hr ago`;\n }\n\n const days = Math.floor(hours / 24);\n if (days === 1) {\n return '1 day ago';\n }\n\n return `${days} days ago`;\n}\n","/**\n * Pivot utility for transforming query results from long format to wide format.\n */\n\nimport { createDateFormatter } from './dateFormat';\nimport type { QueryResult } from '../types';\n\nexport interface PivotConfig {\n /** Column whose unique values become new columns. */\n pivotColumn: string;\n /** Column containing values to distribute across pivot columns. */\n valueColumn: string;\n /** Columns to keep as-is (dimension/grouping columns). */\n dimensionColumns: string[];\n /** Optional date format string for pivot column values (date-fns format). */\n pivotColumnFormat?: string;\n}\n\n/**\n * Pivot a query result by transforming unique values in pivotColumn\n * into separate columns.\n *\n * Example:\n * Input (long format):\n * account | date | name | value\n * Cerby | 2025-02-01 | MAU | 9\n * Cerby | 2025-02-01 | Searches | 1\n *\n * Output (wide format):\n * account | date | MAU | Searches\n * Cerby | 2025-02-01 | 9 | 1\n *\n * @param result - The query result to pivot\n * @param config - Pivot configuration\n * @returns Pivoted query result\n */\n/**\n * Format a value for use as a pivot column header.\n * If it looks like a date and a format is provided, format it.\n */\nfunction formatPivotValue(value: unknown, dateFormat?: string): string {\n const strValue = String(value);\n\n if (!dateFormat) {\n return strValue;\n }\n\n // Try to parse as ISO date\n try {\n // Check if it looks like a date string\n if (strValue.match(/^\\d{4}-\\d{2}-\\d{2}/)) {\n const formatter = createDateFormatter(dateFormat);\n const formatted = formatter(strValue);\n if (formatted && formatted !== strValue) {\n return formatted;\n }\n }\n } catch {\n // If parsing fails, return original string\n }\n\n return strValue;\n}\n\nexport function pivotQueryResult(\n result: QueryResult,\n config: PivotConfig\n): QueryResult {\n const { pivotColumn, valueColumn, dimensionColumns, pivotColumnFormat } = config;\n\n // Find column indices\n const pivotColIndex = result.columns.indexOf(pivotColumn);\n const valueColIndex = result.columns.indexOf(valueColumn);\n\n if (pivotColIndex === -1 || valueColIndex === -1) {\n console.warn(\n `[pivot] Cannot pivot: columns not found (pivot=${pivotColIndex}, value=${valueColIndex})`\n );\n return result; // Can't pivot, return as-is\n }\n\n // Get unique pivot values (these become new columns)\n // Keep track of raw values for grouping and formatted values for display\n const rawPivotValues = Array.from(\n new Set(result.rows.map((row) => String(row[pivotColIndex])))\n ).sort();\n\n // Create mapping from raw value to formatted display value\n const pivotValueToDisplay = new Map<string, string>();\n for (const raw of rawPivotValues) {\n pivotValueToDisplay.set(raw, formatPivotValue(raw, pivotColumnFormat));\n }\n\n // Formatted values for column headers\n const pivotValues = rawPivotValues;\n\n // Build dimension column indices\n const dimIndices = dimensionColumns\n .map((col) => result.columns.indexOf(col))\n .filter((idx) => idx !== -1);\n\n // Group rows by dimension values\n const grouped = new Map<string, Map<string, unknown>>();\n\n for (const row of result.rows) {\n // Create key from dimension column values\n const dimValues = dimIndices.map((i) => row[i]);\n const key = dimValues.map((v) => String(v ?? '')).join('|');\n\n if (!grouped.has(key)) {\n // Store dimension values for this group\n const group = new Map<string, unknown>();\n group.set('__dim_values__', dimValues);\n grouped.set(key, group);\n }\n\n const pivotValue = String(row[pivotColIndex]);\n const value = row[valueColIndex];\n grouped.get(key)!.set(pivotValue, value);\n }\n\n // Build pivoted result - use formatted display values for column headers\n const displayColumns = pivotValues.map((pv) => pivotValueToDisplay.get(pv) ?? pv);\n const newColumns = [...dimensionColumns, ...displayColumns];\n const newRows: unknown[][] = [];\n\n for (const [_key, valueMap] of grouped.entries()) {\n const dimValues = valueMap.get('__dim_values__') as unknown[];\n const newRow = [\n ...dimValues,\n ...pivotValues.map((pv) => valueMap.get(pv) ?? null),\n ];\n newRows.push(newRow);\n }\n\n // Build column_types array (dimension types + value type for each pivot column)\n const dimColTypes = dimensionColumns\n .map((col) => {\n const idx = result.columns.indexOf(col);\n return idx !== -1 && result.column_types && result.column_types[idx]\n ? result.column_types[idx]\n : 'text';\n })\n .filter((t): t is string => t !== undefined);\n\n const valueColType = (result.column_types && result.column_types[valueColIndex]) ?? 'numeric';\n const newColumnTypes = [...dimColTypes, ...pivotValues.map(() => valueColType)];\n\n return {\n columns: newColumns,\n column_types: newColumnTypes,\n rows: newRows,\n row_count: newRows.length,\n truncated: result.truncated,\n execution_time_ms: result.execution_time_ms,\n };\n}\n","/**\n * Utilities for parsing column references in \"tableId.column\" format.\n */\n\n/**\n * Parsed column reference with table ID and column name.\n */\nexport interface ColumnReference {\n tableId: string;\n column: string;\n}\n\n/**\n * Parse a column reference in \"tableId.column\" format.\n *\n * @param ref - The column reference string (e.g., \"t1.created_at\")\n * @param defaultTableId - Table ID to use when ref has no table prefix\n * @returns Parsed reference, or null if invalid. Logs a warning only for\n * malformed references (e.g., \"table.\" or \".column\" or \"a.b.c\").\n * Empty/whitespace inputs return null without warning.\n */\nexport function parseColumnRef(\n ref: string,\n defaultTableId: string\n): ColumnReference | null {\n if (!ref || ref.trim() === '') {\n return null;\n }\n\n if (!ref.includes('.')) {\n // Simple column name without table prefix - use default table\n // for backward compatibility with single-table queries\n return { tableId: defaultTableId, column: ref };\n }\n\n const parts = ref.split('.');\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n console.warn(`Invalid column reference format: \"${ref}\". Expected \"tableId.column\"`);\n return null;\n }\n\n return { tableId: parts[0], column: parts[1] };\n}\n","/**\n * Safe markdown parser that escapes HTML to prevent XSS attacks.\n *\n * Supports a limited subset of markdown:\n * - Headings (#, ##, ###)\n * - Bold (**text**)\n * - Italic (*text*)\n * - Inline code (`code`)\n * - Line breaks\n */\n\n/**\n * Escape HTML special characters to prevent XSS.\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\n/**\n * Validate that a CSS style string contains only safe characters.\n * Rejects strings that could break out of the style attribute.\n */\nfunction isValidCssStyle(style: string): boolean {\n // Only allow: letters, numbers, spaces, basic CSS punctuation\n // Reject: quotes, angle brackets, script-related chars\n const safePattern = /^[a-zA-Z0-9\\s:;,.#%()\\-]+$/;\n return safePattern.test(style);\n}\n\n/**\n * Parse markdown text into safe HTML.\n *\n * HTML is escaped first to prevent XSS, then markdown syntax is converted.\n *\n * @param text - Raw markdown text\n * @param codeStyle - Optional inline styles for code blocks\n * @returns Safe HTML string\n */\nexport function parseMarkdownSafe(\n text: string,\n codeStyle?: string\n): string {\n // First escape any HTML to prevent XSS\n const escaped = escapeHtml(text);\n\n // Then apply markdown transforms\n const defaultCodeStyle =\n 'background: rgba(0,0,0,0.05); padding: 0.1em 0.3em; border-radius: 3px;';\n\n // Validate codeStyle to prevent style attribute injection\n const safeCodeStyle =\n codeStyle && isValidCssStyle(codeStyle) ? codeStyle : defaultCodeStyle;\n\n return escaped\n .replace(/^### (.+)$/gm, '<h3 style=\"margin: 0.5em 0; font-size: 1.1em;\">$1</h3>')\n .replace(/^## (.+)$/gm, '<h2 style=\"margin: 0.5em 0; font-size: 1.25em;\">$1</h2>')\n .replace(/^# (.+)$/gm, '<h1 style=\"margin: 0.5em 0; font-size: 1.5em;\">$1</h1>')\n .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\*(.+?)\\*/g, '<em>$1</em>')\n .replace(/`(.+?)`/g, `<code style=\"${safeCodeStyle}\">$1</code>`)\n .replace(/\\n/g, '<br/>');\n}\n"]}
@@ -312,14 +312,18 @@ function formatDateWithPattern(date, pattern) {
312
312
  result = result.replace(/__QUARTER_PLACEHOLDER__/g, `Q${quarter}`);
313
313
  result = result.replace(/yyyy/g, String(year).padStart(4, "0"));
314
314
  result = result.replace(/yy/g, String(year % 100).padStart(2, "0"));
315
- result = result.replace(/MMMM/g, monthNamesFull[month - 1] || "");
316
- result = result.replace(/MMM/g, monthNamesShort[month - 1] || "");
315
+ result = result.replace(/MMMM/g, "\xAB1\xBB");
316
+ result = result.replace(/MMM/g, "\xAB2\xBB");
317
317
  result = result.replace(/MM/g, String(month).padStart(2, "0"));
318
318
  result = result.replace(/M/g, String(month));
319
- result = result.replace(/dddd/g, dayNamesFull[date.getDay()] || "");
320
- result = result.replace(/ddd/g, dayNamesShort[date.getDay()] || "");
319
+ result = result.replace(/dddd/g, "\xAB3\xBB");
320
+ result = result.replace(/ddd/g, "\xAB4\xBB");
321
321
  result = result.replace(/dd/g, String(day).padStart(2, "0"));
322
322
  result = result.replace(/d/g, String(day));
323
+ result = result.replace(/«1»/g, monthNamesFull[month - 1] || "");
324
+ result = result.replace(/«2»/g, monthNamesShort[month - 1] || "");
325
+ result = result.replace(/«3»/g, dayNamesFull[date.getDay()] || "");
326
+ result = result.replace(/«4»/g, dayNamesShort[date.getDay()] || "");
323
327
  result = result.replace(/HH/g, String(hours).padStart(2, "0"));
324
328
  result = result.replace(/H/g, String(hours));
325
329
  const hours12 = hours % 12 || 12;
@@ -366,8 +370,25 @@ function formatRelativeTime(timestamp) {
366
370
  }
367
371
 
368
372
  // src/utils/pivot.ts
373
+ function formatPivotValue(value, dateFormat) {
374
+ const strValue = String(value);
375
+ if (!dateFormat) {
376
+ return strValue;
377
+ }
378
+ try {
379
+ if (strValue.match(/^\d{4}-\d{2}-\d{2}/)) {
380
+ const formatter = createDateFormatter(dateFormat);
381
+ const formatted = formatter(strValue);
382
+ if (formatted && formatted !== strValue) {
383
+ return formatted;
384
+ }
385
+ }
386
+ } catch {
387
+ }
388
+ return strValue;
389
+ }
369
390
  function pivotQueryResult(result, config) {
370
- const { pivotColumn, valueColumn, dimensionColumns } = config;
391
+ const { pivotColumn, valueColumn, dimensionColumns, pivotColumnFormat } = config;
371
392
  const pivotColIndex = result.columns.indexOf(pivotColumn);
372
393
  const valueColIndex = result.columns.indexOf(valueColumn);
373
394
  if (pivotColIndex === -1 || valueColIndex === -1) {
@@ -376,9 +397,14 @@ function pivotQueryResult(result, config) {
376
397
  );
377
398
  return result;
378
399
  }
379
- const pivotValues = Array.from(
400
+ const rawPivotValues = Array.from(
380
401
  new Set(result.rows.map((row) => String(row[pivotColIndex])))
381
402
  ).sort();
403
+ const pivotValueToDisplay = /* @__PURE__ */ new Map();
404
+ for (const raw of rawPivotValues) {
405
+ pivotValueToDisplay.set(raw, formatPivotValue(raw, pivotColumnFormat));
406
+ }
407
+ const pivotValues = rawPivotValues;
382
408
  const dimIndices = dimensionColumns.map((col) => result.columns.indexOf(col)).filter((idx) => idx !== -1);
383
409
  const grouped = /* @__PURE__ */ new Map();
384
410
  for (const row of result.rows) {
@@ -393,7 +419,8 @@ function pivotQueryResult(result, config) {
393
419
  const value = row[valueColIndex];
394
420
  grouped.get(key).set(pivotValue, value);
395
421
  }
396
- const newColumns = [...dimensionColumns, ...pivotValues];
422
+ const displayColumns = pivotValues.map((pv) => pivotValueToDisplay.get(pv) ?? pv);
423
+ const newColumns = [...dimensionColumns, ...displayColumns];
397
424
  const newRows = [];
398
425
  for (const [_key, valueMap] of grouped.entries()) {
399
426
  const dimValues = valueMap.get("__dim_values__");
@@ -451,5 +478,5 @@ function parseMarkdownSafe(text, codeStyle) {
451
478
  }
452
479
 
453
480
  export { announceToScreenReader, createDateFormatter, createDateFormatters, focusVisibleStyles, formatRelativeTime, parseColumnRef, parseMarkdownSafe, pivotQueryResult, skipLinkFocusStyles, skipLinkStyles, useArrowNavigation, useFocusTrap, useFocusVisible, useRovingTabIndex };
454
- //# sourceMappingURL=chunk-EX74SI67.js.map
455
- //# sourceMappingURL=chunk-EX74SI67.js.map
481
+ //# sourceMappingURL=chunk-LBE6GIBC.js.map
482
+ //# sourceMappingURL=chunk-LBE6GIBC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/accessibility.ts","../src/utils/dateFormat.ts","../src/utils/pivot.ts","../src/utils/columnRef.ts","../src/utils/safeMarkdown.ts"],"names":[],"mappings":";;;AAiEA,IAAM,kBAAA,GAAqB;AAAA,EACzB,wBAAA;AAAA,EACA,uBAAA;AAAA,EACA,wBAAA;AAAA,EACA,0BAAA;AAAA,EACA,SAAA;AAAA,EACA,iCAAA;AAAA,EACA;AACF,CAAA,CAAE,KAAK,IAAI,CAAA;AAKX,SAAS,qBAAqB,SAAA,EAAuC;AACnE,EAAA,MAAM,QAAA,GAAW,SAAA,CAAU,gBAAA,CAA8B,kBAAkB,CAAA;AAC3E,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA;AAAA,IAC1B,CAAC,OAAO,CAAC,EAAA,CAAG,aAAa,aAAa,CAAA,IAAK,GAAG,YAAA,KAAiB;AAAA,GACjE;AACF;AAyBO,SAAS,YAAA,CAAa,OAAA,GAA4B,EAAC,EAAuB;AAC/E,EAAA,MAAM;AAAA,IACJ,MAAA,GAAS,IAAA;AAAA,IACT,SAAA,GAAY,IAAA;AAAA,IACZ,YAAA,GAAe,IAAA;AAAA,IACf;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,YAAA,GAAe,OAAoB,IAAI,CAAA;AAC7C,EAAA,MAAM,gBAAA,GAAmB,OAA2B,IAAI,CAAA;AACxD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,MAAM,CAAA;AAE/C,EAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AACjC,IAAA,IAAI,CAAC,aAAa,OAAA,EAAS;AAG3B,IAAA,gBAAA,CAAiB,UAAU,QAAA,CAAS,aAAA;AAGpC,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAM,SAAA,GAAY,oBAAA,CAAqB,YAAA,CAAa,OAAO,CAAA;AAC3D,MAAA,MAAM,YAAA,GAAe,UAAU,CAAC,CAAA;AAChC,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,YAAA,CAAa,KAAA,EAAM;AAAA,MACrB;AAAA,IACF;AAEA,IAAA,WAAA,CAAY,IAAI,CAAA;AAAA,EAClB,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,UAAA,GAAa,YAAY,MAAM;AACnC,IAAA,WAAA,CAAY,KAAK,CAAA;AAGjB,IAAA,IAAI,YAAA,IAAgB,iBAAiB,OAAA,EAAS;AAC5C,MAAA,gBAAA,CAAiB,QAAQ,KAAA,EAAM;AAAA,IACjC;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAGjB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,YAAA,CAAa,OAAA,EAAS;AAExC,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAE/B,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyB;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,QAAA,IAAW;AACX,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,KAAA,CAAM,QAAQ,KAAA,EAAO;AAEzB,MAAA,MAAM,SAAA,GAAY,qBAAqB,SAAS,CAAA;AAChD,MAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAE5B,MAAA,MAAM,YAAA,GAAe,UAAU,CAAC,CAAA;AAChC,MAAA,MAAM,WAAA,GAAc,SAAA,CAAU,SAAA,CAAU,MAAA,GAAS,CAAC,CAAA;AAGlD,MAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,WAAA,EAAa;AAGnC,MAAA,IAAI,KAAA,CAAM,QAAA,IAAY,QAAA,CAAS,aAAA,KAAkB,YAAA,EAAc;AAC7D,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,WAAA,CAAY,KAAA,EAAM;AAClB,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,CAAC,KAAA,CAAM,QAAA,IAAY,QAAA,CAAS,kBAAkB,WAAA,EAAa;AAC7D,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,YAAA,CAAa,KAAA,EAAM;AAAA,MACrB;AAAA,IACF,CAAA;AAGA,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAsB;AAC3C,MAAA,IAAI,CAAC,SAAA,CAAU,QAAA,CAAS,KAAA,CAAM,MAAc,CAAA,EAAG;AAC7C,QAAA,MAAM,SAAA,GAAY,qBAAqB,SAAS,CAAA;AAChD,QAAA,MAAM,YAAA,GAAe,UAAU,CAAC,CAAA;AAChC,QAAA,IAAI,YAAA,EAAc;AAChB,UAAA,YAAA,CAAa,KAAA,EAAM;AAAA,QACrB;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,SAAA,CAAU,gBAAA,CAAiB,WAAW,aAAa,CAAA;AACnD,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,aAAa,CAAA;AAElD,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,CAAU,mBAAA,CAAoB,WAAW,aAAa,CAAA;AACtD,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,aAAa,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,QAAA,EAAU,QAAQ,CAAC,CAAA;AAGvB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,QAAA,EAAS;AAAA,IACX,CAAA,MAAO;AACL,MAAA,UAAA,EAAW;AAAA,IACb;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,QAAA,EAAU,UAAU,CAAC,CAAA;AAEjC,EAAA,OAAO;AAAA,IACL,YAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF;AACF;AA8BO,SAAS,kBAAA,CACd,SAAA,EACA,OAAA,GAAkC,EAAC,EACT;AAC1B,EAAA,MAAM,EAAE,IAAA,GAAO,IAAA,EAAM,WAAA,GAAc,UAAA,EAAY,gBAAe,GAAI,OAAA;AAElE,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,CAAC,CAAA;AAEhD,EAAA,MAAM,aAAA,GAAgB,WAAA;AAAA,IACpB,CAAC,KAAA,KAA+B;AAC9B,MAAA,IAAI,QAAA,GAAW,WAAA;AACf,MAAA,IAAI,OAAA,GAAU,KAAA;AAGd,MAAA,MAAM,SACH,WAAA,KAAgB,UAAA,IAAc,KAAA,CAAM,GAAA,KAAQ,eAC5C,WAAA,KAAgB,YAAA,IAAgB,KAAA,CAAM,GAAA,KAAQ,gBAC9C,WAAA,KAAgB,MAAA,KAAW,MAAM,GAAA,KAAQ,WAAA,IAAe,MAAM,GAAA,KAAQ,YAAA,CAAA;AAEzE,MAAA,MAAM,SACH,WAAA,KAAgB,UAAA,IAAc,KAAA,CAAM,GAAA,KAAQ,aAC5C,WAAA,KAAgB,YAAA,IAAgB,KAAA,CAAM,GAAA,KAAQ,eAC9C,WAAA,KAAgB,MAAA,KAAW,MAAM,GAAA,KAAQ,SAAA,IAAa,MAAM,GAAA,KAAQ,WAAA,CAAA;AAEvE,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,IAAI,WAAA,GAAc,YAAY,CAAA,EAAG;AAC/B,UAAA,QAAA,GAAW,WAAA,GAAc,CAAA;AAAA,QAC3B,WAAW,IAAA,EAAM;AACf,UAAA,QAAA,GAAW,CAAA;AAAA,QACb;AAAA,MACF,WAAW,MAAA,EAAQ;AACjB,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,IAAI,cAAc,CAAA,EAAG;AACnB,UAAA,QAAA,GAAW,WAAA,GAAc,CAAA;AAAA,QAC3B,WAAW,IAAA,EAAM;AACf,UAAA,QAAA,GAAW,SAAA,GAAY,CAAA;AAAA,QACzB;AAAA,MACF,CAAA,MAAA,IAAW,KAAA,CAAM,GAAA,KAAQ,MAAA,EAAQ;AAC/B,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,QAAA,GAAW,CAAA;AAAA,MACb,CAAA,MAAA,IAAW,KAAA,CAAM,GAAA,KAAQ,KAAA,EAAO;AAC9B,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,QAAA,GAAW,SAAA,GAAY,CAAA;AAAA,MACzB;AAEA,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,KAAA,CAAM,cAAA,EAAe;AACrB,QAAA,cAAA,CAAe,QAAQ,CAAA;AACvB,QAAA,cAAA,GAAiB,QAAQ,CAAA;AAAA,MAC3B;AAAA,IACF,CAAA;AAAA,IACA,CAAC,WAAA,EAAa,SAAA,EAAW,IAAA,EAAM,aAAa,cAAc;AAAA,GAC5D;AAEA,EAAA,MAAM,YAAA,GAAe,WAAA;AAAA,IACnB,CAAC,KAAA,MAAmB;AAAA,MAClB,QAAA,EAAU,KAAA,KAAU,WAAA,GAAc,CAAA,GAAI,EAAA;AAAA,MACtC,iBAAiB,KAAA,KAAU,WAAA;AAAA,MAC3B,SAAS,MAAM;AACb,QAAA,cAAA,CAAe,KAAK,CAAA;AACpB,QAAA,cAAA,GAAiB,KAAK,CAAA;AAAA,MACxB;AAAA,KACF,CAAA;AAAA,IACA,CAAC,aAAa,cAAc;AAAA,GAC9B;AAGA,EAAA,MAAM,oBAAA,GAAuB,WAAA;AAAA,IAC3B,CAAC,KAAA,KAAkB;AACjB,MAAA,cAAA,CAAe,KAAK,CAAA;AACpB,MAAA,cAAA,GAAiB,KAAK,CAAA;AAAA,IACxB,CAAA;AAAA,IACA,CAAC,cAAc;AAAA,GACjB;AAEA,EAAA,OAAO;AAAA,IACL,WAAA;AAAA,IACA,cAAA,EAAgB,oBAAA;AAAA,IAChB,SAAA,EAAW,aAAA;AAAA,IACX;AAAA,GACF;AACF;AAMA,IAAI,eAAA,GAAsC,IAAA;AAK1C,SAAS,kBAAA,GAAkC;AACzC,EAAA,IAAI,iBAAiB,OAAO,eAAA;AAG5B,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACnC,IAAA,MAAM,IAAI,MAAM,gEAAgE,CAAA;AAAA,EAClF;AAEA,EAAA,eAAA,GAAkB,QAAA,CAAS,cAAc,KAAK,CAAA;AAC9C,EAAA,eAAA,CAAgB,YAAA,CAAa,QAAQ,QAAQ,CAAA;AAC7C,EAAA,eAAA,CAAgB,YAAA,CAAa,aAAa,QAAQ,CAAA;AAClD,EAAA,eAAA,CAAgB,YAAA,CAAa,eAAe,MAAM,CAAA;AAClD,EAAA,eAAA,CAAgB,MAAM,OAAA,GAAU;AAAA,IAC9B,oBAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,YAAA;AAAA,IACA,cAAA;AAAA,IACA,kBAAA;AAAA,IACA,wBAAA;AAAA,IACA,qBAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,GAAG,CAAA;AACV,EAAA,eAAA,CAAgB,EAAA,GAAK,mBAAA;AAErB,EAAA,QAAA,CAAS,IAAA,CAAK,YAAY,eAAe,CAAA;AACzC,EAAA,OAAO,eAAA;AACT;AAiBO,SAAS,sBAAA,CACd,OAAA,EACA,QAAA,GAAmC,QAAA,EAC7B;AAEN,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAErC,EAAA,MAAM,UAAU,kBAAA,EAAmB;AACnC,EAAA,OAAA,CAAQ,YAAA,CAAa,aAAa,QAAQ,CAAA;AAG1C,EAAA,OAAA,CAAQ,WAAA,GAAc,EAAA;AAEtB,EAAA,qBAAA,CAAsB,MAAM;AAC1B,IAAA,OAAA,CAAQ,WAAA,GAAc,OAAA;AAAA,EACxB,CAAC,CAAA;AACH;AAUO,IAAM,kBAAA,GAAqB;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuB3B,SAAS,eAAA,GAA2B;AACzC,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,KAAK,CAAA;AAEtD,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEnC,IAAA,IAAI,gBAAA,GAAmB,KAAA;AAEvB,IAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAAyB;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,KAAA,EAAO;AACvB,QAAA,gBAAA,GAAmB,IAAA;AAAA,MACrB;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,oBAAoB,MAAM;AAC9B,MAAA,gBAAA,GAAmB,KAAA;AAAA,IACrB,CAAA;AAEA,IAAA,MAAM,cAAc,MAAM;AACxB,MAAA,eAAA,CAAgB,gBAAgB,CAAA;AAAA,IAClC,CAAA;AAEA,IAAA,MAAM,aAAa,MAAM;AACvB,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,aAAA,EAAe,IAAI,CAAA;AACxD,IAAA,QAAA,CAAS,gBAAA,CAAiB,aAAA,EAAe,iBAAA,EAAmB,IAAI,CAAA;AAChE,IAAA,QAAA,CAAS,gBAAA,CAAiB,OAAA,EAAS,WAAA,EAAa,IAAI,CAAA;AACpD,IAAA,QAAA,CAAS,gBAAA,CAAiB,MAAA,EAAQ,UAAA,EAAY,IAAI,CAAA;AAElD,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,aAAA,EAAe,IAAI,CAAA;AAC3D,MAAA,QAAA,CAAS,mBAAA,CAAoB,aAAA,EAAe,iBAAA,EAAmB,IAAI,CAAA;AACnE,MAAA,QAAA,CAAS,mBAAA,CAAoB,OAAA,EAAS,WAAA,EAAa,IAAI,CAAA;AACvD,MAAA,QAAA,CAAS,mBAAA,CAAoB,MAAA,EAAQ,UAAA,EAAY,IAAI,CAAA;AAAA,IACvD,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,YAAA;AACT;AAmBO,IAAM,cAAA,GAAsC;AAAA,EACjD,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM,SAAA;AAAA,EACN,MAAA,EAAQ,IAAA;AAAA,EACR,OAAA,EAAS,KAAA;AAAA,EACT,eAAA,EAAiB,iCAAA;AAAA,EACjB,KAAA,EAAO,8BAAA;AAAA,EACP,cAAA,EAAgB;AAAA;AAElB;AAEO,IAAM,mBAAA,GAA2C;AAAA,EACtD,GAAG,cAAA;AAAA,EACH,IAAA,EAAM,CAAA;AAAA,EACN,GAAA,EAAK;AACP;AAYO,SAAS,iBAAA,CACd,QAAA,EACA,OAAA,GAAkC,EAAC,EACT;AAC1B,EAAA,MAAM,MAAA,GAAS,kBAAA,CAAmB,QAAA,CAAS,MAAA,EAAQ,OAAO,CAAA;AAG1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,SAAA,GAAY,QAAA,CAAS,MAAA,CAAO,WAAW,CAAA;AAC7C,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,SAAA,CAAU,QAAQ,KAAA,EAAM;AAAA,IAC1B;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,CAAO,WAAA,EAAa,QAAQ,CAAC,CAAA;AAEjC,EAAA,OAAO,MAAA;AACT;;;ACvgBO,SAAS,oBAAoB,YAAA,EAAkD;AACpF,EAAA,OAAO,CAAC,KAAA,KAA2B;AACjC,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW;AACzC,MAAA,OAAO,EAAA;AAAA,IACT;AAGA,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,MAAA,IAAA,GAAO,KAAA;AAAA,IACT,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AACpC,MAAA,IAAA,GAAO,IAAI,KAAK,KAAK,CAAA;AAAA,IACvB,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AACpC,MAAA,IAAA,GAAO,IAAI,KAAK,KAAK,CAAA;AAAA,IACvB,CAAA,MAAO;AACL,MAAA,OAAO,OAAO,KAAK,CAAA;AAAA,IACrB;AAGA,IAAA,IAAI,KAAA,CAAM,IAAA,CAAK,OAAA,EAAS,CAAA,EAAG;AACzB,MAAA,OAAO,OAAO,KAAK,CAAA;AAAA,IACrB;AAGA,IAAA,OAAO,qBAAA,CAAsB,MAAM,YAAY,CAAA;AAAA,EACjD,CAAA;AACF;AAKA,SAAS,qBAAA,CAAsB,MAAY,OAAA,EAAyB;AAElE,EAAA,MAAM,IAAA,GAAO,KAAK,WAAA,EAAY;AAC9B,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,QAAA,EAAS,GAAI,CAAA;AAChC,EAAA,MAAM,GAAA,GAAM,KAAK,OAAA,EAAQ;AACzB,EAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,EAAS;AAC5B,EAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAChC,EAAA,MAAM,OAAA,GAAU,KAAK,UAAA,EAAW;AAGhC,EAAA,MAAM,eAAA,GAAkB,CAAC,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,OAAO,KAAK,CAAA;AAC3G,EAAA,MAAM,cAAA,GAAiB,CAAC,SAAA,EAAW,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,WAAA,EAAa,SAAA,EAAW,YAAY,UAAU,CAAA;AAGhJ,EAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,EAAO,KAAA,EAAO,OAAO,KAAA,EAAO,KAAA,EAAO,OAAO,KAAK,CAAA;AACtE,EAAA,MAAM,YAAA,GAAe,CAAC,QAAA,EAAU,QAAA,EAAU,WAAW,WAAA,EAAa,UAAA,EAAY,UAAU,UAAU,CAAA;AAGlG,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,IAAA,CAAK,KAAA,GAAQ,CAAC,CAAA;AAGnC,EAAA,IAAI,MAAA,GAAS,OAAA;AAGb,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,yBAAyB,CAAA;AACxD,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,YAAA,EAAc,MAAA,CAAO,OAAO,CAAC,CAAA;AACrD,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,0BAAA,EAA4B,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAA;AAGjE,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,OAAA,EAAS,MAAA,CAAO,IAAI,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC9D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,MAAA,CAAO,IAAA,GAAO,GAAG,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAIlE,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,OAAA,EAAS,WAAK,CAAA;AACtC,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,WAAK,CAAA;AACrC,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC7D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAG3C,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,OAAA,EAAS,WAAK,CAAA;AACtC,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,WAAK,CAAA;AACrC,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,KAAA,EAAO,MAAA,CAAO,GAAG,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC3D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AAGzC,EAAA,MAAA,GAAS,OAAO,OAAA,CAAQ,MAAA,EAAQ,eAAe,KAAA,GAAQ,CAAC,KAAK,EAAE,CAAA;AAC/D,EAAA,MAAA,GAAS,OAAO,OAAA,CAAQ,MAAA,EAAQ,gBAAgB,KAAA,GAAQ,CAAC,KAAK,EAAE,CAAA;AAChE,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,MAAA,EAAQ,YAAA,CAAa,KAAK,MAAA,EAAQ,KAAK,EAAE,CAAA;AACjE,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,MAAA,EAAQ,aAAA,CAAc,KAAK,MAAA,EAAQ,KAAK,EAAE,CAAA;AAGlE,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,KAAA,EAAO,MAAA,CAAO,KAAK,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC7D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAG3C,EAAA,MAAM,OAAA,GAAU,QAAQ,EAAA,IAAM,EAAA;AAC9B,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC/D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAG7C,EAAA,MAAM,IAAA,GAAO,KAAA,IAAS,EAAA,GAAK,IAAA,GAAO,IAAA;AAClC,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA;AACnC,EAAA,MAAA,GAAS,OAAO,OAAA,CAAQ,IAAA,EAAM,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAG5C,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC/D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAG7C,EAAA,MAAA,GAAS,MAAA,CAAO,QAAQ,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA;AAC/D,EAAA,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,MAAA,CAAO,OAAO,CAAC,CAAA;AAE7C,EAAA,OAAO,MAAA;AACT;AAQO,SAAS,qBACd,WAAA,EAC4C;AAC5C,EAAA,MAAM,aAAyD,EAAC;AAEhE,EAAA,KAAA,MAAW,CAAC,MAAA,EAAQ,MAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC1D,IAAA,UAAA,CAAW,MAAM,CAAA,GAAI,mBAAA,CAAoB,MAAM,CAAA;AAAA,EACjD;AAEA,EAAA,OAAO,UAAA;AACT;AAQO,SAAS,mBAAmB,SAAA,EAA8C;AAC/E,EAAA,IAAI,SAAA,KAAc,IAAA,IAAQ,SAAA,KAAc,MAAA,EAAW;AACjD,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA;AACzB,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,SAAS,CAAA;AAE1C,EAAA,IAAI,UAAU,EAAA,EAAI;AAChB,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,EAAE,CAAA;AACvC,EAAA,IAAI,UAAU,EAAA,EAAI;AAChB,IAAA,OAAO,GAAG,OAAO,CAAA,QAAA,CAAA;AAAA,EACnB;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,OAAA,GAAU,EAAE,CAAA;AACrC,EAAA,IAAI,QAAQ,EAAA,EAAI;AACd,IAAA,OAAO,GAAG,KAAK,CAAA,OAAA,CAAA;AAAA,EACjB;AAEA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,EAAE,CAAA;AAClC,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,OAAO,GAAG,IAAI,CAAA,SAAA,CAAA;AAChB;;;ACzIA,SAAS,gBAAA,CAAiB,OAAgB,UAAA,EAA6B;AACrE,EAAA,MAAM,QAAA,GAAW,OAAO,KAAK,CAAA;AAE7B,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,IAAI;AAEF,IAAA,IAAI,QAAA,CAAS,KAAA,CAAM,oBAAoB,CAAA,EAAG;AACxC,MAAA,MAAM,SAAA,GAAY,oBAAoB,UAAU,CAAA;AAChD,MAAA,MAAM,SAAA,GAAY,UAAU,QAAQ,CAAA;AACpC,MAAA,IAAI,SAAA,IAAa,cAAc,QAAA,EAAU;AACvC,QAAA,OAAO,SAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,OAAO,QAAA;AACT;AAEO,SAAS,gBAAA,CACd,QACA,MAAA,EACa;AACb,EAAA,MAAM,EAAE,WAAA,EAAa,WAAA,EAAa,gBAAA,EAAkB,mBAAkB,GAAI,MAAA;AAG1E,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,WAAW,CAAA;AACxD,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,WAAW,CAAA;AAExD,EAAA,IAAI,aAAA,KAAkB,EAAA,IAAM,aAAA,KAAkB,EAAA,EAAI;AAChD,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,CAAA,+CAAA,EAAkD,aAAa,CAAA,QAAA,EAAW,aAAa,CAAA,CAAA;AAAA,KACzF;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAIA,EAAA,MAAM,iBAAiB,KAAA,CAAM,IAAA;AAAA,IAC3B,IAAI,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,KAAQ,MAAA,CAAO,GAAA,CAAI,aAAa,CAAC,CAAC,CAAC;AAAA,IAC5D,IAAA,EAAK;AAGP,EAAA,MAAM,mBAAA,uBAA0B,GAAA,EAAoB;AACpD,EAAA,KAAA,MAAW,OAAO,cAAA,EAAgB;AAChC,IAAA,mBAAA,CAAoB,GAAA,CAAI,GAAA,EAAK,gBAAA,CAAiB,GAAA,EAAK,iBAAiB,CAAC,CAAA;AAAA,EACvE;AAGA,EAAA,MAAM,WAAA,GAAc,cAAA;AAGpB,EAAA,MAAM,UAAA,GAAa,gBAAA,CAChB,GAAA,CAAI,CAAC,QAAQ,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAC,CAAA,CACxC,MAAA,CAAO,CAAC,GAAA,KAAQ,QAAQ,EAAE,CAAA;AAG7B,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAkC;AAEtD,EAAA,KAAA,MAAW,GAAA,IAAO,OAAO,IAAA,EAAM;AAE7B,IAAA,MAAM,YAAY,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAM,GAAA,CAAI,CAAC,CAAC,CAAA;AAC9C,IAAA,MAAM,GAAA,GAAM,SAAA,CAAU,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,CAAO,CAAA,IAAK,EAAE,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAE1D,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG;AAErB,MAAA,MAAM,KAAA,uBAAY,GAAA,EAAqB;AACvC,MAAA,KAAA,CAAM,GAAA,CAAI,kBAAkB,SAAS,CAAA;AACrC,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IACxB;AAEA,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,GAAA,CAAI,aAAa,CAAC,CAAA;AAC5C,IAAA,MAAM,KAAA,GAAQ,IAAI,aAAa,CAAA;AAC/B,IAAA,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,CAAG,GAAA,CAAI,YAAY,KAAK,CAAA;AAAA,EACzC;AAGA,EAAA,MAAM,cAAA,GAAiB,YAAY,GAAA,CAAI,CAAC,OAAO,mBAAA,CAAoB,GAAA,CAAI,EAAE,CAAA,IAAK,EAAE,CAAA;AAChF,EAAA,MAAM,UAAA,GAAa,CAAC,GAAG,gBAAA,EAAkB,GAAG,cAAc,CAAA;AAC1D,EAAA,MAAM,UAAuB,EAAC;AAE9B,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,QAAQ,CAAA,IAAK,OAAA,CAAQ,SAAQ,EAAG;AAChD,IAAA,MAAM,SAAA,GAAY,QAAA,CAAS,GAAA,CAAI,gBAAgB,CAAA;AAC/C,IAAA,MAAM,MAAA,GAAS;AAAA,MACb,GAAG,SAAA;AAAA,MACH,GAAG,YAAY,GAAA,CAAI,CAAC,OAAO,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA,IAAK,IAAI;AAAA,KACrD;AACA,IAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,EACrB;AAGA,EAAA,MAAM,WAAA,GAAc,gBAAA,CACjB,GAAA,CAAI,CAAC,GAAA,KAAQ;AACZ,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AACtC,IAAA,OAAO,GAAA,KAAQ,EAAA,IAAM,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,YAAA,CAAa,GAAG,CAAA,GAC/D,MAAA,CAAO,YAAA,CAAa,GAAG,CAAA,GACvB,MAAA;AAAA,EACN,CAAC,CAAA,CACA,MAAA,CAAO,CAAC,CAAA,KAAmB,MAAM,MAAS,CAAA;AAE7C,EAAA,MAAM,gBAAgB,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,YAAA,CAAa,aAAa,CAAA,KAAM,SAAA;AACpF,EAAA,MAAM,cAAA,GAAiB,CAAC,GAAG,WAAA,EAAa,GAAG,WAAA,CAAY,GAAA,CAAI,MAAM,YAAY,CAAC,CAAA;AAE9E,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,UAAA;AAAA,IACT,YAAA,EAAc,cAAA;AAAA,IACd,IAAA,EAAM,OAAA;AAAA,IACN,WAAW,OAAA,CAAQ,MAAA;AAAA,IACnB,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,mBAAmB,MAAA,CAAO;AAAA,GAC5B;AACF;;;ACvIO,SAAS,cAAA,CACd,KACA,cAAA,EACwB;AACxB,EAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,IAAA,OAAW,EAAA,EAAI;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AAGtB,IAAA,OAAO,EAAE,OAAA,EAAS,cAAA,EAAgB,MAAA,EAAQ,GAAA,EAAI;AAAA,EAChD;AAEA,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,CAAC,KAAA,CAAM,CAAC,CAAA,IAAK,CAAC,KAAA,CAAM,CAAC,CAAA,EAAG;AAChD,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,kCAAA,EAAqC,GAAG,CAAA,4BAAA,CAA8B,CAAA;AACnF,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,SAAS,KAAA,CAAM,CAAC,GAAG,MAAA,EAAQ,KAAA,CAAM,CAAC,CAAA,EAAE;AAC/C;;;AC5BA,SAAS,WAAW,IAAA,EAAsB;AACxC,EAAA,OAAO,KACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B;AAMA,SAAS,gBAAgB,KAAA,EAAwB;AAG/C,EAAA,MAAM,WAAA,GAAc,4BAAA;AACpB,EAAA,OAAO,WAAA,CAAY,KAAK,KAAK,CAAA;AAC/B;AAWO,SAAS,iBAAA,CACd,MACA,SAAA,EACQ;AAER,EAAA,MAAM,OAAA,GAAU,WAAW,IAAI,CAAA;AAG/B,EAAA,MAAM,gBAAA,GACJ,yEAAA;AAGF,EAAA,MAAM,aAAA,GACJ,SAAA,IAAa,eAAA,CAAgB,SAAS,IAAI,SAAA,GAAY,gBAAA;AAExD,EAAA,OAAO,OAAA,CACJ,OAAA,CAAQ,cAAA,EAAgB,wDAAwD,CAAA,CAChF,OAAA,CAAQ,aAAA,EAAe,yDAAyD,CAAA,CAChF,OAAA,CAAQ,YAAA,EAAc,wDAAwD,CAAA,CAC9E,OAAA,CAAQ,gBAAA,EAAkB,qBAAqB,CAAA,CAC/C,OAAA,CAAQ,YAAA,EAAc,aAAa,CAAA,CACnC,OAAA,CAAQ,UAAA,EAAY,CAAA,aAAA,EAAgB,aAAa,CAAA,WAAA,CAAa,CAAA,CAC9D,OAAA,CAAQ,OAAO,OAAO,CAAA;AAC3B","file":"chunk-LBE6GIBC.js","sourcesContent":["'use client';\n\n/**\n * Accessibility utilities for keyboard navigation and screen readers.\n */\n\nimport { useCallback, useEffect, useRef, useState, type RefObject } from 'react';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface FocusTrapOptions {\n /** Whether the focus trap is active. */\n active?: boolean;\n /** Whether to focus the first focusable element when activated. */\n autoFocus?: boolean;\n /** Whether to restore focus when deactivated. */\n restoreFocus?: boolean;\n /** Called when Escape is pressed. */\n onEscape?: () => void;\n}\n\nexport interface ArrowNavigationOptions {\n /** Whether navigation wraps around at edges. */\n wrap?: boolean;\n /** Orientation for arrow key mapping. */\n orientation?: 'horizontal' | 'vertical' | 'both';\n /** Callback when active item changes. */\n onActiveChange?: (index: number) => void;\n}\n\nexport interface UseFocusTrapResult {\n /** Ref to attach to the container element. */\n containerRef: RefObject<HTMLElement>;\n /** Activate the focus trap. */\n activate: () => void;\n /** Deactivate the focus trap. */\n deactivate: () => void;\n /** Whether the trap is active. */\n isActive: boolean;\n}\n\nexport interface UseArrowNavigationResult {\n /** Current active index. */\n activeIndex: number;\n /** Set active index. */\n setActiveIndex: (index: number) => void;\n /** Key down handler to attach to container. */\n onKeyDown: (event: React.KeyboardEvent) => void;\n /** Get props for an item. */\n getItemProps: (index: number) => {\n tabIndex: number;\n 'aria-selected': boolean;\n onFocus: () => void;\n };\n}\n\n// ============================================================================\n// Focus Trap Hook\n// ============================================================================\n\n/**\n * Selector for focusable elements.\n */\nconst FOCUSABLE_SELECTOR = [\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'a[href]',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[contenteditable=\"true\"]',\n].join(', ');\n\n/**\n * Get all focusable elements within a container.\n */\nfunction getFocusableElements(container: HTMLElement): HTMLElement[] {\n const elements = container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);\n return Array.from(elements).filter(\n (el) => !el.hasAttribute('aria-hidden') && el.offsetParent !== null\n );\n}\n\n/**\n * Hook to trap focus within a container.\n *\n * @param options - Focus trap options\n * @returns Focus trap controls\n *\n * @example\n * ```tsx\n * function Modal({ isOpen, onClose }) {\n * const { containerRef, activate, deactivate } = useFocusTrap({\n * active: isOpen,\n * onEscape: onClose,\n * });\n *\n * return (\n * <div ref={containerRef} role=\"dialog\" aria-modal=\"true\">\n * <button onClick={onClose}>Close</button>\n * <input type=\"text\" />\n * </div>\n * );\n * }\n * ```\n */\nexport function useFocusTrap(options: FocusTrapOptions = {}): UseFocusTrapResult {\n const {\n active = true,\n autoFocus = true,\n restoreFocus = true,\n onEscape,\n } = options;\n\n const containerRef = useRef<HTMLElement>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const [isActive, setIsActive] = useState(active);\n\n const activate = useCallback(() => {\n if (!containerRef.current) return;\n\n // Store previously focused element\n previousFocusRef.current = document.activeElement as HTMLElement | null;\n\n // Focus first focusable element\n if (autoFocus) {\n const focusable = getFocusableElements(containerRef.current);\n const firstElement = focusable[0];\n if (firstElement) {\n firstElement.focus();\n }\n }\n\n setIsActive(true);\n }, [autoFocus]);\n\n const deactivate = useCallback(() => {\n setIsActive(false);\n\n // Restore focus\n if (restoreFocus && previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n }, [restoreFocus]);\n\n // Handle focus trap\n useEffect(() => {\n if (!isActive || !containerRef.current) return;\n\n const container = containerRef.current;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onEscape?.();\n return;\n }\n\n if (event.key !== 'Tab') return;\n\n const focusable = getFocusableElements(container);\n if (focusable.length === 0) return;\n\n const firstElement = focusable[0];\n const lastElement = focusable[focusable.length - 1];\n\n // Guard against undefined (though array check above should prevent this)\n if (!firstElement || !lastElement) return;\n\n // Shift+Tab on first element -> focus last\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n return;\n }\n\n // Tab on last element -> focus first\n if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n };\n\n // Handle focus escaping the container\n const handleFocusIn = (event: FocusEvent) => {\n if (!container.contains(event.target as Node)) {\n const focusable = getFocusableElements(container);\n const firstElement = focusable[0];\n if (firstElement) {\n firstElement.focus();\n }\n }\n };\n\n container.addEventListener('keydown', handleKeyDown);\n document.addEventListener('focusin', handleFocusIn);\n\n return () => {\n container.removeEventListener('keydown', handleKeyDown);\n document.removeEventListener('focusin', handleFocusIn);\n };\n }, [isActive, onEscape]);\n\n // Auto-activate when active prop changes\n useEffect(() => {\n if (active) {\n activate();\n } else {\n deactivate();\n }\n }, [active, activate, deactivate]);\n\n return {\n containerRef: containerRef as RefObject<HTMLElement>,\n activate,\n deactivate,\n isActive,\n };\n}\n\n// ============================================================================\n// Arrow Navigation Hook\n// ============================================================================\n\n/**\n * Hook for arrow key navigation through a list of items.\n *\n * @param itemCount - Number of items in the list\n * @param options - Navigation options\n * @returns Navigation state and handlers\n *\n * @example\n * ```tsx\n * function Menu({ items }) {\n * const { activeIndex, onKeyDown, getItemProps } = useArrowNavigation(items.length);\n *\n * return (\n * <ul role=\"menu\" onKeyDown={onKeyDown}>\n * {items.map((item, index) => (\n * <li key={index} role=\"menuitem\" {...getItemProps(index)}>\n * {item}\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useArrowNavigation(\n itemCount: number,\n options: ArrowNavigationOptions = {}\n): UseArrowNavigationResult {\n const { wrap = true, orientation = 'vertical', onActiveChange } = options;\n\n const [activeIndex, setActiveIndex] = useState(0);\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n let newIndex = activeIndex;\n let handled = false;\n\n // Map arrow keys based on orientation\n const isNext =\n (orientation === 'vertical' && event.key === 'ArrowDown') ||\n (orientation === 'horizontal' && event.key === 'ArrowRight') ||\n (orientation === 'both' && (event.key === 'ArrowDown' || event.key === 'ArrowRight'));\n\n const isPrev =\n (orientation === 'vertical' && event.key === 'ArrowUp') ||\n (orientation === 'horizontal' && event.key === 'ArrowLeft') ||\n (orientation === 'both' && (event.key === 'ArrowUp' || event.key === 'ArrowLeft'));\n\n if (isNext) {\n handled = true;\n if (activeIndex < itemCount - 1) {\n newIndex = activeIndex + 1;\n } else if (wrap) {\n newIndex = 0;\n }\n } else if (isPrev) {\n handled = true;\n if (activeIndex > 0) {\n newIndex = activeIndex - 1;\n } else if (wrap) {\n newIndex = itemCount - 1;\n }\n } else if (event.key === 'Home') {\n handled = true;\n newIndex = 0;\n } else if (event.key === 'End') {\n handled = true;\n newIndex = itemCount - 1;\n }\n\n if (handled) {\n event.preventDefault();\n setActiveIndex(newIndex);\n onActiveChange?.(newIndex);\n }\n },\n [activeIndex, itemCount, wrap, orientation, onActiveChange]\n );\n\n const getItemProps = useCallback(\n (index: number) => ({\n tabIndex: index === activeIndex ? 0 : -1,\n 'aria-selected': index === activeIndex,\n onFocus: () => {\n setActiveIndex(index);\n onActiveChange?.(index);\n },\n }),\n [activeIndex, onActiveChange]\n );\n\n // Update active index setter to also call callback\n const handleSetActiveIndex = useCallback(\n (index: number) => {\n setActiveIndex(index);\n onActiveChange?.(index);\n },\n [onActiveChange]\n );\n\n return {\n activeIndex,\n setActiveIndex: handleSetActiveIndex,\n onKeyDown: handleKeyDown,\n getItemProps,\n };\n}\n\n// ============================================================================\n// Screen Reader Announcements\n// ============================================================================\n\nlet announceElement: HTMLElement | null = null;\n\n/**\n * Get or create the live region element for announcements.\n */\nfunction getAnnounceElement(): HTMLElement {\n if (announceElement) return announceElement;\n\n // Check if we're in a browser environment\n if (typeof document === 'undefined') {\n throw new Error('announceToScreenReader can only be used in browser environment');\n }\n\n announceElement = document.createElement('div');\n announceElement.setAttribute('role', 'status');\n announceElement.setAttribute('aria-live', 'polite');\n announceElement.setAttribute('aria-atomic', 'true');\n announceElement.style.cssText = [\n 'position: absolute',\n 'width: 1px',\n 'height: 1px',\n 'padding: 0',\n 'margin: -1px',\n 'overflow: hidden',\n 'clip: rect(0, 0, 0, 0)',\n 'white-space: nowrap',\n 'border: 0',\n ].join(';');\n announceElement.id = 'prismiq-announcer';\n\n document.body.appendChild(announceElement);\n return announceElement;\n}\n\n/**\n * Announce a message to screen readers.\n *\n * @param message - The message to announce\n * @param priority - Announcement priority ('polite' or 'assertive')\n *\n * @example\n * ```tsx\n * // Announce a status update\n * announceToScreenReader('Results loaded: 42 items');\n *\n * // Urgent announcement\n * announceToScreenReader('Error: Connection lost', 'assertive');\n * ```\n */\nexport function announceToScreenReader(\n message: string,\n priority: 'polite' | 'assertive' = 'polite'\n): void {\n // Skip in SSR\n if (typeof document === 'undefined') return;\n\n const element = getAnnounceElement();\n element.setAttribute('aria-live', priority);\n\n // Clear and set message (this triggers announcement)\n element.textContent = '';\n // Use requestAnimationFrame to ensure the clear happens first\n requestAnimationFrame(() => {\n element.textContent = message;\n });\n}\n\n// ============================================================================\n// Focus Visible\n// ============================================================================\n\n/**\n * CSS for focus-visible styling.\n * Add this to your global styles or use the useFocusVisible hook.\n */\nexport const focusVisibleStyles = `\n /* Hide focus outline for mouse users */\n :focus:not(:focus-visible) {\n outline: none;\n }\n\n /* Show focus outline for keyboard users */\n :focus-visible {\n outline: 2px solid var(--prismiq-color-primary);\n outline-offset: 2px;\n }\n\n /* Prismiq focus ring class */\n .prismiq-focus-ring:focus-visible {\n outline: 2px solid var(--prismiq-color-primary);\n outline-offset: 2px;\n box-shadow: 0 0 0 4px rgba(var(--prismiq-color-primary-rgb), 0.2);\n }\n`;\n\n/**\n * Hook to detect if focus is visible (keyboard navigation).\n */\nexport function useFocusVisible(): boolean {\n const [focusVisible, setFocusVisible] = useState(false);\n\n useEffect(() => {\n // Skip in SSR\n if (typeof window === 'undefined') return;\n\n let hadKeyboardEvent = false;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Tab') {\n hadKeyboardEvent = true;\n }\n };\n\n const handlePointerDown = () => {\n hadKeyboardEvent = false;\n };\n\n const handleFocus = () => {\n setFocusVisible(hadKeyboardEvent);\n };\n\n const handleBlur = () => {\n setFocusVisible(false);\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n document.addEventListener('pointerdown', handlePointerDown, true);\n document.addEventListener('focus', handleFocus, true);\n document.addEventListener('blur', handleBlur, true);\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown, true);\n document.removeEventListener('pointerdown', handlePointerDown, true);\n document.removeEventListener('focus', handleFocus, true);\n document.removeEventListener('blur', handleBlur, true);\n };\n }, []);\n\n return focusVisible;\n}\n\n// ============================================================================\n// Skip Link\n// ============================================================================\n\n/**\n * Props for the skip link component.\n */\nexport interface SkipLinkProps {\n /** Target element ID to skip to. */\n targetId: string;\n /** Link text. */\n children?: React.ReactNode;\n}\n\n/**\n * Styles for skip link (visually hidden until focused).\n */\nexport const skipLinkStyles: React.CSSProperties = {\n position: 'absolute',\n left: '-9999px',\n zIndex: 9999,\n padding: '1em',\n backgroundColor: 'var(--prismiq-color-background)',\n color: 'var(--prismiq-color-primary)',\n textDecoration: 'underline',\n // When focused, show the link\n};\n\nexport const skipLinkFocusStyles: React.CSSProperties = {\n ...skipLinkStyles,\n left: 0,\n top: 0,\n};\n\n// ============================================================================\n// Roving Tab Index\n// ============================================================================\n\n/**\n * Hook for implementing roving tabindex pattern.\n *\n * @param itemRefs - Refs to the focusable items\n * @param options - Navigation options\n */\nexport function useRovingTabIndex<T extends HTMLElement>(\n itemRefs: RefObject<T>[],\n options: ArrowNavigationOptions = {}\n): UseArrowNavigationResult {\n const result = useArrowNavigation(itemRefs.length, options);\n\n // Focus the active element when activeIndex changes\n useEffect(() => {\n const activeRef = itemRefs[result.activeIndex];\n if (activeRef?.current) {\n activeRef.current.focus();\n }\n }, [result.activeIndex, itemRefs]);\n\n return result;\n}\n","/**\n * Date formatting utilities for converting .NET format strings to JavaScript date formatters.\n *\n * Supports common .NET date format patterns.\n */\n\n/**\n * Convert .NET date format string to JavaScript date formatter.\n *\n * Common patterns:\n * - dd-MMM-yyyy HH:mm -> 20-Mar-2025 17:00\n * - yyyy-MM-dd -> 2025-03-20\n * - MM/dd/yyyy -> 03/20/2025\n * - yyyy-MM-dd HH:mm:ss -> 2025-03-20 17:00:00\n *\n * @param formatString .NET date format string\n * @returns Formatter function\n */\nexport function createDateFormatter(formatString: string): (value: unknown) => string {\n return (value: unknown): string => {\n if (value === null || value === undefined) {\n return '';\n }\n\n // Parse date from various formats\n let date: Date;\n if (value instanceof Date) {\n date = value;\n } else if (typeof value === 'string') {\n date = new Date(value);\n } else if (typeof value === 'number') {\n date = new Date(value);\n } else {\n return String(value);\n }\n\n // Check if date is valid\n if (isNaN(date.getTime())) {\n return String(value);\n }\n\n // Convert .NET format to formatted string\n return formatDateWithPattern(date, formatString);\n };\n}\n\n/**\n * Format date according to .NET format pattern.\n */\nfunction formatDateWithPattern(date: Date, pattern: string): string {\n // Get date components\n const year = date.getFullYear();\n const month = date.getMonth() + 1;\n const day = date.getDate();\n const hours = date.getHours();\n const minutes = date.getMinutes();\n const seconds = date.getSeconds();\n\n // Month names\n const monthNamesShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n const monthNamesFull = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n\n // Day names\n const dayNamesShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\n const dayNamesFull = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];\n\n // Quarter (1-4)\n const quarter = Math.ceil(month / 3);\n\n // Replace tokens\n let result = pattern;\n\n // Quarter - use placeholder to avoid the single-Q pass reprocessing the Q inserted by QQ\n result = result.replace(/QQ/g, '__QUARTER_PLACEHOLDER__');\n result = result.replace(/Q(?!['\"])/g, String(quarter));\n result = result.replace(/__QUARTER_PLACEHOLDER__/g, `Q${quarter}`);\n\n // Year\n result = result.replace(/yyyy/g, String(year).padStart(4, '0'));\n result = result.replace(/yy/g, String(year % 100).padStart(2, '0'));\n\n // Month - use placeholders without pattern letters to avoid subsequent replacements\n // Using «» brackets which won't appear in date format patterns\n result = result.replace(/MMMM/g, '«1»');\n result = result.replace(/MMM/g, '«2»');\n result = result.replace(/MM/g, String(month).padStart(2, '0'));\n result = result.replace(/M/g, String(month));\n\n // Day - use placeholders for day names\n result = result.replace(/dddd/g, '«3»');\n result = result.replace(/ddd/g, '«4»');\n result = result.replace(/dd/g, String(day).padStart(2, '0'));\n result = result.replace(/d/g, String(day));\n\n // Replace month/day name placeholders at the end (after all pattern matching is done)\n result = result.replace(/«1»/g, monthNamesFull[month - 1] || '');\n result = result.replace(/«2»/g, monthNamesShort[month - 1] || '');\n result = result.replace(/«3»/g, dayNamesFull[date.getDay()] || '');\n result = result.replace(/«4»/g, dayNamesShort[date.getDay()] || '');\n\n // Hours (24-hour)\n result = result.replace(/HH/g, String(hours).padStart(2, '0'));\n result = result.replace(/H/g, String(hours));\n\n // Hours (12-hour)\n const hours12 = hours % 12 || 12;\n result = result.replace(/hh/g, String(hours12).padStart(2, '0'));\n result = result.replace(/h/g, String(hours12));\n\n // AM/PM\n const ampm = hours >= 12 ? 'PM' : 'AM';\n result = result.replace(/tt/g, ampm);\n result = result.replace(/t/g, ampm.charAt(0));\n\n // Minutes\n result = result.replace(/mm/g, String(minutes).padStart(2, '0'));\n result = result.replace(/m/g, String(minutes));\n\n // Seconds\n result = result.replace(/ss/g, String(seconds).padStart(2, '0'));\n result = result.replace(/s/g, String(seconds));\n\n return result;\n}\n\n/**\n * Create date formatters from config map.\n *\n * @param dateFormats Map of column name to .NET format string\n * @returns Map of column name to formatter function\n */\nexport function createDateFormatters(\n dateFormats: Record<string, string>\n): Record<string, (value: unknown) => string> {\n const formatters: Record<string, (value: unknown) => string> = {};\n\n for (const [column, format] of Object.entries(dateFormats)) {\n formatters[column] = createDateFormatter(format);\n }\n\n return formatters;\n}\n\n/**\n * Format a Unix timestamp as relative time (e.g., \"5 min ago\").\n *\n * @param timestamp Unix timestamp in seconds\n * @returns Relative time string\n */\nexport function formatRelativeTime(timestamp: number | null | undefined): string {\n if (timestamp === null || timestamp === undefined) {\n return 'Never';\n }\n\n const now = Date.now() / 1000; // Convert to seconds\n const seconds = Math.floor(now - timestamp);\n\n if (seconds < 60) {\n return 'Just now';\n }\n\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) {\n return `${minutes} min ago`;\n }\n\n const hours = Math.floor(minutes / 60);\n if (hours < 24) {\n return `${hours} hr ago`;\n }\n\n const days = Math.floor(hours / 24);\n if (days === 1) {\n return '1 day ago';\n }\n\n return `${days} days ago`;\n}\n","/**\n * Pivot utility for transforming query results from long format to wide format.\n */\n\nimport { createDateFormatter } from './dateFormat';\nimport type { QueryResult } from '../types';\n\nexport interface PivotConfig {\n /** Column whose unique values become new columns. */\n pivotColumn: string;\n /** Column containing values to distribute across pivot columns. */\n valueColumn: string;\n /** Columns to keep as-is (dimension/grouping columns). */\n dimensionColumns: string[];\n /** Optional date format string for pivot column values (date-fns format). */\n pivotColumnFormat?: string;\n}\n\n/**\n * Pivot a query result by transforming unique values in pivotColumn\n * into separate columns.\n *\n * Example:\n * Input (long format):\n * account | date | name | value\n * Cerby | 2025-02-01 | MAU | 9\n * Cerby | 2025-02-01 | Searches | 1\n *\n * Output (wide format):\n * account | date | MAU | Searches\n * Cerby | 2025-02-01 | 9 | 1\n *\n * @param result - The query result to pivot\n * @param config - Pivot configuration\n * @returns Pivoted query result\n */\n/**\n * Format a value for use as a pivot column header.\n * If it looks like a date and a format is provided, format it.\n */\nfunction formatPivotValue(value: unknown, dateFormat?: string): string {\n const strValue = String(value);\n\n if (!dateFormat) {\n return strValue;\n }\n\n // Try to parse as ISO date\n try {\n // Check if it looks like a date string\n if (strValue.match(/^\\d{4}-\\d{2}-\\d{2}/)) {\n const formatter = createDateFormatter(dateFormat);\n const formatted = formatter(strValue);\n if (formatted && formatted !== strValue) {\n return formatted;\n }\n }\n } catch {\n // If parsing fails, return original string\n }\n\n return strValue;\n}\n\nexport function pivotQueryResult(\n result: QueryResult,\n config: PivotConfig\n): QueryResult {\n const { pivotColumn, valueColumn, dimensionColumns, pivotColumnFormat } = config;\n\n // Find column indices\n const pivotColIndex = result.columns.indexOf(pivotColumn);\n const valueColIndex = result.columns.indexOf(valueColumn);\n\n if (pivotColIndex === -1 || valueColIndex === -1) {\n console.warn(\n `[pivot] Cannot pivot: columns not found (pivot=${pivotColIndex}, value=${valueColIndex})`\n );\n return result; // Can't pivot, return as-is\n }\n\n // Get unique pivot values (these become new columns)\n // Keep track of raw values for grouping and formatted values for display\n const rawPivotValues = Array.from(\n new Set(result.rows.map((row) => String(row[pivotColIndex])))\n ).sort();\n\n // Create mapping from raw value to formatted display value\n const pivotValueToDisplay = new Map<string, string>();\n for (const raw of rawPivotValues) {\n pivotValueToDisplay.set(raw, formatPivotValue(raw, pivotColumnFormat));\n }\n\n // Formatted values for column headers\n const pivotValues = rawPivotValues;\n\n // Build dimension column indices\n const dimIndices = dimensionColumns\n .map((col) => result.columns.indexOf(col))\n .filter((idx) => idx !== -1);\n\n // Group rows by dimension values\n const grouped = new Map<string, Map<string, unknown>>();\n\n for (const row of result.rows) {\n // Create key from dimension column values\n const dimValues = dimIndices.map((i) => row[i]);\n const key = dimValues.map((v) => String(v ?? '')).join('|');\n\n if (!grouped.has(key)) {\n // Store dimension values for this group\n const group = new Map<string, unknown>();\n group.set('__dim_values__', dimValues);\n grouped.set(key, group);\n }\n\n const pivotValue = String(row[pivotColIndex]);\n const value = row[valueColIndex];\n grouped.get(key)!.set(pivotValue, value);\n }\n\n // Build pivoted result - use formatted display values for column headers\n const displayColumns = pivotValues.map((pv) => pivotValueToDisplay.get(pv) ?? pv);\n const newColumns = [...dimensionColumns, ...displayColumns];\n const newRows: unknown[][] = [];\n\n for (const [_key, valueMap] of grouped.entries()) {\n const dimValues = valueMap.get('__dim_values__') as unknown[];\n const newRow = [\n ...dimValues,\n ...pivotValues.map((pv) => valueMap.get(pv) ?? null),\n ];\n newRows.push(newRow);\n }\n\n // Build column_types array (dimension types + value type for each pivot column)\n const dimColTypes = dimensionColumns\n .map((col) => {\n const idx = result.columns.indexOf(col);\n return idx !== -1 && result.column_types && result.column_types[idx]\n ? result.column_types[idx]\n : 'text';\n })\n .filter((t): t is string => t !== undefined);\n\n const valueColType = (result.column_types && result.column_types[valueColIndex]) ?? 'numeric';\n const newColumnTypes = [...dimColTypes, ...pivotValues.map(() => valueColType)];\n\n return {\n columns: newColumns,\n column_types: newColumnTypes,\n rows: newRows,\n row_count: newRows.length,\n truncated: result.truncated,\n execution_time_ms: result.execution_time_ms,\n };\n}\n","/**\n * Utilities for parsing column references in \"tableId.column\" format.\n */\n\n/**\n * Parsed column reference with table ID and column name.\n */\nexport interface ColumnReference {\n tableId: string;\n column: string;\n}\n\n/**\n * Parse a column reference in \"tableId.column\" format.\n *\n * @param ref - The column reference string (e.g., \"t1.created_at\")\n * @param defaultTableId - Table ID to use when ref has no table prefix\n * @returns Parsed reference, or null if invalid. Logs a warning only for\n * malformed references (e.g., \"table.\" or \".column\" or \"a.b.c\").\n * Empty/whitespace inputs return null without warning.\n */\nexport function parseColumnRef(\n ref: string,\n defaultTableId: string\n): ColumnReference | null {\n if (!ref || ref.trim() === '') {\n return null;\n }\n\n if (!ref.includes('.')) {\n // Simple column name without table prefix - use default table\n // for backward compatibility with single-table queries\n return { tableId: defaultTableId, column: ref };\n }\n\n const parts = ref.split('.');\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n console.warn(`Invalid column reference format: \"${ref}\". Expected \"tableId.column\"`);\n return null;\n }\n\n return { tableId: parts[0], column: parts[1] };\n}\n","/**\n * Safe markdown parser that escapes HTML to prevent XSS attacks.\n *\n * Supports a limited subset of markdown:\n * - Headings (#, ##, ###)\n * - Bold (**text**)\n * - Italic (*text*)\n * - Inline code (`code`)\n * - Line breaks\n */\n\n/**\n * Escape HTML special characters to prevent XSS.\n */\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\n/**\n * Validate that a CSS style string contains only safe characters.\n * Rejects strings that could break out of the style attribute.\n */\nfunction isValidCssStyle(style: string): boolean {\n // Only allow: letters, numbers, spaces, basic CSS punctuation\n // Reject: quotes, angle brackets, script-related chars\n const safePattern = /^[a-zA-Z0-9\\s:;,.#%()\\-]+$/;\n return safePattern.test(style);\n}\n\n/**\n * Parse markdown text into safe HTML.\n *\n * HTML is escaped first to prevent XSS, then markdown syntax is converted.\n *\n * @param text - Raw markdown text\n * @param codeStyle - Optional inline styles for code blocks\n * @returns Safe HTML string\n */\nexport function parseMarkdownSafe(\n text: string,\n codeStyle?: string\n): string {\n // First escape any HTML to prevent XSS\n const escaped = escapeHtml(text);\n\n // Then apply markdown transforms\n const defaultCodeStyle =\n 'background: rgba(0,0,0,0.05); padding: 0.1em 0.3em; border-radius: 3px;';\n\n // Validate codeStyle to prevent style attribute injection\n const safeCodeStyle =\n codeStyle && isValidCssStyle(codeStyle) ? codeStyle : defaultCodeStyle;\n\n return escaped\n .replace(/^### (.+)$/gm, '<h3 style=\"margin: 0.5em 0; font-size: 1.1em;\">$1</h3>')\n .replace(/^## (.+)$/gm, '<h2 style=\"margin: 0.5em 0; font-size: 1.25em;\">$1</h2>')\n .replace(/^# (.+)$/gm, '<h1 style=\"margin: 0.5em 0; font-size: 1.5em;\">$1</h1>')\n .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\*(.+?)\\*/g, '<em>$1</em>')\n .replace(/`(.+?)`/g, `<code style=\"${safeCodeStyle}\">$1</code>`)\n .replace(/\\n/g, '<br/>');\n}\n"]}