@remyxjs/react 1.0.0-beta → 1.0.4-beta

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 (64) hide show
  1. package/dist/{AttachmentModal-D-uxbXvb.cjs → AttachmentModal-BDFFiZJt.cjs} +2 -2
  2. package/dist/{AttachmentModal-D-uxbXvb.cjs.map → AttachmentModal-BDFFiZJt.cjs.map} +1 -1
  3. package/dist/{AttachmentModal--6T-vYJt.js → AttachmentModal-Di5V6QX-.js} +2 -2
  4. package/dist/{AttachmentModal--6T-vYJt.js.map → AttachmentModal-Di5V6QX-.js.map} +1 -1
  5. package/dist/{ContextMenu-B4K3Zbfp.cjs → ContextMenu-BafbP2Uh.cjs} +2 -2
  6. package/dist/{ContextMenu-B4K3Zbfp.cjs.map → ContextMenu-BafbP2Uh.cjs.map} +1 -1
  7. package/dist/{ContextMenu-D8wNSMc3.js → ContextMenu-DsA0YsY7.js} +2 -2
  8. package/dist/{ContextMenu-D8wNSMc3.js.map → ContextMenu-DsA0YsY7.js.map} +1 -1
  9. package/dist/{EmbedModal-Bh2Tcow9.cjs → EmbedModal-C73lODIT.cjs} +2 -2
  10. package/dist/{EmbedModal-Bh2Tcow9.cjs.map → EmbedModal-C73lODIT.cjs.map} +1 -1
  11. package/dist/{EmbedModal-cxE4maD2.js → EmbedModal-alpHQiAP.js} +2 -2
  12. package/dist/{EmbedModal-cxE4maD2.js.map → EmbedModal-alpHQiAP.js.map} +1 -1
  13. package/dist/{ExportModal-Cf1uE4r_.js → ExportModal-BN8LUaSR.js} +2 -2
  14. package/dist/{ExportModal-Cf1uE4r_.js.map → ExportModal-BN8LUaSR.js.map} +1 -1
  15. package/dist/{ExportModal-DwQVsrZE.cjs → ExportModal-Cu-cCwa6.cjs} +2 -2
  16. package/dist/{ExportModal-DwQVsrZE.cjs.map → ExportModal-Cu-cCwa6.cjs.map} +1 -1
  17. package/dist/{FindReplaceModal-Dgt_MrWb.js → FindReplaceModal-BqNcotUr.js} +2 -2
  18. package/dist/{FindReplaceModal-Dgt_MrWb.js.map → FindReplaceModal-BqNcotUr.js.map} +1 -1
  19. package/dist/{FindReplaceModal-DYL_2z8U.cjs → FindReplaceModal-DgysYT04.cjs} +2 -2
  20. package/dist/{FindReplaceModal-DYL_2z8U.cjs.map → FindReplaceModal-DgysYT04.cjs.map} +1 -1
  21. package/dist/{ImageModal-D39ywxqI.cjs → ImageModal-BzgYXY9y.cjs} +2 -2
  22. package/dist/{ImageModal-D39ywxqI.cjs.map → ImageModal-BzgYXY9y.cjs.map} +1 -1
  23. package/dist/{ImageModal-DqScpPrc.js → ImageModal-bCzSSTmd.js} +2 -2
  24. package/dist/{ImageModal-DqScpPrc.js.map → ImageModal-bCzSSTmd.js.map} +1 -1
  25. package/dist/{ImportDocumentModal-BKqMxO3z.js → ImportDocumentModal-BypTEn2i.js} +4 -4
  26. package/dist/{ImportDocumentModal-BKqMxO3z.js.map → ImportDocumentModal-BypTEn2i.js.map} +1 -1
  27. package/dist/{ImportDocumentModal-Bev9hp_J.cjs → ImportDocumentModal-gCFept9p.cjs} +2 -2
  28. package/dist/{ImportDocumentModal-Bev9hp_J.cjs.map → ImportDocumentModal-gCFept9p.cjs.map} +1 -1
  29. package/dist/{LinkModal-k9IeDtAb.js → LinkModal-CmkK4m-k.js} +3 -3
  30. package/dist/{LinkModal-k9IeDtAb.js.map → LinkModal-CmkK4m-k.js.map} +1 -1
  31. package/dist/{LinkModal-B-igSa-g.cjs → LinkModal-DPxg7YCE.cjs} +2 -2
  32. package/dist/{LinkModal-B-igSa-g.cjs.map → LinkModal-DPxg7YCE.cjs.map} +1 -1
  33. package/dist/{MenuBar-DWxJNHmb.js → MenuBar-DOv7JPwR.js} +2 -2
  34. package/dist/{MenuBar-DWxJNHmb.js.map → MenuBar-DOv7JPwR.js.map} +1 -1
  35. package/dist/{MenuBar-B-ZAX9rH.cjs → MenuBar-Lw_5Jp8u.cjs} +2 -2
  36. package/dist/{MenuBar-B-ZAX9rH.cjs.map → MenuBar-Lw_5Jp8u.cjs.map} +1 -1
  37. package/dist/{ModalOverlay-BDsGgv3_.cjs → ModalOverlay-Dh5quv7X.cjs} +2 -2
  38. package/dist/{ModalOverlay-BDsGgv3_.cjs.map → ModalOverlay-Dh5quv7X.cjs.map} +1 -1
  39. package/dist/{ModalOverlay-CLvRNHmp.js → ModalOverlay-Dt0JiW3M.js} +2 -2
  40. package/dist/{ModalOverlay-CLvRNHmp.js.map → ModalOverlay-Dt0JiW3M.js.map} +1 -1
  41. package/dist/{SourceModal-BNI_i4iW.cjs → SourceModal-CHKC5xcv.cjs} +2 -2
  42. package/dist/{SourceModal-BNI_i4iW.cjs.map → SourceModal-CHKC5xcv.cjs.map} +1 -1
  43. package/dist/{SourceModal-MdTGK3Uf.js → SourceModal-ChhNVz7y.js} +2 -2
  44. package/dist/{SourceModal-MdTGK3Uf.js.map → SourceModal-ChhNVz7y.js.map} +1 -1
  45. package/dist/{TablePickerModal-DYODWEA1.js → TablePickerModal-BnZHyMsk.js} +2 -2
  46. package/dist/{TablePickerModal-DYODWEA1.js.map → TablePickerModal-BnZHyMsk.js.map} +1 -1
  47. package/dist/{TablePickerModal-Do1QyoyM.cjs → TablePickerModal-Dr0wUx_h.cjs} +2 -2
  48. package/dist/{TablePickerModal-Do1QyoyM.cjs.map → TablePickerModal-Dr0wUx_h.cjs.map} +1 -1
  49. package/dist/index-Bg_uAWlM.js +3 -0
  50. package/dist/index-Bg_uAWlM.js.map +1 -0
  51. package/dist/index-DL-qBZZU.js +357 -0
  52. package/dist/index-DL-qBZZU.js.map +1 -0
  53. package/dist/index-OfJxpaev.cjs +2 -0
  54. package/dist/index-OfJxpaev.cjs.map +1 -0
  55. package/dist/index-qh1Yzh-l.cjs +2 -0
  56. package/dist/index-qh1Yzh-l.cjs.map +1 -0
  57. package/dist/remyx-react.cjs +1 -1
  58. package/dist/remyx-react.css +1 -1
  59. package/dist/remyx-react.js +1 -1
  60. package/package.json +3 -3
  61. package/dist/index-C720tbJA.js +0 -359
  62. package/dist/index-C720tbJA.js.map +0 -1
  63. package/dist/index-Dc63uIP0.cjs +0 -2
  64. package/dist/index-Dc63uIP0.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MenuBar-DWxJNHmb.js","sources":["../src/components/MenuBar/MenuItem.jsx","../src/components/MenuBar/MenuBar.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { ICON_MAP, ChevronRightIcon } from '../../icons/index.jsx'\nimport { TOOLTIP_MAP, SHORTCUT_MAP, MODAL_COMMANDS, getShortcutLabel, getCommandActiveState } from '@remyxjs/core'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\n/**\n * Navigate focus between sibling menu items within a menu/submenu.\n * Skips separators and non-focusable elements.\n */\nfunction focusMenuSibling(container, direction) {\n if (!container) return\n const items = Array.from(container.querySelectorAll(':scope > [role=\"menuitem\"], :scope > .rmx-menubar-submenu-wrapper > [role=\"menuitem\"]'))\n const current = document.activeElement\n const idx = items.indexOf(current)\n if (idx === -1) return\n let next\n if (direction === 'down') {\n next = idx < items.length - 1 ? idx + 1 : 0\n } else if (direction === 'up') {\n next = idx > 0 ? idx - 1 : items.length - 1\n } else if (direction === 'home') {\n next = 0\n } else if (direction === 'end') {\n next = items.length - 1\n }\n items[next]?.focus()\n}\n\nfunction MenuItemInner({ item, engine, onOpenModal, onClose }) {\n const selectionState = useSelectionContext()\n\n // Separator\n if (item === '---') {\n return <div className=\"rmx-menubar-separator\" role=\"separator\" />\n }\n\n // Submenu\n if (typeof item === 'object' && item.label && item.items) {\n return (\n <SubMenuItem\n label={item.label}\n items={item.items}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n )\n }\n\n // Regular command item\n const command = typeof item === 'string' ? item : item.command\n const label = TOOLTIP_MAP[command] || command\n const shortcut = getShortcutLabel(command)\n const isActive = getCommandActiveState(command, selectionState, engine)\n const IconComponent = ICON_MAP[command]\n\n const handleClick = (e) => {\n e.preventDefault()\n const modalName = MODAL_COMMANDS[command]\n if (modalName) {\n if (command === 'link') {\n if (selectionState.link) {\n onOpenModal?.('link', selectionState.link)\n } else {\n onOpenModal?.('link', { text: engine.selection.getSelectedText() })\n }\n } else {\n onOpenModal?.(modalName)\n }\n } else {\n engine.executeCommand(command)\n }\n onClose()\n }\n\n const handleKeyDown = (e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n handleClick(e)\n break\n }\n }\n\n return (\n <button\n className={`rmx-menubar-item ${isActive ? 'rmx-active' : ''}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\">\n {IconComponent && <IconComponent size={16} />}\n </span>\n <span className=\"rmx-menubar-item-label\">{label}</span>\n {shortcut && <span className=\"rmx-menubar-shortcut\">{shortcut}</span>}\n </button>\n )\n}\n\nexport const MenuItem = React.memo(MenuItemInner)\n\nfunction SubMenuItem({ label, items, engine, onOpenModal, onClose }) {\n const [open, setOpen] = useState(false)\n const ref = useRef(null)\n const timeoutRef = useRef(null)\n\n const handleEnter = () => {\n clearTimeout(timeoutRef.current)\n setOpen(true)\n }\n\n const handleLeave = () => {\n timeoutRef.current = setTimeout(() => setOpen(false), 150)\n }\n\n const handleKeyDown = useCallback((e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowRight':\n case 'Enter':\n case ' ':\n e.preventDefault()\n setOpen(true)\n // Focus first item in submenu after it renders\n setTimeout(() => {\n const submenu = ref.current?.querySelector('.rmx-menubar-submenu')\n const firstItem = submenu?.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }, 0)\n break\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'ArrowLeft':\n e.preventDefault()\n setOpen(false)\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n }\n }, [])\n\n useEffect(() => {\n return () => clearTimeout(timeoutRef.current)\n }, [])\n\n return (\n <div\n className=\"rmx-menubar-submenu-wrapper\"\n ref={ref}\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n >\n <button\n className=\"rmx-menubar-item rmx-menubar-submenu-trigger\"\n onMouseDown={(e) => e.preventDefault()}\n onKeyDown={handleKeyDown}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\" />\n <span className=\"rmx-menubar-item-label\">{label}</span>\n <span className=\"rmx-menubar-submenu-arrow\"><ChevronRightIcon size={14} /></span>\n </button>\n {open && (\n <div className=\"rmx-menubar-menu rmx-menubar-submenu\" role=\"menu\" aria-label={label}>\n {items.map((subItem, i) => (\n <MenuItem\n key={typeof subItem === 'string' ? `${subItem}-${i}` : subItem.label || i}\n item={subItem}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { MenuItem } from './MenuItem.jsx'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\nfunction MenuBarInner({ config, engine, onOpenModal }) {\n const selectionState = useSelectionContext()\n const [openMenu, setOpenMenu] = useState(null)\n const [hoverMode, setHoverMode] = useState(false)\n const barRef = useRef(null)\n const triggerRefs = useRef([])\n\n // Close on click outside or Escape\n useEffect(() => {\n if (openMenu === null) return\n\n const handleClickOutside = (e) => {\n if (barRef.current && !barRef.current.contains(e.target)) {\n setOpenMenu(null)\n setHoverMode(false)\n }\n }\n\n const handleKeyDown = (e) => {\n if (e.key === 'Escape') {\n setOpenMenu(null)\n setHoverMode(false)\n // Return focus to the trigger that opened this menu\n if (openMenu !== null) {\n triggerRefs.current[openMenu]?.focus()\n }\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleKeyDown)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [openMenu])\n\n const handleTriggerClick = useCallback((index) => {\n if (openMenu === index) {\n setOpenMenu(null)\n setHoverMode(false)\n } else {\n setOpenMenu(index)\n setHoverMode(true)\n }\n }, [openMenu])\n\n const handleTriggerEnter = useCallback((index) => {\n if (hoverMode && openMenu !== null) {\n setOpenMenu(index)\n }\n }, [hoverMode, openMenu])\n\n const handleCloseMenu = useCallback(() => {\n setOpenMenu(null)\n setHoverMode(false)\n }, [])\n\n const handleBarKeyDown = useCallback((e) => {\n const triggers = triggerRefs.current.filter(Boolean)\n const currentIndex = triggers.indexOf(document.activeElement)\n\n switch (e.key) {\n case 'ArrowRight': {\n e.preventDefault()\n const next = currentIndex < triggers.length - 1 ? currentIndex + 1 : 0\n triggers[next]?.focus()\n if (openMenu !== null) setOpenMenu(next)\n break\n }\n case 'ArrowLeft': {\n e.preventDefault()\n const prev = currentIndex > 0 ? currentIndex - 1 : triggers.length - 1\n triggers[prev]?.focus()\n if (openMenu !== null) setOpenMenu(prev)\n break\n }\n case 'ArrowDown': {\n e.preventDefault()\n if (openMenu === null && currentIndex >= 0) {\n setOpenMenu(currentIndex)\n setHoverMode(true)\n }\n // Focus first item in the open dropdown\n const menuEl = barRef.current?.querySelectorAll('.rmx-menubar-menu')?.[0]\n if (menuEl) {\n const firstItem = menuEl.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n triggers[0]?.focus()\n if (openMenu !== null) setOpenMenu(0)\n break\n }\n case 'End': {\n e.preventDefault()\n triggers[triggers.length - 1]?.focus()\n if (openMenu !== null) setOpenMenu(triggers.length - 1)\n break\n }\n }\n }, [openMenu])\n\n if (!engine || !config) return null\n\n return (\n <div\n className=\"rmx-menubar\"\n ref={barRef}\n role=\"menubar\"\n aria-label=\"Editor menu\"\n onKeyDown={handleBarKeyDown}\n >\n {config.map((menu, index) => (\n <div key={menu.label} className=\"rmx-menubar-dropdown\">\n <button\n ref={(el) => { triggerRefs.current[index] = el }}\n className={`rmx-menubar-trigger ${openMenu === index ? 'rmx-open' : ''}`}\n onClick={(e) => {\n e.preventDefault()\n handleTriggerClick(index)\n }}\n onMouseEnter={() => handleTriggerEnter(index)}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={openMenu === index}\n tabIndex={index === 0 ? 0 : -1}\n >\n {menu.label}\n </button>\n {openMenu === index && (\n <div className=\"rmx-menubar-menu\" role=\"menu\" aria-label={menu.label}>\n {menu.items.map((item, i) => (\n <MenuItem\n key={typeof item === 'string' ? `${item}-${i}` : item.label || item.command || i}\n item={item}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={handleCloseMenu}\n />\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\nexport const MenuBar = React.memo(MenuBarInner)\n\n// Re-export for backward compatibility (actual implementation in separate module\n// to avoid forcing eager load of this component when only the utility is needed)\nexport { collectMenuBarCommands } from './collectMenuBarCommands.js'\n"],"names":["focusMenuSibling","container","direction","items","Array","from","querySelectorAll","current","document","activeElement","idx","indexOf","next","length","focus","MenuItem","React","memo","item","engine","onOpenModal","onClose","selectionState","useSelectionContext","className","role","label","jsx","SubMenuItem","command","TOOLTIP_MAP","shortcut","getShortcutLabel","isActive","getCommandActiveState","IconComponent","ICON_MAP","handleClick","e","preventDefault","modalName","MODAL_COMMANDS","link","text","selection","getSelectedText","executeCommand","jsxs","onClick","onKeyDown","menu","currentTarget","closest","key","onMouseDown","type","tabIndex","children","size","open","setOpen","useState","ref","useRef","timeoutRef","handleKeyDown","useCallback","setTimeout","submenu","querySelector","firstItem","useEffect","clearTimeout","onMouseEnter","onMouseLeave","ChevronRightIcon","map","subItem","i","MenuBar","config","openMenu","setOpenMenu","hoverMode","setHoverMode","barRef","triggerRefs","handleClickOutside","contains","target","addEventListener","removeEventListener","handleTriggerClick","index","handleTriggerEnter","handleCloseMenu","handleBarKeyDown","triggers","filter","Boolean","currentIndex","prev","menuEl","el"],"mappings":"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"}
1
+ {"version":3,"file":"MenuBar-DOv7JPwR.js","sources":["../src/components/MenuBar/MenuItem.jsx","../src/components/MenuBar/MenuBar.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { ICON_MAP, ChevronRightIcon } from '../../icons/index.jsx'\nimport { TOOLTIP_MAP, SHORTCUT_MAP, MODAL_COMMANDS, getShortcutLabel, getCommandActiveState } from '@remyxjs/core'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\n/**\n * Navigate focus between sibling menu items within a menu/submenu.\n * Skips separators and non-focusable elements.\n */\nfunction focusMenuSibling(container, direction) {\n if (!container) return\n const items = Array.from(container.querySelectorAll(':scope > [role=\"menuitem\"], :scope > .rmx-menubar-submenu-wrapper > [role=\"menuitem\"]'))\n const current = document.activeElement\n const idx = items.indexOf(current)\n if (idx === -1) return\n let next\n if (direction === 'down') {\n next = idx < items.length - 1 ? idx + 1 : 0\n } else if (direction === 'up') {\n next = idx > 0 ? idx - 1 : items.length - 1\n } else if (direction === 'home') {\n next = 0\n } else if (direction === 'end') {\n next = items.length - 1\n }\n items[next]?.focus()\n}\n\nfunction MenuItemInner({ item, engine, onOpenModal, onClose }) {\n const selectionState = useSelectionContext()\n\n // Separator\n if (item === '---') {\n return <div className=\"rmx-menubar-separator\" role=\"separator\" />\n }\n\n // Submenu\n if (typeof item === 'object' && item.label && item.items) {\n return (\n <SubMenuItem\n label={item.label}\n items={item.items}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n )\n }\n\n // Regular command item\n const command = typeof item === 'string' ? item : item.command\n const label = TOOLTIP_MAP[command] || command\n const shortcut = getShortcutLabel(command)\n const isActive = getCommandActiveState(command, selectionState, engine)\n const IconComponent = ICON_MAP[command]\n\n const handleClick = (e) => {\n e.preventDefault()\n const modalName = MODAL_COMMANDS[command]\n if (modalName) {\n if (command === 'link') {\n if (selectionState.link) {\n onOpenModal?.('link', selectionState.link)\n } else {\n onOpenModal?.('link', { text: engine.selection.getSelectedText() })\n }\n } else {\n onOpenModal?.(modalName)\n }\n } else {\n engine.executeCommand(command)\n }\n onClose()\n }\n\n const handleKeyDown = (e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n handleClick(e)\n break\n }\n }\n\n return (\n <button\n className={`rmx-menubar-item ${isActive ? 'rmx-active' : ''}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\">\n {IconComponent && <IconComponent size={16} />}\n </span>\n <span className=\"rmx-menubar-item-label\">{label}</span>\n {shortcut && <span className=\"rmx-menubar-shortcut\">{shortcut}</span>}\n </button>\n )\n}\n\nexport const MenuItem = React.memo(MenuItemInner)\n\nfunction SubMenuItem({ label, items, engine, onOpenModal, onClose }) {\n const [open, setOpen] = useState(false)\n const ref = useRef(null)\n const timeoutRef = useRef(null)\n\n const handleEnter = () => {\n clearTimeout(timeoutRef.current)\n setOpen(true)\n }\n\n const handleLeave = () => {\n timeoutRef.current = setTimeout(() => setOpen(false), 150)\n }\n\n const handleKeyDown = useCallback((e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowRight':\n case 'Enter':\n case ' ':\n e.preventDefault()\n setOpen(true)\n // Focus first item in submenu after it renders\n setTimeout(() => {\n const submenu = ref.current?.querySelector('.rmx-menubar-submenu')\n const firstItem = submenu?.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }, 0)\n break\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'ArrowLeft':\n e.preventDefault()\n setOpen(false)\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n }\n }, [])\n\n useEffect(() => {\n return () => clearTimeout(timeoutRef.current)\n }, [])\n\n return (\n <div\n className=\"rmx-menubar-submenu-wrapper\"\n ref={ref}\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n >\n <button\n className=\"rmx-menubar-item rmx-menubar-submenu-trigger\"\n onMouseDown={(e) => e.preventDefault()}\n onKeyDown={handleKeyDown}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\" />\n <span className=\"rmx-menubar-item-label\">{label}</span>\n <span className=\"rmx-menubar-submenu-arrow\"><ChevronRightIcon size={14} /></span>\n </button>\n {open && (\n <div className=\"rmx-menubar-menu rmx-menubar-submenu\" role=\"menu\" aria-label={label}>\n {items.map((subItem, i) => (\n <MenuItem\n key={typeof subItem === 'string' ? `${subItem}-${i}` : subItem.label || i}\n item={subItem}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { MenuItem } from './MenuItem.jsx'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\nfunction MenuBarInner({ config, engine, onOpenModal }) {\n const selectionState = useSelectionContext()\n const [openMenu, setOpenMenu] = useState(null)\n const [hoverMode, setHoverMode] = useState(false)\n const barRef = useRef(null)\n const triggerRefs = useRef([])\n\n // Close on click outside or Escape\n useEffect(() => {\n if (openMenu === null) return\n\n const handleClickOutside = (e) => {\n if (barRef.current && !barRef.current.contains(e.target)) {\n setOpenMenu(null)\n setHoverMode(false)\n }\n }\n\n const handleKeyDown = (e) => {\n if (e.key === 'Escape') {\n setOpenMenu(null)\n setHoverMode(false)\n // Return focus to the trigger that opened this menu\n if (openMenu !== null) {\n triggerRefs.current[openMenu]?.focus()\n }\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleKeyDown)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [openMenu])\n\n const handleTriggerClick = useCallback((index) => {\n if (openMenu === index) {\n setOpenMenu(null)\n setHoverMode(false)\n } else {\n setOpenMenu(index)\n setHoverMode(true)\n }\n }, [openMenu])\n\n const handleTriggerEnter = useCallback((index) => {\n if (hoverMode && openMenu !== null) {\n setOpenMenu(index)\n }\n }, [hoverMode, openMenu])\n\n const handleCloseMenu = useCallback(() => {\n setOpenMenu(null)\n setHoverMode(false)\n }, [])\n\n const handleBarKeyDown = useCallback((e) => {\n const triggers = triggerRefs.current.filter(Boolean)\n const currentIndex = triggers.indexOf(document.activeElement)\n\n switch (e.key) {\n case 'ArrowRight': {\n e.preventDefault()\n const next = currentIndex < triggers.length - 1 ? currentIndex + 1 : 0\n triggers[next]?.focus()\n if (openMenu !== null) setOpenMenu(next)\n break\n }\n case 'ArrowLeft': {\n e.preventDefault()\n const prev = currentIndex > 0 ? currentIndex - 1 : triggers.length - 1\n triggers[prev]?.focus()\n if (openMenu !== null) setOpenMenu(prev)\n break\n }\n case 'ArrowDown': {\n e.preventDefault()\n if (openMenu === null && currentIndex >= 0) {\n setOpenMenu(currentIndex)\n setHoverMode(true)\n }\n // Focus first item in the open dropdown\n const menuEl = barRef.current?.querySelectorAll('.rmx-menubar-menu')?.[0]\n if (menuEl) {\n const firstItem = menuEl.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n triggers[0]?.focus()\n if (openMenu !== null) setOpenMenu(0)\n break\n }\n case 'End': {\n e.preventDefault()\n triggers[triggers.length - 1]?.focus()\n if (openMenu !== null) setOpenMenu(triggers.length - 1)\n break\n }\n }\n }, [openMenu])\n\n if (!engine || !config) return null\n\n return (\n <div\n className=\"rmx-menubar\"\n ref={barRef}\n role=\"menubar\"\n aria-label=\"Editor menu\"\n onKeyDown={handleBarKeyDown}\n >\n {config.map((menu, index) => (\n <div key={menu.label} className=\"rmx-menubar-dropdown\">\n <button\n ref={(el) => { triggerRefs.current[index] = el }}\n className={`rmx-menubar-trigger ${openMenu === index ? 'rmx-open' : ''}`}\n onClick={(e) => {\n e.preventDefault()\n handleTriggerClick(index)\n }}\n onMouseEnter={() => handleTriggerEnter(index)}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={openMenu === index}\n tabIndex={index === 0 ? 0 : -1}\n >\n {menu.label}\n </button>\n {openMenu === index && (\n <div className=\"rmx-menubar-menu\" role=\"menu\" aria-label={menu.label}>\n {menu.items.map((item, i) => (\n <MenuItem\n key={typeof item === 'string' ? `${item}-${i}` : item.label || item.command || i}\n item={item}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={handleCloseMenu}\n />\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\nexport const MenuBar = React.memo(MenuBarInner)\n\n// Re-export for backward compatibility (actual implementation in separate module\n// to avoid forcing eager load of this component when only the utility is needed)\nexport { collectMenuBarCommands } from './collectMenuBarCommands.js'\n"],"names":["focusMenuSibling","container","direction","items","Array","from","querySelectorAll","current","document","activeElement","idx","indexOf","next","length","focus","MenuItem","React","memo","item","engine","onOpenModal","onClose","selectionState","useSelectionContext","className","role","label","jsx","SubMenuItem","command","TOOLTIP_MAP","shortcut","getShortcutLabel","isActive","getCommandActiveState","IconComponent","ICON_MAP","handleClick","e","preventDefault","modalName","MODAL_COMMANDS","link","text","selection","getSelectedText","executeCommand","jsxs","onClick","onKeyDown","menu","currentTarget","closest","key","onMouseDown","type","tabIndex","children","size","open","setOpen","useState","ref","useRef","timeoutRef","handleKeyDown","useCallback","setTimeout","submenu","querySelector","firstItem","useEffect","clearTimeout","onMouseEnter","onMouseLeave","ChevronRightIcon","map","subItem","i","MenuBar","config","openMenu","setOpenMenu","hoverMode","setHoverMode","barRef","triggerRefs","handleClickOutside","contains","target","addEventListener","removeEventListener","handleTriggerClick","index","handleTriggerEnter","handleCloseMenu","handleBarKeyDown","triggers","filter","Boolean","currentIndex","prev","menuEl","el"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),r=require("./index-Dc63uIP0.cjs"),t=require("@remyxjs/core");function a(e,n){if(!e)return;const r=Array.from(e.querySelectorAll(':scope > [role="menuitem"], :scope > .rmx-menubar-submenu-wrapper > [role="menuitem"]')),t=document.activeElement,a=r.indexOf(t);if(-1===a)return;let u;"down"===n?u=a<r.length-1?a+1:0:"up"===n?u=a>0?a-1:r.length-1:"home"===n?u=0:"end"===n&&(u=r.length-1),r[u]?.focus()}const u=n.memo((function({item:n,engine:u,onOpenModal:l,onClose:s}){const c=r.useSelectionContext();if("---"===n)return e.jsx("div",{className:"rmx-menubar-separator",role:"separator"});if("object"==typeof n&&n.label&&n.items)return e.jsx(o,{label:n.label,items:n.items,engine:u,onOpenModal:l,onClose:s});const m="string"==typeof n?n:n.command,i=t.TOOLTIP_MAP[m]||m,b=t.getShortcutLabel(m),p=t.getCommandActiveState(m,c,u),d=r.ICON_MAP[m],f=e=>{e.preventDefault();const n=t.MODAL_COMMANDS[m];n?"link"===m?c.link?l?.("link",c.link):l?.("link",{text:u.selection.getSelectedText()}):l?.(n):u.executeCommand(m),s()};return e.jsxs("button",{className:"rmx-menubar-item "+(p?"rmx-active":""),onClick:f,onKeyDown:e=>{const n=e.currentTarget.closest(".rmx-menubar-menu");switch(e.key){case"ArrowDown":e.preventDefault(),a(n,"down");break;case"ArrowUp":e.preventDefault(),a(n,"up");break;case"Home":e.preventDefault(),a(n,"home");break;case"End":e.preventDefault(),a(n,"end");break;case"Enter":case" ":e.preventDefault(),f(e)}},onMouseDown:e=>e.preventDefault(),type:"button",role:"menuitem",tabIndex:-1,children:[e.jsx("span",{className:"rmx-menubar-item-icon",children:d&&e.jsx(d,{size:16})}),e.jsx("span",{className:"rmx-menubar-item-label",children:i}),b&&e.jsx("span",{className:"rmx-menubar-shortcut",children:b})]})}));function o({label:t,items:o,engine:l,onOpenModal:s,onClose:c}){const[m,i]=n.useState(!1),b=n.useRef(null),p=n.useRef(null),d=n.useCallback((e=>{const n=e.currentTarget.closest(".rmx-menubar-menu");switch(e.key){case"ArrowRight":case"Enter":case" ":e.preventDefault(),i(!0),setTimeout((()=>{const e=b.current?.querySelector(".rmx-menubar-submenu"),n=e?.querySelector('[role="menuitem"]');n?.focus()}),0);break;case"ArrowDown":e.preventDefault(),a(n,"down");break;case"ArrowUp":e.preventDefault(),a(n,"up");break;case"ArrowLeft":e.preventDefault(),i(!1);break;case"Home":e.preventDefault(),a(n,"home");break;case"End":e.preventDefault(),a(n,"end")}}),[]);return n.useEffect((()=>()=>clearTimeout(p.current)),[]),e.jsxs("div",{className:"rmx-menubar-submenu-wrapper",ref:b,onMouseEnter:()=>{clearTimeout(p.current),i(!0)},onMouseLeave:()=>{p.current=setTimeout((()=>i(!1)),150)},children:[e.jsxs("button",{className:"rmx-menubar-item rmx-menubar-submenu-trigger",onMouseDown:e=>e.preventDefault(),onKeyDown:d,type:"button",role:"menuitem","aria-haspopup":"true","aria-expanded":m,tabIndex:-1,children:[e.jsx("span",{className:"rmx-menubar-item-icon"}),e.jsx("span",{className:"rmx-menubar-item-label",children:t}),e.jsx("span",{className:"rmx-menubar-submenu-arrow",children:e.jsx(r.ChevronRightIcon,{size:14})})]}),m&&e.jsx("div",{className:"rmx-menubar-menu rmx-menubar-submenu",role:"menu","aria-label":t,children:o.map(((n,r)=>e.jsx(u,{item:n,engine:l,onOpenModal:s,onClose:c},"string"==typeof n?`${n}-${r}`:n.label||r)))})]})}const l=n.memo((function({config:t,engine:a,onOpenModal:o}){r.useSelectionContext();const[l,s]=n.useState(null),[c,m]=n.useState(!1),i=n.useRef(null),b=n.useRef([]);n.useEffect((()=>{if(null===l)return;const e=e=>{i.current&&!i.current.contains(e.target)&&(s(null),m(!1))},n=e=>{"Escape"===e.key&&(s(null),m(!1),null!==l&&b.current[l]?.focus())};return document.addEventListener("mousedown",e),document.addEventListener("keydown",n),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("keydown",n)}}),[l]);const p=n.useCallback((e=>{l===e?(s(null),m(!1)):(s(e),m(!0))}),[l]),d=n.useCallback((e=>{c&&null!==l&&s(e)}),[c,l]),f=n.useCallback((()=>{s(null),m(!1)}),[]),x=n.useCallback((e=>{const n=b.current.filter(Boolean),r=n.indexOf(document.activeElement);switch(e.key){case"ArrowRight":{e.preventDefault();const t=r<n.length-1?r+1:0;n[t]?.focus(),null!==l&&s(t);break}case"ArrowLeft":{e.preventDefault();const t=r>0?r-1:n.length-1;n[t]?.focus(),null!==l&&s(t);break}case"ArrowDown":{e.preventDefault(),null===l&&r>=0&&(s(r),m(!0));const n=i.current?.querySelectorAll(".rmx-menubar-menu")?.[0];if(n){const e=n.querySelector('[role="menuitem"]');e?.focus()}break}case"Home":e.preventDefault(),n[0]?.focus(),null!==l&&s(0);break;case"End":e.preventDefault(),n[n.length-1]?.focus(),null!==l&&s(n.length-1)}}),[l]);return a&&t?e.jsx("div",{className:"rmx-menubar",ref:i,role:"menubar","aria-label":"Editor menu",onKeyDown:x,children:t.map(((n,r)=>e.jsxs("div",{className:"rmx-menubar-dropdown",children:[e.jsx("button",{ref:e=>{b.current[r]=e},className:"rmx-menubar-trigger "+(l===r?"rmx-open":""),onClick:e=>{e.preventDefault(),p(r)},onMouseEnter:()=>d(r),onMouseDown:e=>e.preventDefault(),type:"button",role:"menuitem","aria-haspopup":"true","aria-expanded":l===r,tabIndex:0===r?0:-1,children:n.label}),l===r&&e.jsx("div",{className:"rmx-menubar-menu",role:"menu","aria-label":n.label,children:n.items.map(((n,r)=>e.jsx(u,{item:n,engine:a,onOpenModal:o,onClose:f},"string"==typeof n?`${n}-${r}`:n.label||n.command||r)))})]},n.label)))}):null}));exports.MenuBar=l;
2
- //# sourceMappingURL=MenuBar-B-ZAX9rH.cjs.map
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),n=require("react"),r=require("./index-qh1Yzh-l.cjs"),t=require("@remyxjs/core");function a(e,n){if(!e)return;const r=Array.from(e.querySelectorAll(':scope > [role="menuitem"], :scope > .rmx-menubar-submenu-wrapper > [role="menuitem"]')),t=document.activeElement,a=r.indexOf(t);if(-1===a)return;let u;"down"===n?u=a<r.length-1?a+1:0:"up"===n?u=a>0?a-1:r.length-1:"home"===n?u=0:"end"===n&&(u=r.length-1),r[u]?.focus()}const u=n.memo((function({item:n,engine:u,onOpenModal:l,onClose:s}){const c=r.useSelectionContext();if("---"===n)return e.jsx("div",{className:"rmx-menubar-separator",role:"separator"});if("object"==typeof n&&n.label&&n.items)return e.jsx(o,{label:n.label,items:n.items,engine:u,onOpenModal:l,onClose:s});const m="string"==typeof n?n:n.command,i=t.TOOLTIP_MAP[m]||m,b=t.getShortcutLabel(m),p=t.getCommandActiveState(m,c,u),d=r.ICON_MAP[m],f=e=>{e.preventDefault();const n=t.MODAL_COMMANDS[m];n?"link"===m?c.link?l?.("link",c.link):l?.("link",{text:u.selection.getSelectedText()}):l?.(n):u.executeCommand(m),s()};return e.jsxs("button",{className:"rmx-menubar-item "+(p?"rmx-active":""),onClick:f,onKeyDown:e=>{const n=e.currentTarget.closest(".rmx-menubar-menu");switch(e.key){case"ArrowDown":e.preventDefault(),a(n,"down");break;case"ArrowUp":e.preventDefault(),a(n,"up");break;case"Home":e.preventDefault(),a(n,"home");break;case"End":e.preventDefault(),a(n,"end");break;case"Enter":case" ":e.preventDefault(),f(e)}},onMouseDown:e=>e.preventDefault(),type:"button",role:"menuitem",tabIndex:-1,children:[e.jsx("span",{className:"rmx-menubar-item-icon",children:d&&e.jsx(d,{size:16})}),e.jsx("span",{className:"rmx-menubar-item-label",children:i}),b&&e.jsx("span",{className:"rmx-menubar-shortcut",children:b})]})}));function o({label:t,items:o,engine:l,onOpenModal:s,onClose:c}){const[m,i]=n.useState(!1),b=n.useRef(null),p=n.useRef(null),d=n.useCallback((e=>{const n=e.currentTarget.closest(".rmx-menubar-menu");switch(e.key){case"ArrowRight":case"Enter":case" ":e.preventDefault(),i(!0),setTimeout((()=>{const e=b.current?.querySelector(".rmx-menubar-submenu"),n=e?.querySelector('[role="menuitem"]');n?.focus()}),0);break;case"ArrowDown":e.preventDefault(),a(n,"down");break;case"ArrowUp":e.preventDefault(),a(n,"up");break;case"ArrowLeft":e.preventDefault(),i(!1);break;case"Home":e.preventDefault(),a(n,"home");break;case"End":e.preventDefault(),a(n,"end")}}),[]);return n.useEffect((()=>()=>clearTimeout(p.current)),[]),e.jsxs("div",{className:"rmx-menubar-submenu-wrapper",ref:b,onMouseEnter:()=>{clearTimeout(p.current),i(!0)},onMouseLeave:()=>{p.current=setTimeout((()=>i(!1)),150)},children:[e.jsxs("button",{className:"rmx-menubar-item rmx-menubar-submenu-trigger",onMouseDown:e=>e.preventDefault(),onKeyDown:d,type:"button",role:"menuitem","aria-haspopup":"true","aria-expanded":m,tabIndex:-1,children:[e.jsx("span",{className:"rmx-menubar-item-icon"}),e.jsx("span",{className:"rmx-menubar-item-label",children:t}),e.jsx("span",{className:"rmx-menubar-submenu-arrow",children:e.jsx(r.ChevronRightIcon,{size:14})})]}),m&&e.jsx("div",{className:"rmx-menubar-menu rmx-menubar-submenu",role:"menu","aria-label":t,children:o.map(((n,r)=>e.jsx(u,{item:n,engine:l,onOpenModal:s,onClose:c},"string"==typeof n?`${n}-${r}`:n.label||r)))})]})}const l=n.memo((function({config:t,engine:a,onOpenModal:o}){r.useSelectionContext();const[l,s]=n.useState(null),[c,m]=n.useState(!1),i=n.useRef(null),b=n.useRef([]);n.useEffect((()=>{if(null===l)return;const e=e=>{i.current&&!i.current.contains(e.target)&&(s(null),m(!1))},n=e=>{"Escape"===e.key&&(s(null),m(!1),null!==l&&b.current[l]?.focus())};return document.addEventListener("mousedown",e),document.addEventListener("keydown",n),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("keydown",n)}}),[l]);const p=n.useCallback((e=>{l===e?(s(null),m(!1)):(s(e),m(!0))}),[l]),d=n.useCallback((e=>{c&&null!==l&&s(e)}),[c,l]),f=n.useCallback((()=>{s(null),m(!1)}),[]),x=n.useCallback((e=>{const n=b.current.filter(Boolean),r=n.indexOf(document.activeElement);switch(e.key){case"ArrowRight":{e.preventDefault();const t=r<n.length-1?r+1:0;n[t]?.focus(),null!==l&&s(t);break}case"ArrowLeft":{e.preventDefault();const t=r>0?r-1:n.length-1;n[t]?.focus(),null!==l&&s(t);break}case"ArrowDown":{e.preventDefault(),null===l&&r>=0&&(s(r),m(!0));const n=i.current?.querySelectorAll(".rmx-menubar-menu")?.[0];if(n){const e=n.querySelector('[role="menuitem"]');e?.focus()}break}case"Home":e.preventDefault(),n[0]?.focus(),null!==l&&s(0);break;case"End":e.preventDefault(),n[n.length-1]?.focus(),null!==l&&s(n.length-1)}}),[l]);return a&&t?e.jsx("div",{className:"rmx-menubar",ref:i,role:"menubar","aria-label":"Editor menu",onKeyDown:x,children:t.map(((n,r)=>e.jsxs("div",{className:"rmx-menubar-dropdown",children:[e.jsx("button",{ref:e=>{b.current[r]=e},className:"rmx-menubar-trigger "+(l===r?"rmx-open":""),onClick:e=>{e.preventDefault(),p(r)},onMouseEnter:()=>d(r),onMouseDown:e=>e.preventDefault(),type:"button",role:"menuitem","aria-haspopup":"true","aria-expanded":l===r,tabIndex:0===r?0:-1,children:n.label}),l===r&&e.jsx("div",{className:"rmx-menubar-menu",role:"menu","aria-label":n.label,children:n.items.map(((n,r)=>e.jsx(u,{item:n,engine:a,onOpenModal:o,onClose:f},"string"==typeof n?`${n}-${r}`:n.label||n.command||r)))})]},n.label)))}):null}));exports.MenuBar=l;
2
+ //# sourceMappingURL=MenuBar-Lw_5Jp8u.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"MenuBar-B-ZAX9rH.cjs","sources":["../src/components/MenuBar/MenuItem.jsx","../src/components/MenuBar/MenuBar.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { ICON_MAP, ChevronRightIcon } from '../../icons/index.jsx'\nimport { TOOLTIP_MAP, SHORTCUT_MAP, MODAL_COMMANDS, getShortcutLabel, getCommandActiveState } from '@remyxjs/core'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\n/**\n * Navigate focus between sibling menu items within a menu/submenu.\n * Skips separators and non-focusable elements.\n */\nfunction focusMenuSibling(container, direction) {\n if (!container) return\n const items = Array.from(container.querySelectorAll(':scope > [role=\"menuitem\"], :scope > .rmx-menubar-submenu-wrapper > [role=\"menuitem\"]'))\n const current = document.activeElement\n const idx = items.indexOf(current)\n if (idx === -1) return\n let next\n if (direction === 'down') {\n next = idx < items.length - 1 ? idx + 1 : 0\n } else if (direction === 'up') {\n next = idx > 0 ? idx - 1 : items.length - 1\n } else if (direction === 'home') {\n next = 0\n } else if (direction === 'end') {\n next = items.length - 1\n }\n items[next]?.focus()\n}\n\nfunction MenuItemInner({ item, engine, onOpenModal, onClose }) {\n const selectionState = useSelectionContext()\n\n // Separator\n if (item === '---') {\n return <div className=\"rmx-menubar-separator\" role=\"separator\" />\n }\n\n // Submenu\n if (typeof item === 'object' && item.label && item.items) {\n return (\n <SubMenuItem\n label={item.label}\n items={item.items}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n )\n }\n\n // Regular command item\n const command = typeof item === 'string' ? item : item.command\n const label = TOOLTIP_MAP[command] || command\n const shortcut = getShortcutLabel(command)\n const isActive = getCommandActiveState(command, selectionState, engine)\n const IconComponent = ICON_MAP[command]\n\n const handleClick = (e) => {\n e.preventDefault()\n const modalName = MODAL_COMMANDS[command]\n if (modalName) {\n if (command === 'link') {\n if (selectionState.link) {\n onOpenModal?.('link', selectionState.link)\n } else {\n onOpenModal?.('link', { text: engine.selection.getSelectedText() })\n }\n } else {\n onOpenModal?.(modalName)\n }\n } else {\n engine.executeCommand(command)\n }\n onClose()\n }\n\n const handleKeyDown = (e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n handleClick(e)\n break\n }\n }\n\n return (\n <button\n className={`rmx-menubar-item ${isActive ? 'rmx-active' : ''}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\">\n {IconComponent && <IconComponent size={16} />}\n </span>\n <span className=\"rmx-menubar-item-label\">{label}</span>\n {shortcut && <span className=\"rmx-menubar-shortcut\">{shortcut}</span>}\n </button>\n )\n}\n\nexport const MenuItem = React.memo(MenuItemInner)\n\nfunction SubMenuItem({ label, items, engine, onOpenModal, onClose }) {\n const [open, setOpen] = useState(false)\n const ref = useRef(null)\n const timeoutRef = useRef(null)\n\n const handleEnter = () => {\n clearTimeout(timeoutRef.current)\n setOpen(true)\n }\n\n const handleLeave = () => {\n timeoutRef.current = setTimeout(() => setOpen(false), 150)\n }\n\n const handleKeyDown = useCallback((e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowRight':\n case 'Enter':\n case ' ':\n e.preventDefault()\n setOpen(true)\n // Focus first item in submenu after it renders\n setTimeout(() => {\n const submenu = ref.current?.querySelector('.rmx-menubar-submenu')\n const firstItem = submenu?.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }, 0)\n break\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'ArrowLeft':\n e.preventDefault()\n setOpen(false)\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n }\n }, [])\n\n useEffect(() => {\n return () => clearTimeout(timeoutRef.current)\n }, [])\n\n return (\n <div\n className=\"rmx-menubar-submenu-wrapper\"\n ref={ref}\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n >\n <button\n className=\"rmx-menubar-item rmx-menubar-submenu-trigger\"\n onMouseDown={(e) => e.preventDefault()}\n onKeyDown={handleKeyDown}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\" />\n <span className=\"rmx-menubar-item-label\">{label}</span>\n <span className=\"rmx-menubar-submenu-arrow\"><ChevronRightIcon size={14} /></span>\n </button>\n {open && (\n <div className=\"rmx-menubar-menu rmx-menubar-submenu\" role=\"menu\" aria-label={label}>\n {items.map((subItem, i) => (\n <MenuItem\n key={typeof subItem === 'string' ? `${subItem}-${i}` : subItem.label || i}\n item={subItem}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { MenuItem } from './MenuItem.jsx'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\nfunction MenuBarInner({ config, engine, onOpenModal }) {\n const selectionState = useSelectionContext()\n const [openMenu, setOpenMenu] = useState(null)\n const [hoverMode, setHoverMode] = useState(false)\n const barRef = useRef(null)\n const triggerRefs = useRef([])\n\n // Close on click outside or Escape\n useEffect(() => {\n if (openMenu === null) return\n\n const handleClickOutside = (e) => {\n if (barRef.current && !barRef.current.contains(e.target)) {\n setOpenMenu(null)\n setHoverMode(false)\n }\n }\n\n const handleKeyDown = (e) => {\n if (e.key === 'Escape') {\n setOpenMenu(null)\n setHoverMode(false)\n // Return focus to the trigger that opened this menu\n if (openMenu !== null) {\n triggerRefs.current[openMenu]?.focus()\n }\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleKeyDown)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [openMenu])\n\n const handleTriggerClick = useCallback((index) => {\n if (openMenu === index) {\n setOpenMenu(null)\n setHoverMode(false)\n } else {\n setOpenMenu(index)\n setHoverMode(true)\n }\n }, [openMenu])\n\n const handleTriggerEnter = useCallback((index) => {\n if (hoverMode && openMenu !== null) {\n setOpenMenu(index)\n }\n }, [hoverMode, openMenu])\n\n const handleCloseMenu = useCallback(() => {\n setOpenMenu(null)\n setHoverMode(false)\n }, [])\n\n const handleBarKeyDown = useCallback((e) => {\n const triggers = triggerRefs.current.filter(Boolean)\n const currentIndex = triggers.indexOf(document.activeElement)\n\n switch (e.key) {\n case 'ArrowRight': {\n e.preventDefault()\n const next = currentIndex < triggers.length - 1 ? currentIndex + 1 : 0\n triggers[next]?.focus()\n if (openMenu !== null) setOpenMenu(next)\n break\n }\n case 'ArrowLeft': {\n e.preventDefault()\n const prev = currentIndex > 0 ? currentIndex - 1 : triggers.length - 1\n triggers[prev]?.focus()\n if (openMenu !== null) setOpenMenu(prev)\n break\n }\n case 'ArrowDown': {\n e.preventDefault()\n if (openMenu === null && currentIndex >= 0) {\n setOpenMenu(currentIndex)\n setHoverMode(true)\n }\n // Focus first item in the open dropdown\n const menuEl = barRef.current?.querySelectorAll('.rmx-menubar-menu')?.[0]\n if (menuEl) {\n const firstItem = menuEl.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n triggers[0]?.focus()\n if (openMenu !== null) setOpenMenu(0)\n break\n }\n case 'End': {\n e.preventDefault()\n triggers[triggers.length - 1]?.focus()\n if (openMenu !== null) setOpenMenu(triggers.length - 1)\n break\n }\n }\n }, [openMenu])\n\n if (!engine || !config) return null\n\n return (\n <div\n className=\"rmx-menubar\"\n ref={barRef}\n role=\"menubar\"\n aria-label=\"Editor menu\"\n onKeyDown={handleBarKeyDown}\n >\n {config.map((menu, index) => (\n <div key={menu.label} className=\"rmx-menubar-dropdown\">\n <button\n ref={(el) => { triggerRefs.current[index] = el }}\n className={`rmx-menubar-trigger ${openMenu === index ? 'rmx-open' : ''}`}\n onClick={(e) => {\n e.preventDefault()\n handleTriggerClick(index)\n }}\n onMouseEnter={() => handleTriggerEnter(index)}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={openMenu === index}\n tabIndex={index === 0 ? 0 : -1}\n >\n {menu.label}\n </button>\n {openMenu === index && (\n <div className=\"rmx-menubar-menu\" role=\"menu\" aria-label={menu.label}>\n {menu.items.map((item, i) => (\n <MenuItem\n key={typeof item === 'string' ? `${item}-${i}` : item.label || item.command || i}\n item={item}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={handleCloseMenu}\n />\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\nexport const MenuBar = React.memo(MenuBarInner)\n\n// Re-export for backward compatibility (actual implementation in separate module\n// to avoid forcing eager load of this component when only the utility is needed)\nexport { collectMenuBarCommands } from './collectMenuBarCommands.js'\n"],"names":["focusMenuSibling","container","direction","items","Array","from","querySelectorAll","current","document","activeElement","idx","indexOf","next","length","focus","MenuItem","React","memo","item","engine","onOpenModal","onClose","selectionState","useSelectionContext","jsx","className","role","label","SubMenuItem","command","TOOLTIP_MAP","shortcut","getShortcutLabel","isActive","getCommandActiveState","IconComponent","ICON_MAP","handleClick","e","preventDefault","modalName","MODAL_COMMANDS","link","text","selection","getSelectedText","executeCommand","jsxs","onClick","onKeyDown","menu","currentTarget","closest","key","onMouseDown","type","tabIndex","children","size","open","setOpen","useState","ref","useRef","timeoutRef","handleKeyDown","useCallback","setTimeout","submenu","querySelector","firstItem","useEffect","clearTimeout","onMouseEnter","onMouseLeave","ChevronRightIcon","map","subItem","i","MenuBar","config","openMenu","setOpenMenu","hoverMode","setHoverMode","barRef","triggerRefs","handleClickOutside","contains","target","addEventListener","removeEventListener","handleTriggerClick","index","handleTriggerEnter","handleCloseMenu","handleBarKeyDown","triggers","filter","Boolean","currentIndex","prev","menuEl","el"],"mappings":"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"}
1
+ {"version":3,"file":"MenuBar-Lw_5Jp8u.cjs","sources":["../src/components/MenuBar/MenuItem.jsx","../src/components/MenuBar/MenuBar.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { ICON_MAP, ChevronRightIcon } from '../../icons/index.jsx'\nimport { TOOLTIP_MAP, SHORTCUT_MAP, MODAL_COMMANDS, getShortcutLabel, getCommandActiveState } from '@remyxjs/core'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\n/**\n * Navigate focus between sibling menu items within a menu/submenu.\n * Skips separators and non-focusable elements.\n */\nfunction focusMenuSibling(container, direction) {\n if (!container) return\n const items = Array.from(container.querySelectorAll(':scope > [role=\"menuitem\"], :scope > .rmx-menubar-submenu-wrapper > [role=\"menuitem\"]'))\n const current = document.activeElement\n const idx = items.indexOf(current)\n if (idx === -1) return\n let next\n if (direction === 'down') {\n next = idx < items.length - 1 ? idx + 1 : 0\n } else if (direction === 'up') {\n next = idx > 0 ? idx - 1 : items.length - 1\n } else if (direction === 'home') {\n next = 0\n } else if (direction === 'end') {\n next = items.length - 1\n }\n items[next]?.focus()\n}\n\nfunction MenuItemInner({ item, engine, onOpenModal, onClose }) {\n const selectionState = useSelectionContext()\n\n // Separator\n if (item === '---') {\n return <div className=\"rmx-menubar-separator\" role=\"separator\" />\n }\n\n // Submenu\n if (typeof item === 'object' && item.label && item.items) {\n return (\n <SubMenuItem\n label={item.label}\n items={item.items}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n )\n }\n\n // Regular command item\n const command = typeof item === 'string' ? item : item.command\n const label = TOOLTIP_MAP[command] || command\n const shortcut = getShortcutLabel(command)\n const isActive = getCommandActiveState(command, selectionState, engine)\n const IconComponent = ICON_MAP[command]\n\n const handleClick = (e) => {\n e.preventDefault()\n const modalName = MODAL_COMMANDS[command]\n if (modalName) {\n if (command === 'link') {\n if (selectionState.link) {\n onOpenModal?.('link', selectionState.link)\n } else {\n onOpenModal?.('link', { text: engine.selection.getSelectedText() })\n }\n } else {\n onOpenModal?.(modalName)\n }\n } else {\n engine.executeCommand(command)\n }\n onClose()\n }\n\n const handleKeyDown = (e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n case 'Enter':\n case ' ':\n e.preventDefault()\n handleClick(e)\n break\n }\n }\n\n return (\n <button\n className={`rmx-menubar-item ${isActive ? 'rmx-active' : ''}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\">\n {IconComponent && <IconComponent size={16} />}\n </span>\n <span className=\"rmx-menubar-item-label\">{label}</span>\n {shortcut && <span className=\"rmx-menubar-shortcut\">{shortcut}</span>}\n </button>\n )\n}\n\nexport const MenuItem = React.memo(MenuItemInner)\n\nfunction SubMenuItem({ label, items, engine, onOpenModal, onClose }) {\n const [open, setOpen] = useState(false)\n const ref = useRef(null)\n const timeoutRef = useRef(null)\n\n const handleEnter = () => {\n clearTimeout(timeoutRef.current)\n setOpen(true)\n }\n\n const handleLeave = () => {\n timeoutRef.current = setTimeout(() => setOpen(false), 150)\n }\n\n const handleKeyDown = useCallback((e) => {\n const menu = e.currentTarget.closest('.rmx-menubar-menu')\n switch (e.key) {\n case 'ArrowRight':\n case 'Enter':\n case ' ':\n e.preventDefault()\n setOpen(true)\n // Focus first item in submenu after it renders\n setTimeout(() => {\n const submenu = ref.current?.querySelector('.rmx-menubar-submenu')\n const firstItem = submenu?.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }, 0)\n break\n case 'ArrowDown':\n e.preventDefault()\n focusMenuSibling(menu, 'down')\n break\n case 'ArrowUp':\n e.preventDefault()\n focusMenuSibling(menu, 'up')\n break\n case 'ArrowLeft':\n e.preventDefault()\n setOpen(false)\n break\n case 'Home':\n e.preventDefault()\n focusMenuSibling(menu, 'home')\n break\n case 'End':\n e.preventDefault()\n focusMenuSibling(menu, 'end')\n break\n }\n }, [])\n\n useEffect(() => {\n return () => clearTimeout(timeoutRef.current)\n }, [])\n\n return (\n <div\n className=\"rmx-menubar-submenu-wrapper\"\n ref={ref}\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n >\n <button\n className=\"rmx-menubar-item rmx-menubar-submenu-trigger\"\n onMouseDown={(e) => e.preventDefault()}\n onKeyDown={handleKeyDown}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={open}\n tabIndex={-1}\n >\n <span className=\"rmx-menubar-item-icon\" />\n <span className=\"rmx-menubar-item-label\">{label}</span>\n <span className=\"rmx-menubar-submenu-arrow\"><ChevronRightIcon size={14} /></span>\n </button>\n {open && (\n <div className=\"rmx-menubar-menu rmx-menubar-submenu\" role=\"menu\" aria-label={label}>\n {items.map((subItem, i) => (\n <MenuItem\n key={typeof subItem === 'string' ? `${subItem}-${i}` : subItem.label || i}\n item={subItem}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={onClose}\n />\n ))}\n </div>\n )}\n </div>\n )\n}\n","import React, { useState, useRef, useEffect, useCallback } from 'react'\nimport { MenuItem } from './MenuItem.jsx'\nimport { useSelectionContext } from '../../config/SelectionContext.js'\n\nfunction MenuBarInner({ config, engine, onOpenModal }) {\n const selectionState = useSelectionContext()\n const [openMenu, setOpenMenu] = useState(null)\n const [hoverMode, setHoverMode] = useState(false)\n const barRef = useRef(null)\n const triggerRefs = useRef([])\n\n // Close on click outside or Escape\n useEffect(() => {\n if (openMenu === null) return\n\n const handleClickOutside = (e) => {\n if (barRef.current && !barRef.current.contains(e.target)) {\n setOpenMenu(null)\n setHoverMode(false)\n }\n }\n\n const handleKeyDown = (e) => {\n if (e.key === 'Escape') {\n setOpenMenu(null)\n setHoverMode(false)\n // Return focus to the trigger that opened this menu\n if (openMenu !== null) {\n triggerRefs.current[openMenu]?.focus()\n }\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleKeyDown)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleKeyDown)\n }\n }, [openMenu])\n\n const handleTriggerClick = useCallback((index) => {\n if (openMenu === index) {\n setOpenMenu(null)\n setHoverMode(false)\n } else {\n setOpenMenu(index)\n setHoverMode(true)\n }\n }, [openMenu])\n\n const handleTriggerEnter = useCallback((index) => {\n if (hoverMode && openMenu !== null) {\n setOpenMenu(index)\n }\n }, [hoverMode, openMenu])\n\n const handleCloseMenu = useCallback(() => {\n setOpenMenu(null)\n setHoverMode(false)\n }, [])\n\n const handleBarKeyDown = useCallback((e) => {\n const triggers = triggerRefs.current.filter(Boolean)\n const currentIndex = triggers.indexOf(document.activeElement)\n\n switch (e.key) {\n case 'ArrowRight': {\n e.preventDefault()\n const next = currentIndex < triggers.length - 1 ? currentIndex + 1 : 0\n triggers[next]?.focus()\n if (openMenu !== null) setOpenMenu(next)\n break\n }\n case 'ArrowLeft': {\n e.preventDefault()\n const prev = currentIndex > 0 ? currentIndex - 1 : triggers.length - 1\n triggers[prev]?.focus()\n if (openMenu !== null) setOpenMenu(prev)\n break\n }\n case 'ArrowDown': {\n e.preventDefault()\n if (openMenu === null && currentIndex >= 0) {\n setOpenMenu(currentIndex)\n setHoverMode(true)\n }\n // Focus first item in the open dropdown\n const menuEl = barRef.current?.querySelectorAll('.rmx-menubar-menu')?.[0]\n if (menuEl) {\n const firstItem = menuEl.querySelector('[role=\"menuitem\"]')\n firstItem?.focus()\n }\n break\n }\n case 'Home': {\n e.preventDefault()\n triggers[0]?.focus()\n if (openMenu !== null) setOpenMenu(0)\n break\n }\n case 'End': {\n e.preventDefault()\n triggers[triggers.length - 1]?.focus()\n if (openMenu !== null) setOpenMenu(triggers.length - 1)\n break\n }\n }\n }, [openMenu])\n\n if (!engine || !config) return null\n\n return (\n <div\n className=\"rmx-menubar\"\n ref={barRef}\n role=\"menubar\"\n aria-label=\"Editor menu\"\n onKeyDown={handleBarKeyDown}\n >\n {config.map((menu, index) => (\n <div key={menu.label} className=\"rmx-menubar-dropdown\">\n <button\n ref={(el) => { triggerRefs.current[index] = el }}\n className={`rmx-menubar-trigger ${openMenu === index ? 'rmx-open' : ''}`}\n onClick={(e) => {\n e.preventDefault()\n handleTriggerClick(index)\n }}\n onMouseEnter={() => handleTriggerEnter(index)}\n onMouseDown={(e) => e.preventDefault()}\n type=\"button\"\n role=\"menuitem\"\n aria-haspopup=\"true\"\n aria-expanded={openMenu === index}\n tabIndex={index === 0 ? 0 : -1}\n >\n {menu.label}\n </button>\n {openMenu === index && (\n <div className=\"rmx-menubar-menu\" role=\"menu\" aria-label={menu.label}>\n {menu.items.map((item, i) => (\n <MenuItem\n key={typeof item === 'string' ? `${item}-${i}` : item.label || item.command || i}\n item={item}\n engine={engine}\n onOpenModal={onOpenModal}\n onClose={handleCloseMenu}\n />\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\nexport const MenuBar = React.memo(MenuBarInner)\n\n// Re-export for backward compatibility (actual implementation in separate module\n// to avoid forcing eager load of this component when only the utility is needed)\nexport { collectMenuBarCommands } from './collectMenuBarCommands.js'\n"],"names":["focusMenuSibling","container","direction","items","Array","from","querySelectorAll","current","document","activeElement","idx","indexOf","next","length","focus","MenuItem","React","memo","item","engine","onOpenModal","onClose","selectionState","useSelectionContext","jsx","className","role","label","SubMenuItem","command","TOOLTIP_MAP","shortcut","getShortcutLabel","isActive","getCommandActiveState","IconComponent","ICON_MAP","handleClick","e","preventDefault","modalName","MODAL_COMMANDS","link","text","selection","getSelectedText","executeCommand","jsxs","onClick","onKeyDown","menu","currentTarget","closest","key","onMouseDown","type","tabIndex","children","size","open","setOpen","useState","ref","useRef","timeoutRef","handleKeyDown","useCallback","setTimeout","submenu","querySelector","firstItem","useEffect","clearTimeout","onMouseEnter","onMouseLeave","ChevronRightIcon","map","subItem","i","MenuBar","config","openMenu","setOpenMenu","hoverMode","setHoverMode","barRef","triggerRefs","handleClickOutside","contains","target","addEventListener","removeEventListener","handleTriggerClick","index","handleTriggerEnter","handleCloseMenu","handleBarKeyDown","triggers","filter","Boolean","currentIndex","prev","menuEl","el"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";const e=require("react/jsx-runtime"),r=require("react"),t=require("./index-Dc63uIP0.cjs"),n='a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';const l=r.memo((function({title:l,open:o,onClose:s,children:c,width:u=420}){const a=r.useRef(null),i=r.useRef(null),d=r.useRef([]);r.useEffect((()=>{o&&(i.current=document.activeElement)}),[o]),r.useEffect((()=>{if(!o&&i.current){const e=i.current;i.current=null,requestAnimationFrame((()=>{e&&"function"==typeof e.focus&&e.focus()}))}}),[o]),r.useEffect((()=>{if(o&&a.current){const e=a.current.querySelector("input, textarea, select")||a.current.querySelector(n);e&&e.focus()}}),[o]),r.useEffect((()=>{o&&a.current&&(d.current=Array.from(a.current.querySelectorAll(n)))}),[o]);const m=r.useCallback((e=>{if("Escape"!==e.key){if("Tab"===e.key&&a.current){const r=d.current.length>0?d.current:Array.from(a.current.querySelectorAll(n));if(0===r.length)return void e.preventDefault();const t=r[0],l=r[r.length-1];e.shiftKey?document.activeElement===t&&(e.preventDefault(),l.focus()):document.activeElement===l&&(e.preventDefault(),t.focus())}}else s()}),[s]);return o?e.jsx("div",{className:"rmx-modal-overlay",onClick:s,onKeyDown:m,children:e.jsxs("div",{ref:a,className:"rmx-modal",style:{maxWidth:u},onClick:e=>e.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":l,children:[e.jsxs("div",{className:"rmx-modal-header",children:[e.jsx("h3",{className:"rmx-modal-title",children:l}),e.jsx("button",{className:"rmx-modal-close",onClick:s,type:"button","aria-label":"Close",children:e.jsx(t.CloseIcon,{size:18})})]}),e.jsx("div",{className:"rmx-modal-body",children:c})]})}):null}));l.propTypes={title:t.PropTypes.string.isRequired,open:t.PropTypes.bool.isRequired,onClose:t.PropTypes.func.isRequired,children:t.PropTypes.node,width:t.PropTypes.number},exports.ModalOverlay=l;
2
- //# sourceMappingURL=ModalOverlay-BDsGgv3_.cjs.map
1
+ "use strict";const e=require("react/jsx-runtime"),r=require("react"),t=require("./index-qh1Yzh-l.cjs"),n='a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';const l=r.memo((function({title:l,open:o,onClose:s,children:c,width:u=420}){const a=r.useRef(null),i=r.useRef(null),d=r.useRef([]);r.useEffect((()=>{o&&(i.current=document.activeElement)}),[o]),r.useEffect((()=>{if(!o&&i.current){const e=i.current;i.current=null,requestAnimationFrame((()=>{e&&"function"==typeof e.focus&&e.focus()}))}}),[o]),r.useEffect((()=>{if(o&&a.current){const e=a.current.querySelector("input, textarea, select")||a.current.querySelector(n);e&&e.focus()}}),[o]),r.useEffect((()=>{o&&a.current&&(d.current=Array.from(a.current.querySelectorAll(n)))}),[o]);const m=r.useCallback((e=>{if("Escape"!==e.key){if("Tab"===e.key&&a.current){const r=d.current.length>0?d.current:Array.from(a.current.querySelectorAll(n));if(0===r.length)return void e.preventDefault();const t=r[0],l=r[r.length-1];e.shiftKey?document.activeElement===t&&(e.preventDefault(),l.focus()):document.activeElement===l&&(e.preventDefault(),t.focus())}}else s()}),[s]);return o?e.jsx("div",{className:"rmx-modal-overlay",onClick:s,onKeyDown:m,children:e.jsxs("div",{ref:a,className:"rmx-modal",style:{maxWidth:u},onClick:e=>e.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":l,children:[e.jsxs("div",{className:"rmx-modal-header",children:[e.jsx("h3",{className:"rmx-modal-title",children:l}),e.jsx("button",{className:"rmx-modal-close",onClick:s,type:"button","aria-label":"Close",children:e.jsx(t.CloseIcon,{size:18})})]}),e.jsx("div",{className:"rmx-modal-body",children:c})]})}):null}));l.propTypes={title:t.PropTypes.string.isRequired,open:t.PropTypes.bool.isRequired,onClose:t.PropTypes.func.isRequired,children:t.PropTypes.node,width:t.PropTypes.number},exports.ModalOverlay=l;
2
+ //# sourceMappingURL=ModalOverlay-Dh5quv7X.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModalOverlay-BDsGgv3_.cjs","sources":["../src/components/Modals/ModalOverlay.jsx"],"sourcesContent":["import React, { useEffect, useRef, useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { CloseIcon } from '../../icons/index.jsx'\n\nconst FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction ModalOverlayInner({ title, open, onClose, children, width = 420 }) {\n const ref = useRef(null)\n const previousFocusRef = useRef(null)\n const focusableRef = useRef([])\n\n // Save previously focused element when opening\n useEffect(() => {\n if (open) {\n previousFocusRef.current = document.activeElement\n }\n }, [open])\n\n // Restore focus to previously focused element on close\n useEffect(() => {\n if (!open && previousFocusRef.current) {\n const el = previousFocusRef.current\n previousFocusRef.current = null\n // Delay to allow DOM to settle after modal unmount\n requestAnimationFrame(() => {\n if (el && typeof el.focus === 'function') el.focus()\n })\n }\n }, [open])\n\n // Focus the first focusable element on open\n useEffect(() => {\n if (open && ref.current) {\n // Prefer input/textarea/select, fall back to any focusable element\n const firstInput = ref.current.querySelector('input, textarea, select')\n const firstFocusable = firstInput || ref.current.querySelector(FOCUSABLE_SELECTOR)\n if (firstFocusable) firstFocusable.focus()\n }\n }, [open])\n\n // Cache focusable elements when modal opens or content changes\n useEffect(() => {\n if (open && ref.current) {\n focusableRef.current = Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n }\n }, [open])\n\n // Handle Escape and focus trapping (Tab / Shift+Tab)\n const handleKeyDown = useCallback((e) => {\n if (e.key === 'Escape') {\n onClose()\n return\n }\n\n if (e.key === 'Tab' && ref.current) {\n const focusable = focusableRef.current.length > 0 ? focusableRef.current : Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n if (focusable.length === 0) {\n e.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (e.shiftKey) {\n // Shift+Tab: if focus is on first element, wrap to last\n if (document.activeElement === first) {\n e.preventDefault()\n last.focus()\n }\n } else {\n // Tab: if focus is on last element, wrap to first\n if (document.activeElement === last) {\n e.preventDefault()\n first.focus()\n }\n }\n }\n }, [onClose])\n\n if (!open) return null\n\n return (\n <div className=\"rmx-modal-overlay\" onClick={onClose} onKeyDown={handleKeyDown}>\n <div\n ref={ref}\n className=\"rmx-modal\"\n style={{ maxWidth: width }}\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"rmx-modal-header\">\n <h3 className=\"rmx-modal-title\">{title}</h3>\n <button className=\"rmx-modal-close\" onClick={onClose} type=\"button\" aria-label=\"Close\">\n <CloseIcon size={18} />\n </button>\n </div>\n <div className=\"rmx-modal-body\">\n {children}\n </div>\n </div>\n </div>\n )\n}\n\nexport const ModalOverlay = React.memo(ModalOverlayInner)\n\nModalOverlay.propTypes = {\n title: PropTypes.string.isRequired,\n open: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n children: PropTypes.node,\n width: PropTypes.number,\n}\n"],"names":["FOCUSABLE_SELECTOR","ModalOverlay","React","memo","title","open","onClose","children","width","ref","useRef","previousFocusRef","focusableRef","useEffect","current","document","activeElement","el","requestAnimationFrame","focus","firstFocusable","querySelector","Array","from","querySelectorAll","handleKeyDown","useCallback","e","key","focusable","length","preventDefault","first","last","shiftKey","className","onClick","onKeyDown","jsxs","style","maxWidth","stopPropagation","role","jsx","type","CloseIcon","size","propTypes","PropTypes","string","isRequired","bool","func","node","number"],"mappings":"uGAIMA,EAAqB,4HAuGpB,MAAMC,EAAeC,EAAMC,MArGlC,UAA2BC,MAAEA,EAAAC,KAAOA,EAAAC,QAAMA,WAASC,EAAAC,MAAUA,EAAQ,MACnE,MAAMC,EAAMC,EAAAA,OAAO,MACbC,EAAmBD,EAAAA,OAAO,MAC1BE,EAAeF,EAAAA,OAAO,IAG5BG,EAAAA,WAAU,KACJR,IACFM,EAAiBG,QAAUC,SAASC,cACtC,GACC,CAACX,IAGJQ,EAAAA,WAAU,KACR,IAAKR,GAAQM,EAAiBG,QAAS,CACrC,MAAMG,EAAKN,EAAiBG,QAC5BH,EAAiBG,QAAU,KAE3BI,uBAAsB,KAChBD,GAA0B,mBAAbA,EAAGE,SAAyBA,OAAA,GAEjD,IACC,CAACd,IAGJQ,EAAAA,WAAU,KACR,GAAIR,GAAQI,EAAIK,QAAS,CAEvB,MACMM,EADaX,EAAIK,QAAQO,cAAc,4BACRZ,EAAIK,QAAQO,cAAcrB,GAC3DoB,KAA+BD,OACrC,IACC,CAACd,IAGJQ,EAAAA,WAAU,KACJR,GAAQI,EAAIK,UACdF,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACjE,GACC,CAACK,IAGJ,MAAMoB,EAAgBC,eAAaC,IACjC,GAAc,WAAVA,EAAEC,KAKN,GAAc,QAAVD,EAAEC,KAAiBnB,EAAIK,QAAS,CAClC,MAAMe,EAAYjB,EAAaE,QAAQgB,OAAS,EAAIlB,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACnH,GAAyB,IAArB6B,EAAUC,OAEZ,YADAH,EAAEI,iBAIJ,MAAMC,EAAQH,EAAU,GAClBI,EAAOJ,EAAUA,EAAUC,OAAS,GAEtCH,EAAEO,SAEAnB,SAASC,gBAAkBgB,IAC7BL,EAAEI,iBACFE,EAAKd,SAIHJ,SAASC,gBAAkBiB,IAC7BN,EAAEI,iBACFC,EAAMb,QAGZ,OA3BEb,GA2BF,GACC,CAACA,IAEJ,OAAKD,QAGF,MAAA,CAAI8B,UAAU,oBAAoBC,QAAS9B,EAAS+B,UAAWZ,EAC9DlB,SAAA+B,EAAAA,KAAC,MAAA,CACC7B,MACA0B,UAAU,YACVI,MAAO,CAAEC,SAAUhC,GACnB4B,QAAUT,GAAMA,EAAEc,kBAClBC,KAAK,SACL,aAAW,OACX,aAAYtC,EAEZG,SAAA,GAAA+B,KAAC,MAAA,CAAIH,UAAU,mBACb5B,SAAA,CAAAoC,EAAAA,IAAC,KAAA,CAAGR,UAAU,kBAAmB5B,SAAAH,IACjCuC,EAAAA,IAAC,SAAA,CAAOR,UAAU,kBAAkBC,QAAS9B,EAASsC,KAAK,SAAS,aAAW,QAC7ErC,SAAAoC,EAAAA,IAACE,EAAAA,UAAA,CAAUC,KAAM,YAGrBH,IAAC,MAAA,CAAIR,UAAU,iBACZ5B,kBApBS,IAyBpB,IAIAN,EAAa8C,UAAY,CACvB3C,MAAO4C,EAAAA,UAAUC,OAAOC,WACxB7C,KAAM2C,EAAAA,UAAUG,KAAKD,WACrB5C,QAAS0C,EAAAA,UAAUI,KAAKF,WACxB3C,SAAUyC,EAAAA,UAAUK,KACpB7C,MAAOwC,EAAAA,UAAUM"}
1
+ {"version":3,"file":"ModalOverlay-Dh5quv7X.cjs","sources":["../src/components/Modals/ModalOverlay.jsx"],"sourcesContent":["import React, { useEffect, useRef, useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { CloseIcon } from '../../icons/index.jsx'\n\nconst FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction ModalOverlayInner({ title, open, onClose, children, width = 420 }) {\n const ref = useRef(null)\n const previousFocusRef = useRef(null)\n const focusableRef = useRef([])\n\n // Save previously focused element when opening\n useEffect(() => {\n if (open) {\n previousFocusRef.current = document.activeElement\n }\n }, [open])\n\n // Restore focus to previously focused element on close\n useEffect(() => {\n if (!open && previousFocusRef.current) {\n const el = previousFocusRef.current\n previousFocusRef.current = null\n // Delay to allow DOM to settle after modal unmount\n requestAnimationFrame(() => {\n if (el && typeof el.focus === 'function') el.focus()\n })\n }\n }, [open])\n\n // Focus the first focusable element on open\n useEffect(() => {\n if (open && ref.current) {\n // Prefer input/textarea/select, fall back to any focusable element\n const firstInput = ref.current.querySelector('input, textarea, select')\n const firstFocusable = firstInput || ref.current.querySelector(FOCUSABLE_SELECTOR)\n if (firstFocusable) firstFocusable.focus()\n }\n }, [open])\n\n // Cache focusable elements when modal opens or content changes\n useEffect(() => {\n if (open && ref.current) {\n focusableRef.current = Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n }\n }, [open])\n\n // Handle Escape and focus trapping (Tab / Shift+Tab)\n const handleKeyDown = useCallback((e) => {\n if (e.key === 'Escape') {\n onClose()\n return\n }\n\n if (e.key === 'Tab' && ref.current) {\n const focusable = focusableRef.current.length > 0 ? focusableRef.current : Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n if (focusable.length === 0) {\n e.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (e.shiftKey) {\n // Shift+Tab: if focus is on first element, wrap to last\n if (document.activeElement === first) {\n e.preventDefault()\n last.focus()\n }\n } else {\n // Tab: if focus is on last element, wrap to first\n if (document.activeElement === last) {\n e.preventDefault()\n first.focus()\n }\n }\n }\n }, [onClose])\n\n if (!open) return null\n\n return (\n <div className=\"rmx-modal-overlay\" onClick={onClose} onKeyDown={handleKeyDown}>\n <div\n ref={ref}\n className=\"rmx-modal\"\n style={{ maxWidth: width }}\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"rmx-modal-header\">\n <h3 className=\"rmx-modal-title\">{title}</h3>\n <button className=\"rmx-modal-close\" onClick={onClose} type=\"button\" aria-label=\"Close\">\n <CloseIcon size={18} />\n </button>\n </div>\n <div className=\"rmx-modal-body\">\n {children}\n </div>\n </div>\n </div>\n )\n}\n\nexport const ModalOverlay = React.memo(ModalOverlayInner)\n\nModalOverlay.propTypes = {\n title: PropTypes.string.isRequired,\n open: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n children: PropTypes.node,\n width: PropTypes.number,\n}\n"],"names":["FOCUSABLE_SELECTOR","ModalOverlay","React","memo","title","open","onClose","children","width","ref","useRef","previousFocusRef","focusableRef","useEffect","current","document","activeElement","el","requestAnimationFrame","focus","firstFocusable","querySelector","Array","from","querySelectorAll","handleKeyDown","useCallback","e","key","focusable","length","preventDefault","first","last","shiftKey","className","onClick","onKeyDown","jsxs","style","maxWidth","stopPropagation","role","jsx","type","CloseIcon","size","propTypes","PropTypes","string","isRequired","bool","func","node","number"],"mappings":"uGAIMA,EAAqB,4HAuGpB,MAAMC,EAAeC,EAAMC,MArGlC,UAA2BC,MAAEA,EAAAC,KAAOA,EAAAC,QAAMA,WAASC,EAAAC,MAAUA,EAAQ,MACnE,MAAMC,EAAMC,EAAAA,OAAO,MACbC,EAAmBD,EAAAA,OAAO,MAC1BE,EAAeF,EAAAA,OAAO,IAG5BG,EAAAA,WAAU,KACJR,IACFM,EAAiBG,QAAUC,SAASC,cACtC,GACC,CAACX,IAGJQ,EAAAA,WAAU,KACR,IAAKR,GAAQM,EAAiBG,QAAS,CACrC,MAAMG,EAAKN,EAAiBG,QAC5BH,EAAiBG,QAAU,KAE3BI,uBAAsB,KAChBD,GAA0B,mBAAbA,EAAGE,SAAyBA,OAAA,GAEjD,IACC,CAACd,IAGJQ,EAAAA,WAAU,KACR,GAAIR,GAAQI,EAAIK,QAAS,CAEvB,MACMM,EADaX,EAAIK,QAAQO,cAAc,4BACRZ,EAAIK,QAAQO,cAAcrB,GAC3DoB,KAA+BD,OACrC,IACC,CAACd,IAGJQ,EAAAA,WAAU,KACJR,GAAQI,EAAIK,UACdF,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACjE,GACC,CAACK,IAGJ,MAAMoB,EAAgBC,eAAaC,IACjC,GAAc,WAAVA,EAAEC,KAKN,GAAc,QAAVD,EAAEC,KAAiBnB,EAAIK,QAAS,CAClC,MAAMe,EAAYjB,EAAaE,QAAQgB,OAAS,EAAIlB,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACnH,GAAyB,IAArB6B,EAAUC,OAEZ,YADAH,EAAEI,iBAIJ,MAAMC,EAAQH,EAAU,GAClBI,EAAOJ,EAAUA,EAAUC,OAAS,GAEtCH,EAAEO,SAEAnB,SAASC,gBAAkBgB,IAC7BL,EAAEI,iBACFE,EAAKd,SAIHJ,SAASC,gBAAkBiB,IAC7BN,EAAEI,iBACFC,EAAMb,QAGZ,OA3BEb,GA2BF,GACC,CAACA,IAEJ,OAAKD,QAGF,MAAA,CAAI8B,UAAU,oBAAoBC,QAAS9B,EAAS+B,UAAWZ,EAC9DlB,SAAA+B,EAAAA,KAAC,MAAA,CACC7B,MACA0B,UAAU,YACVI,MAAO,CAAEC,SAAUhC,GACnB4B,QAAUT,GAAMA,EAAEc,kBAClBC,KAAK,SACL,aAAW,OACX,aAAYtC,EAEZG,SAAA,GAAA+B,KAAC,MAAA,CAAIH,UAAU,mBACb5B,SAAA,CAAAoC,EAAAA,IAAC,KAAA,CAAGR,UAAU,kBAAmB5B,SAAAH,IACjCuC,EAAAA,IAAC,SAAA,CAAOR,UAAU,kBAAkBC,QAAS9B,EAASsC,KAAK,SAAS,aAAW,QAC7ErC,SAAAoC,EAAAA,IAACE,EAAAA,UAAA,CAAUC,KAAM,YAGrBH,IAAC,MAAA,CAAIR,UAAU,iBACZ5B,kBApBS,IAyBpB,IAIAN,EAAa8C,UAAY,CACvB3C,MAAO4C,EAAAA,UAAUC,OAAOC,WACxB7C,KAAM2C,EAAAA,UAAUG,KAAKD,WACrB5C,QAAS0C,EAAAA,UAAUI,KAAKF,WACxB3C,SAAUyC,EAAAA,UAAUK,KACpB7C,MAAOwC,EAAAA,UAAUM"}
@@ -1,6 +1,6 @@
1
- import{jsx as e,jsxs as t}from"react/jsx-runtime";import r,{useRef as n,useEffect as o,useCallback as l}from"react";import{a as c,P as a}from"./index-C720tbJA.js";const i='a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';const s=r.memo((function({title:r,open:a,onClose:s,children:u,width:d=420}){const m=n(null),f=n(null),p=n([]);o((()=>{a&&(f.current=document.activeElement)}),[a]),o((()=>{if(!a&&f.current){const e=f.current;f.current=null,requestAnimationFrame((()=>{e&&"function"==typeof e.focus&&e.focus()}))}}),[a]),o((()=>{if(a&&m.current){const e=m.current.querySelector("input, textarea, select")||m.current.querySelector(i);e&&e.focus()}}),[a]),o((()=>{a&&m.current&&(p.current=Array.from(m.current.querySelectorAll(i)))}),[a]);const h=l((e=>{if("Escape"!==e.key){if("Tab"===e.key&&m.current){const t=p.current.length>0?p.current:Array.from(m.current.querySelectorAll(i));if(0===t.length)return void e.preventDefault();const r=t[0],n=t[t.length-1];e.shiftKey?document.activeElement===r&&(e.preventDefault(),n.focus()):document.activeElement===n&&(e.preventDefault(),r.focus())}}else s()}),[s]);return a?/* @__PURE__ */e("div",{className:"rmx-modal-overlay",onClick:s,onKeyDown:h,children:/* @__PURE__ */t("div",{ref:m,className:"rmx-modal",style:{maxWidth:d},onClick:e=>e.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":r,children:[
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import r,{useRef as n,useEffect as o,useCallback as l}from"react";import{a as c,P as a}from"./index-DL-qBZZU.js";const i='a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';const s=r.memo((function({title:r,open:a,onClose:s,children:u,width:d=420}){const m=n(null),f=n(null),p=n([]);o((()=>{a&&(f.current=document.activeElement)}),[a]),o((()=>{if(!a&&f.current){const e=f.current;f.current=null,requestAnimationFrame((()=>{e&&"function"==typeof e.focus&&e.focus()}))}}),[a]),o((()=>{if(a&&m.current){const e=m.current.querySelector("input, textarea, select")||m.current.querySelector(i);e&&e.focus()}}),[a]),o((()=>{a&&m.current&&(p.current=Array.from(m.current.querySelectorAll(i)))}),[a]);const h=l((e=>{if("Escape"!==e.key){if("Tab"===e.key&&m.current){const t=p.current.length>0?p.current:Array.from(m.current.querySelectorAll(i));if(0===t.length)return void e.preventDefault();const r=t[0],n=t[t.length-1];e.shiftKey?document.activeElement===r&&(e.preventDefault(),n.focus()):document.activeElement===n&&(e.preventDefault(),r.focus())}}else s()}),[s]);return a?/* @__PURE__ */e("div",{className:"rmx-modal-overlay",onClick:s,onKeyDown:h,children:/* @__PURE__ */t("div",{ref:m,className:"rmx-modal",style:{maxWidth:d},onClick:e=>e.stopPropagation(),role:"dialog","aria-modal":"true","aria-label":r,children:[
2
2
  /* @__PURE__ */t("div",{className:"rmx-modal-header",children:[
3
3
  /* @__PURE__ */e("h3",{className:"rmx-modal-title",children:r}),
4
4
  /* @__PURE__ */e("button",{className:"rmx-modal-close",onClick:s,type:"button","aria-label":"Close",children:/* @__PURE__ */e(c,{size:18})})]}),
5
5
  /* @__PURE__ */e("div",{className:"rmx-modal-body",children:u})]})}):null}));s.propTypes={title:a.string.isRequired,open:a.bool.isRequired,onClose:a.func.isRequired,children:a.node,width:a.number};export{s as M};
6
- //# sourceMappingURL=ModalOverlay-CLvRNHmp.js.map
6
+ //# sourceMappingURL=ModalOverlay-Dt0JiW3M.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModalOverlay-CLvRNHmp.js","sources":["../src/components/Modals/ModalOverlay.jsx"],"sourcesContent":["import React, { useEffect, useRef, useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { CloseIcon } from '../../icons/index.jsx'\n\nconst FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction ModalOverlayInner({ title, open, onClose, children, width = 420 }) {\n const ref = useRef(null)\n const previousFocusRef = useRef(null)\n const focusableRef = useRef([])\n\n // Save previously focused element when opening\n useEffect(() => {\n if (open) {\n previousFocusRef.current = document.activeElement\n }\n }, [open])\n\n // Restore focus to previously focused element on close\n useEffect(() => {\n if (!open && previousFocusRef.current) {\n const el = previousFocusRef.current\n previousFocusRef.current = null\n // Delay to allow DOM to settle after modal unmount\n requestAnimationFrame(() => {\n if (el && typeof el.focus === 'function') el.focus()\n })\n }\n }, [open])\n\n // Focus the first focusable element on open\n useEffect(() => {\n if (open && ref.current) {\n // Prefer input/textarea/select, fall back to any focusable element\n const firstInput = ref.current.querySelector('input, textarea, select')\n const firstFocusable = firstInput || ref.current.querySelector(FOCUSABLE_SELECTOR)\n if (firstFocusable) firstFocusable.focus()\n }\n }, [open])\n\n // Cache focusable elements when modal opens or content changes\n useEffect(() => {\n if (open && ref.current) {\n focusableRef.current = Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n }\n }, [open])\n\n // Handle Escape and focus trapping (Tab / Shift+Tab)\n const handleKeyDown = useCallback((e) => {\n if (e.key === 'Escape') {\n onClose()\n return\n }\n\n if (e.key === 'Tab' && ref.current) {\n const focusable = focusableRef.current.length > 0 ? focusableRef.current : Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n if (focusable.length === 0) {\n e.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (e.shiftKey) {\n // Shift+Tab: if focus is on first element, wrap to last\n if (document.activeElement === first) {\n e.preventDefault()\n last.focus()\n }\n } else {\n // Tab: if focus is on last element, wrap to first\n if (document.activeElement === last) {\n e.preventDefault()\n first.focus()\n }\n }\n }\n }, [onClose])\n\n if (!open) return null\n\n return (\n <div className=\"rmx-modal-overlay\" onClick={onClose} onKeyDown={handleKeyDown}>\n <div\n ref={ref}\n className=\"rmx-modal\"\n style={{ maxWidth: width }}\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"rmx-modal-header\">\n <h3 className=\"rmx-modal-title\">{title}</h3>\n <button className=\"rmx-modal-close\" onClick={onClose} type=\"button\" aria-label=\"Close\">\n <CloseIcon size={18} />\n </button>\n </div>\n <div className=\"rmx-modal-body\">\n {children}\n </div>\n </div>\n </div>\n )\n}\n\nexport const ModalOverlay = React.memo(ModalOverlayInner)\n\nModalOverlay.propTypes = {\n title: PropTypes.string.isRequired,\n open: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n children: PropTypes.node,\n width: PropTypes.number,\n}\n"],"names":["FOCUSABLE_SELECTOR","ModalOverlay","React","memo","title","open","onClose","children","width","ref","useRef","previousFocusRef","focusableRef","useEffect","current","document","activeElement","el","requestAnimationFrame","focus","firstFocusable","querySelector","Array","from","querySelectorAll","handleKeyDown","useCallback","e","key","focusable","length","preventDefault","first","last","shiftKey","className","onClick","onKeyDown","jsxs","style","maxWidth","stopPropagation","role","type","CloseIcon","size","propTypes","PropTypes","string","isRequired","bool","func","node","number"],"mappings":"mKAIA,MAAMA,EAAqB,4HAuGpB,MAAMC,EAAeC,EAAMC,MArGlC,UAA2BC,MAAEA,EAAAC,KAAOA,EAAAC,QAAMA,WAASC,EAAAC,MAAUA,EAAQ,MACnE,MAAMC,EAAMC,EAAO,MACbC,EAAmBD,EAAO,MAC1BE,EAAeF,EAAO,IAG5BG,GAAU,KACJR,IACFM,EAAiBG,QAAUC,SAASC,cACtC,GACC,CAACX,IAGJQ,GAAU,KACR,IAAKR,GAAQM,EAAiBG,QAAS,CACrC,MAAMG,EAAKN,EAAiBG,QAC5BH,EAAiBG,QAAU,KAE3BI,uBAAsB,KAChBD,GAA0B,mBAAbA,EAAGE,SAAyBA,OAAA,GAEjD,IACC,CAACd,IAGJQ,GAAU,KACR,GAAIR,GAAQI,EAAIK,QAAS,CAEvB,MACMM,EADaX,EAAIK,QAAQO,cAAc,4BACRZ,EAAIK,QAAQO,cAAcrB,GAC3DoB,KAA+BD,OACrC,IACC,CAACd,IAGJQ,GAAU,KACJR,GAAQI,EAAIK,UACdF,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACjE,GACC,CAACK,IAGJ,MAAMoB,EAAgBC,GAAaC,IACjC,GAAc,WAAVA,EAAEC,KAKN,GAAc,QAAVD,EAAEC,KAAiBnB,EAAIK,QAAS,CAClC,MAAMe,EAAYjB,EAAaE,QAAQgB,OAAS,EAAIlB,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACnH,GAAyB,IAArB6B,EAAUC,OAEZ,YADAH,EAAEI,iBAIJ,MAAMC,EAAQH,EAAU,GAClBI,EAAOJ,EAAUA,EAAUC,OAAS,GAEtCH,EAAEO,SAEAnB,SAASC,gBAAkBgB,IAC7BL,EAAEI,iBACFE,EAAKd,SAIHJ,SAASC,gBAAkBiB,IAC7BN,EAAEI,iBACFC,EAAMb,QAGZ,OA3BEb,GA2BF,GACC,CAACA,IAEJ,OAAKD,mBAGF,MAAA,CAAI8B,UAAU,oBAAoBC,QAAS9B,EAAS+B,UAAWZ,EAC9DlB,wBAAA+B,EAAC,MAAA,CACC7B,MACA0B,UAAU,YACVI,MAAO,CAAEC,SAAUhC,GACnB4B,QAAUT,GAAMA,EAAEc,kBAClBC,KAAK,SACL,aAAW,OACX,aAAYtC,EAEZG,SAAA;eAAA+B,EAAC,MAAA,CAAIH,UAAU,mBACb5B,SAAA;iBAAC,KAAA,CAAG4B,UAAU,kBAAmB5B,SAAAH;iBAChC,SAAA,CAAO+B,UAAU,kBAAkBC,QAAS9B,EAASqC,KAAK,SAAS,aAAW,QAC7EpC,0BAACqC,EAAA,CAAUC,KAAM;iBAGpB,MAAA,CAAIV,UAAU,iBACZ5B,kBApBS,IAyBpB,IAIAN,EAAa6C,UAAY,CACvB1C,MAAO2C,EAAUC,OAAOC,WACxB5C,KAAM0C,EAAUG,KAAKD,WACrB3C,QAASyC,EAAUI,KAAKF,WACxB1C,SAAUwC,EAAUK,KACpB5C,MAAOuC,EAAUM"}
1
+ {"version":3,"file":"ModalOverlay-Dt0JiW3M.js","sources":["../src/components/Modals/ModalOverlay.jsx"],"sourcesContent":["import React, { useEffect, useRef, useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { CloseIcon } from '../../icons/index.jsx'\n\nconst FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea, input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n\nfunction ModalOverlayInner({ title, open, onClose, children, width = 420 }) {\n const ref = useRef(null)\n const previousFocusRef = useRef(null)\n const focusableRef = useRef([])\n\n // Save previously focused element when opening\n useEffect(() => {\n if (open) {\n previousFocusRef.current = document.activeElement\n }\n }, [open])\n\n // Restore focus to previously focused element on close\n useEffect(() => {\n if (!open && previousFocusRef.current) {\n const el = previousFocusRef.current\n previousFocusRef.current = null\n // Delay to allow DOM to settle after modal unmount\n requestAnimationFrame(() => {\n if (el && typeof el.focus === 'function') el.focus()\n })\n }\n }, [open])\n\n // Focus the first focusable element on open\n useEffect(() => {\n if (open && ref.current) {\n // Prefer input/textarea/select, fall back to any focusable element\n const firstInput = ref.current.querySelector('input, textarea, select')\n const firstFocusable = firstInput || ref.current.querySelector(FOCUSABLE_SELECTOR)\n if (firstFocusable) firstFocusable.focus()\n }\n }, [open])\n\n // Cache focusable elements when modal opens or content changes\n useEffect(() => {\n if (open && ref.current) {\n focusableRef.current = Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n }\n }, [open])\n\n // Handle Escape and focus trapping (Tab / Shift+Tab)\n const handleKeyDown = useCallback((e) => {\n if (e.key === 'Escape') {\n onClose()\n return\n }\n\n if (e.key === 'Tab' && ref.current) {\n const focusable = focusableRef.current.length > 0 ? focusableRef.current : Array.from(ref.current.querySelectorAll(FOCUSABLE_SELECTOR))\n if (focusable.length === 0) {\n e.preventDefault()\n return\n }\n\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n\n if (e.shiftKey) {\n // Shift+Tab: if focus is on first element, wrap to last\n if (document.activeElement === first) {\n e.preventDefault()\n last.focus()\n }\n } else {\n // Tab: if focus is on last element, wrap to first\n if (document.activeElement === last) {\n e.preventDefault()\n first.focus()\n }\n }\n }\n }, [onClose])\n\n if (!open) return null\n\n return (\n <div className=\"rmx-modal-overlay\" onClick={onClose} onKeyDown={handleKeyDown}>\n <div\n ref={ref}\n className=\"rmx-modal\"\n style={{ maxWidth: width }}\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"rmx-modal-header\">\n <h3 className=\"rmx-modal-title\">{title}</h3>\n <button className=\"rmx-modal-close\" onClick={onClose} type=\"button\" aria-label=\"Close\">\n <CloseIcon size={18} />\n </button>\n </div>\n <div className=\"rmx-modal-body\">\n {children}\n </div>\n </div>\n </div>\n )\n}\n\nexport const ModalOverlay = React.memo(ModalOverlayInner)\n\nModalOverlay.propTypes = {\n title: PropTypes.string.isRequired,\n open: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n children: PropTypes.node,\n width: PropTypes.number,\n}\n"],"names":["FOCUSABLE_SELECTOR","ModalOverlay","React","memo","title","open","onClose","children","width","ref","useRef","previousFocusRef","focusableRef","useEffect","current","document","activeElement","el","requestAnimationFrame","focus","firstFocusable","querySelector","Array","from","querySelectorAll","handleKeyDown","useCallback","e","key","focusable","length","preventDefault","first","last","shiftKey","className","onClick","onKeyDown","jsxs","style","maxWidth","stopPropagation","role","type","CloseIcon","size","propTypes","PropTypes","string","isRequired","bool","func","node","number"],"mappings":"mKAIA,MAAMA,EAAqB,4HAuGpB,MAAMC,EAAeC,EAAMC,MArGlC,UAA2BC,MAAEA,EAAAC,KAAOA,EAAAC,QAAMA,WAASC,EAAAC,MAAUA,EAAQ,MACnE,MAAMC,EAAMC,EAAO,MACbC,EAAmBD,EAAO,MAC1BE,EAAeF,EAAO,IAG5BG,GAAU,KACJR,IACFM,EAAiBG,QAAUC,SAASC,cACtC,GACC,CAACX,IAGJQ,GAAU,KACR,IAAKR,GAAQM,EAAiBG,QAAS,CACrC,MAAMG,EAAKN,EAAiBG,QAC5BH,EAAiBG,QAAU,KAE3BI,uBAAsB,KAChBD,GAA0B,mBAAbA,EAAGE,SAAyBA,OAAA,GAEjD,IACC,CAACd,IAGJQ,GAAU,KACR,GAAIR,GAAQI,EAAIK,QAAS,CAEvB,MACMM,EADaX,EAAIK,QAAQO,cAAc,4BACRZ,EAAIK,QAAQO,cAAcrB,GAC3DoB,KAA+BD,OACrC,IACC,CAACd,IAGJQ,GAAU,KACJR,GAAQI,EAAIK,UACdF,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACjE,GACC,CAACK,IAGJ,MAAMoB,EAAgBC,GAAaC,IACjC,GAAc,WAAVA,EAAEC,KAKN,GAAc,QAAVD,EAAEC,KAAiBnB,EAAIK,QAAS,CAClC,MAAMe,EAAYjB,EAAaE,QAAQgB,OAAS,EAAIlB,EAAaE,QAAUQ,MAAMC,KAAKd,EAAIK,QAAQU,iBAAiBxB,IACnH,GAAyB,IAArB6B,EAAUC,OAEZ,YADAH,EAAEI,iBAIJ,MAAMC,EAAQH,EAAU,GAClBI,EAAOJ,EAAUA,EAAUC,OAAS,GAEtCH,EAAEO,SAEAnB,SAASC,gBAAkBgB,IAC7BL,EAAEI,iBACFE,EAAKd,SAIHJ,SAASC,gBAAkBiB,IAC7BN,EAAEI,iBACFC,EAAMb,QAGZ,OA3BEb,GA2BF,GACC,CAACA,IAEJ,OAAKD,mBAGF,MAAA,CAAI8B,UAAU,oBAAoBC,QAAS9B,EAAS+B,UAAWZ,EAC9DlB,wBAAA+B,EAAC,MAAA,CACC7B,MACA0B,UAAU,YACVI,MAAO,CAAEC,SAAUhC,GACnB4B,QAAUT,GAAMA,EAAEc,kBAClBC,KAAK,SACL,aAAW,OACX,aAAYtC,EAEZG,SAAA;eAAA+B,EAAC,MAAA,CAAIH,UAAU,mBACb5B,SAAA;iBAAC,KAAA,CAAG4B,UAAU,kBAAmB5B,SAAAH;iBAChC,SAAA,CAAO+B,UAAU,kBAAkBC,QAAS9B,EAASqC,KAAK,SAAS,aAAW,QAC7EpC,0BAACqC,EAAA,CAAUC,KAAM;iBAGpB,MAAA,CAAIV,UAAU,iBACZ5B,kBApBS,IAyBpB,IAIAN,EAAa6C,UAAY,CACvB1C,MAAO2C,EAAUC,OAAOC,WACxB5C,KAAM0C,EAAUG,KAAKD,WACrB3C,QAASyC,EAAUI,KAAKF,WACxB1C,SAAUwC,EAAUK,KACpB5C,MAAOuC,EAAUM"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),s=require("react"),t=require("./index-Dc63uIP0.cjs"),n=require("./ModalOverlay-BDsGgv3_.cjs"),l=require("@remyxjs/core");function c(e){const s=[];let t=0;const n=e.length;for(;t<n;){if("<"===e[t]&&e.startsWith("!--",t+1)){const l=e.indexOf("--\x3e",t+4),c=-1===l?n:l+3;s.push({text:e.slice(t,c),className:"rmx-syn-comment"}),t=c;continue}if("<"===e[t]&&e.startsWith("!",t+1)&&/^<![a-zA-Z]/.test(e.slice(t,t+3))){const l=e.indexOf(">",t),c=-1===l?n:l+1;s.push({text:e.slice(t,c),className:"rmx-syn-doctype"}),t=c;continue}if("<"===e[t]&&("/"===e[t+1]||/[a-zA-Z]/.test(e[t+1]||""))){t=a(e,t,s);continue}if("&"===e[t]){const n=e.indexOf(";",t+1);if(-1!==n&&n-t<12&&/^&[#a-zA-Z0-9]+;$/.test(e.slice(t,n+1))){s.push({text:e.slice(t,n+1),className:"rmx-syn-entity"}),t=n+1;continue}}let l=t+1;for(;l<n&&"<"!==e[l]&&"&"!==e[l];)l++;s.push({text:e.slice(t,l),className:null}),t=l}return s}function a(e,s,t){const n=e.length;"/"===e[s+1]?(t.push({text:"</",className:"rmx-syn-tag"}),s+=2):(t.push({text:"<",className:"rmx-syn-tag"}),s+=1);let l=s;for(;s<n&&/[a-zA-Z0-9:-]/.test(e[s]);)s++;for(s>l&&t.push({text:e.slice(l,s),className:"rmx-syn-tag"});s<n;){if(/\s/.test(e[s])){let l=s;for(;s<n&&/\s/.test(e[s]);)s++;t.push({text:e.slice(l,s),className:null});continue}if("/"===e[s]&&">"===e[s+1])return t.push({text:"/>",className:"rmx-syn-tag"}),s+2;if(">"===e[s])return t.push({text:">",className:"rmx-syn-tag"}),s+1;let l=s;for(;s<n&&/[^\s=/>]/.test(e[s]);)s++;for(s>l&&t.push({text:e.slice(l,s),className:"rmx-syn-attr-name"});s<n&&/\s/.test(e[s]);)t.push({text:e[s],className:null}),s++;if(s<n&&"="===e[s]){for(t.push({text:"=",className:null}),s++;s<n&&/\s/.test(e[s]);)t.push({text:e[s],className:null}),s++;if(s<n&&('"'===e[s]||"'"===e[s])){const l=e[s],c=e.indexOf(l,s+1),a=-1===c?n:c+1;t.push({text:e.slice(s,a),className:"rmx-syn-attr-value"}),s=a}else{let l=s;for(;s<n&&/[^\s>]/.test(e[s]);)s++;s>l&&t.push({text:e.slice(l,s),className:"rmx-syn-attr-value"})}}}return s}function r(e){const s=e.split("\n"),t=[];let n=!1;for(let l=0;l<s.length;l++){const e=s[l];if(l>0&&t.push({text:"\n",className:null}),/^```/.test(e.trimStart())){t.push({text:e,className:"rmx-syn-code-fence"}),n=!n;continue}if(n){t.push({text:e,className:"rmx-syn-code"});continue}if(/^#{1,6}\s/.test(e)){t.push({text:e,className:"rmx-syn-heading"});continue}if(/^(\s*)([-*_])\2{2,}\s*$/.test(e)){t.push({text:e,className:"rmx-syn-hr"});continue}if(/^>\s?/.test(e)){const s=e.match(/^(>\s?)/);t.push({text:s[0],className:"rmx-syn-blockquote"}),i(e.slice(s[0].length),t);continue}const c=e.match(/^(\s*[-*+]\s+)/);if(c){t.push({text:c[0],className:"rmx-syn-list-marker"}),i(e.slice(c[0].length),t);continue}const a=e.match(/^(\s*\d+[.)]\s+)/);a?(t.push({text:a[0],className:"rmx-syn-list-marker"}),i(e.slice(a[0].length),t)):/^\|[\s:|-]+\|$/.test(e.trim())?t.push({text:e,className:"rmx-syn-hr"}):i(e,t)}return t}function i(e,s){let t=0;const n=e.length;let l=0;for(;t<n;){if("`"===e[t]){t>l&&s.push({text:e.slice(l,t),className:null});const n=e.indexOf("`",t+1);if(-1!==n){s.push({text:e.slice(t,n+1),className:"rmx-syn-code"}),t=n+1,l=t;continue}}if("!"===e[t]&&"["===e[t+1]){const n=e.indexOf("]",t+2);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,c+1),className:"rmx-syn-image"}),t=c+1,l=t;continue}}}if("["===e[t]){const n=e.indexOf("]",t+1);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,n+1),className:"rmx-syn-link"}),s.push({text:e.slice(n+1,c+1),className:"rmx-syn-url"}),t=c+1,l=t;continue}}}if("*"===e[t]&&"*"===e[t+1]||"_"===e[t]&&"_"===e[t+1]){const n=e.slice(t,t+2),c=e.indexOf(n,t+2);if(-1!==c){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,c+2),className:"rmx-syn-bold"}),t=c+2,l=t;continue}}if(("*"===e[t]||"_"===e[t])&&e[t+1]!==e[t]){const n=e[t],c=e.indexOf(n,t+1);if(-1!==c&&c>t+1){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,c+1),className:"rmx-syn-italic"}),t=c+1,l=t;continue}}t++}l<n&&s.push({text:e.slice(l),className:null})}function o({value:t,onChange:n,language:l="html"}){const a=s.useRef(null),i=s.useRef(null),o=s.useRef(null),u=s.useRef(null),[m,x]=s.useState(t||"");s.useEffect((()=>(u.current=setTimeout((()=>{x(t||"")}),150),()=>clearTimeout(u.current))),[t]);const f=s.useMemo((()=>("markdown"===l?r:c)(m)),[m,l]),h=s.useMemo((()=>(t||"").split("\n").length),[t]),d=s.useCallback((()=>{const e=a.current;e&&(i.current&&(i.current.scrollTop=e.scrollTop,i.current.scrollLeft=e.scrollLeft),o.current&&(o.current.scrollTop=e.scrollTop))}),[]),p=s.useCallback((e=>{if("Tab"===e.key){e.preventDefault();const s=e.target,l=s.selectionStart,c=s.selectionEnd;if("function"==typeof s.setRangeText)s.setRangeText(" ",l,c,"end"),s.dispatchEvent(new Event("input",{bubbles:!0}));else{const e=t.substring(0,l)+" "+t.substring(c);n(e),requestAnimationFrame((()=>{s.selectionStart=s.selectionEnd=l+2}))}}}),[t,n]);return e.jsxs("div",{className:"rmx-code-editor",children:[e.jsx("div",{ref:o,className:"rmx-code-gutter","aria-hidden":"true",children:Array.from({length:h},((s,t)=>e.jsx("div",{className:"rmx-code-line-number",children:t+1},t)))}),e.jsxs("div",{className:"rmx-code-body",children:[e.jsx("pre",{ref:i,className:"rmx-code-highlight","aria-hidden":"true",children:e.jsxs("code",{children:[f.map(((s,t)=>s.className?e.jsx("span",{className:s.className,children:s.text},t):s.text)),"\n"]})}),e.jsx("textarea",{ref:a,className:"rmx-code-input",value:t,onChange:e=>n(e.target.value),onScroll:d,onKeyDown:p,spellCheck:!1,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off","data-gramm":"false"})]})]})}function u({open:t,onClose:c,engine:a}){const[r,i]=s.useState(""),[u,m]=s.useState(""),x="markdown"===a?.outputFormat;s.useEffect((()=>{if(t&&a){const e=a.getHTML(),s=x?l.htmlToMarkdown(e):l.formatHTML(e);i(s),m(s)}}),[t,a,x]);const f=s.useCallback((()=>{if(r!==u){if(!window.confirm("You have unsaved changes. Discard them?"))return}c()}),[r,u,c]);return e.jsx(n.ModalOverlay,{title:x?"Markdown Source":"Source Code",open:t,onClose:f,width:750,children:e.jsxs("div",{className:"rmx-modal-form",children:[e.jsx(o,{value:r,onChange:i,language:x?"markdown":"html"}),e.jsxs("div",{className:"rmx-modal-actions",children:[e.jsx("button",{type:"button",className:"rmx-btn",onClick:f,children:"Cancel"}),e.jsx("button",{type:"button",className:"rmx-btn rmx-btn-primary",onClick:()=>{a.history.snapshot();const e=x?l.markdownToHtml(r):r,s=a.sanitizer.sanitize(e);s!==e&&a.eventBus.emit("source:sanitized",{message:"Some HTML elements or attributes were removed for security."}),a.setHTML(s),a.eventBus.emit("content:change"),c()},children:"Apply"})]})]})})}u.propTypes={open:t.PropTypes.bool.isRequired,onClose:t.PropTypes.func.isRequired,engine:t.PropTypes.object},exports.SourceModal=u;
2
- //# sourceMappingURL=SourceModal-BNI_i4iW.cjs.map
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),s=require("react"),t=require("./index-qh1Yzh-l.cjs"),n=require("./ModalOverlay-Dh5quv7X.cjs"),l=require("@remyxjs/core");function c(e){const s=[];let t=0;const n=e.length;for(;t<n;){if("<"===e[t]&&e.startsWith("!--",t+1)){const l=e.indexOf("--\x3e",t+4),c=-1===l?n:l+3;s.push({text:e.slice(t,c),className:"rmx-syn-comment"}),t=c;continue}if("<"===e[t]&&e.startsWith("!",t+1)&&/^<![a-zA-Z]/.test(e.slice(t,t+3))){const l=e.indexOf(">",t),c=-1===l?n:l+1;s.push({text:e.slice(t,c),className:"rmx-syn-doctype"}),t=c;continue}if("<"===e[t]&&("/"===e[t+1]||/[a-zA-Z]/.test(e[t+1]||""))){t=a(e,t,s);continue}if("&"===e[t]){const n=e.indexOf(";",t+1);if(-1!==n&&n-t<12&&/^&[#a-zA-Z0-9]+;$/.test(e.slice(t,n+1))){s.push({text:e.slice(t,n+1),className:"rmx-syn-entity"}),t=n+1;continue}}let l=t+1;for(;l<n&&"<"!==e[l]&&"&"!==e[l];)l++;s.push({text:e.slice(t,l),className:null}),t=l}return s}function a(e,s,t){const n=e.length;"/"===e[s+1]?(t.push({text:"</",className:"rmx-syn-tag"}),s+=2):(t.push({text:"<",className:"rmx-syn-tag"}),s+=1);let l=s;for(;s<n&&/[a-zA-Z0-9:-]/.test(e[s]);)s++;for(s>l&&t.push({text:e.slice(l,s),className:"rmx-syn-tag"});s<n;){if(/\s/.test(e[s])){let l=s;for(;s<n&&/\s/.test(e[s]);)s++;t.push({text:e.slice(l,s),className:null});continue}if("/"===e[s]&&">"===e[s+1])return t.push({text:"/>",className:"rmx-syn-tag"}),s+2;if(">"===e[s])return t.push({text:">",className:"rmx-syn-tag"}),s+1;let l=s;for(;s<n&&/[^\s=/>]/.test(e[s]);)s++;for(s>l&&t.push({text:e.slice(l,s),className:"rmx-syn-attr-name"});s<n&&/\s/.test(e[s]);)t.push({text:e[s],className:null}),s++;if(s<n&&"="===e[s]){for(t.push({text:"=",className:null}),s++;s<n&&/\s/.test(e[s]);)t.push({text:e[s],className:null}),s++;if(s<n&&('"'===e[s]||"'"===e[s])){const l=e[s],c=e.indexOf(l,s+1),a=-1===c?n:c+1;t.push({text:e.slice(s,a),className:"rmx-syn-attr-value"}),s=a}else{let l=s;for(;s<n&&/[^\s>]/.test(e[s]);)s++;s>l&&t.push({text:e.slice(l,s),className:"rmx-syn-attr-value"})}}}return s}function r(e){const s=e.split("\n"),t=[];let n=!1;for(let l=0;l<s.length;l++){const e=s[l];if(l>0&&t.push({text:"\n",className:null}),/^```/.test(e.trimStart())){t.push({text:e,className:"rmx-syn-code-fence"}),n=!n;continue}if(n){t.push({text:e,className:"rmx-syn-code"});continue}if(/^#{1,6}\s/.test(e)){t.push({text:e,className:"rmx-syn-heading"});continue}if(/^(\s*)([-*_])\2{2,}\s*$/.test(e)){t.push({text:e,className:"rmx-syn-hr"});continue}if(/^>\s?/.test(e)){const s=e.match(/^(>\s?)/);t.push({text:s[0],className:"rmx-syn-blockquote"}),i(e.slice(s[0].length),t);continue}const c=e.match(/^(\s*[-*+]\s+)/);if(c){t.push({text:c[0],className:"rmx-syn-list-marker"}),i(e.slice(c[0].length),t);continue}const a=e.match(/^(\s*\d+[.)]\s+)/);a?(t.push({text:a[0],className:"rmx-syn-list-marker"}),i(e.slice(a[0].length),t)):/^\|[\s:|-]+\|$/.test(e.trim())?t.push({text:e,className:"rmx-syn-hr"}):i(e,t)}return t}function i(e,s){let t=0;const n=e.length;let l=0;for(;t<n;){if("`"===e[t]){t>l&&s.push({text:e.slice(l,t),className:null});const n=e.indexOf("`",t+1);if(-1!==n){s.push({text:e.slice(t,n+1),className:"rmx-syn-code"}),t=n+1,l=t;continue}}if("!"===e[t]&&"["===e[t+1]){const n=e.indexOf("]",t+2);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,c+1),className:"rmx-syn-image"}),t=c+1,l=t;continue}}}if("["===e[t]){const n=e.indexOf("]",t+1);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,n+1),className:"rmx-syn-link"}),s.push({text:e.slice(n+1,c+1),className:"rmx-syn-url"}),t=c+1,l=t;continue}}}if("*"===e[t]&&"*"===e[t+1]||"_"===e[t]&&"_"===e[t+1]){const n=e.slice(t,t+2),c=e.indexOf(n,t+2);if(-1!==c){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,c+2),className:"rmx-syn-bold"}),t=c+2,l=t;continue}}if(("*"===e[t]||"_"===e[t])&&e[t+1]!==e[t]){const n=e[t],c=e.indexOf(n,t+1);if(-1!==c&&c>t+1){t>l&&s.push({text:e.slice(l,t),className:null}),s.push({text:e.slice(t,c+1),className:"rmx-syn-italic"}),t=c+1,l=t;continue}}t++}l<n&&s.push({text:e.slice(l),className:null})}function o({value:t,onChange:n,language:l="html"}){const a=s.useRef(null),i=s.useRef(null),o=s.useRef(null),u=s.useRef(null),[m,x]=s.useState(t||"");s.useEffect((()=>(u.current=setTimeout((()=>{x(t||"")}),150),()=>clearTimeout(u.current))),[t]);const f=s.useMemo((()=>("markdown"===l?r:c)(m)),[m,l]),h=s.useMemo((()=>(t||"").split("\n").length),[t]),d=s.useCallback((()=>{const e=a.current;e&&(i.current&&(i.current.scrollTop=e.scrollTop,i.current.scrollLeft=e.scrollLeft),o.current&&(o.current.scrollTop=e.scrollTop))}),[]),p=s.useCallback((e=>{if("Tab"===e.key){e.preventDefault();const s=e.target,l=s.selectionStart,c=s.selectionEnd;if("function"==typeof s.setRangeText)s.setRangeText(" ",l,c,"end"),s.dispatchEvent(new Event("input",{bubbles:!0}));else{const e=t.substring(0,l)+" "+t.substring(c);n(e),requestAnimationFrame((()=>{s.selectionStart=s.selectionEnd=l+2}))}}}),[t,n]);return e.jsxs("div",{className:"rmx-code-editor",children:[e.jsx("div",{ref:o,className:"rmx-code-gutter","aria-hidden":"true",children:Array.from({length:h},((s,t)=>e.jsx("div",{className:"rmx-code-line-number",children:t+1},t)))}),e.jsxs("div",{className:"rmx-code-body",children:[e.jsx("pre",{ref:i,className:"rmx-code-highlight","aria-hidden":"true",children:e.jsxs("code",{children:[f.map(((s,t)=>s.className?e.jsx("span",{className:s.className,children:s.text},t):s.text)),"\n"]})}),e.jsx("textarea",{ref:a,className:"rmx-code-input",value:t,onChange:e=>n(e.target.value),onScroll:d,onKeyDown:p,spellCheck:!1,autoCapitalize:"off",autoComplete:"off",autoCorrect:"off","data-gramm":"false"})]})]})}function u({open:t,onClose:c,engine:a}){const[r,i]=s.useState(""),[u,m]=s.useState(""),x="markdown"===a?.outputFormat;s.useEffect((()=>{if(t&&a){const e=a.getHTML(),s=x?l.htmlToMarkdown(e):l.formatHTML(e);i(s),m(s)}}),[t,a,x]);const f=s.useCallback((()=>{if(r!==u){if(!window.confirm("You have unsaved changes. Discard them?"))return}c()}),[r,u,c]);return e.jsx(n.ModalOverlay,{title:x?"Markdown Source":"Source Code",open:t,onClose:f,width:750,children:e.jsxs("div",{className:"rmx-modal-form",children:[e.jsx(o,{value:r,onChange:i,language:x?"markdown":"html"}),e.jsxs("div",{className:"rmx-modal-actions",children:[e.jsx("button",{type:"button",className:"rmx-btn",onClick:f,children:"Cancel"}),e.jsx("button",{type:"button",className:"rmx-btn rmx-btn-primary",onClick:()=>{a.history.snapshot();const e=x?l.markdownToHtml(r):r,s=a.sanitizer.sanitize(e);s!==e&&a.eventBus.emit("source:sanitized",{message:"Some HTML elements or attributes were removed for security."}),a.setHTML(s),a.eventBus.emit("content:change"),c()},children:"Apply"})]})]})})}u.propTypes={open:t.PropTypes.bool.isRequired,onClose:t.PropTypes.func.isRequired,engine:t.PropTypes.object},exports.SourceModal=u;
2
+ //# sourceMappingURL=SourceModal-CHKC5xcv.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SourceModal-BNI_i4iW.cjs","sources":["../src/components/Modals/CodeEditor/highlightHTML.js","../src/components/Modals/CodeEditor/highlightMarkdown.js","../src/components/Modals/CodeEditor/CodeEditor.jsx","../src/components/Modals/SourceModal.jsx"],"sourcesContent":["/**\n * Lightweight HTML tokenizer for syntax highlighting.\n * Returns an array of { text, className } tokens.\n */\nexport function highlightHTML(code) {\n const tokens = []\n let i = 0\n const len = code.length\n\n while (i < len) {\n // Comment: <!-- ... -->\n if (code[i] === '<' && code.startsWith('!--', i + 1)) {\n const end = code.indexOf('-->', i + 4)\n const commentEnd = end === -1 ? len : end + 3\n tokens.push({ text: code.slice(i, commentEnd), className: 'rmx-syn-comment' })\n i = commentEnd\n continue\n }\n\n // Doctype: <!DOCTYPE ...>\n if (code[i] === '<' && code.startsWith('!', i + 1) && /^<![a-zA-Z]/.test(code.slice(i, i + 3))) {\n const end = code.indexOf('>', i)\n const doctypeEnd = end === -1 ? len : end + 1\n tokens.push({ text: code.slice(i, doctypeEnd), className: 'rmx-syn-doctype' })\n i = doctypeEnd\n continue\n }\n\n // Tag: < ... >\n if (code[i] === '<' && (code[i + 1] === '/' || /[a-zA-Z]/.test(code[i + 1] || ''))) {\n i = parseTag(code, i, tokens)\n continue\n }\n\n // Entity: &...;\n if (code[i] === '&') {\n const semi = code.indexOf(';', i + 1)\n if (semi !== -1 && semi - i < 12 && /^&[#a-zA-Z0-9]+;$/.test(code.slice(i, semi + 1))) {\n tokens.push({ text: code.slice(i, semi + 1), className: 'rmx-syn-entity' })\n i = semi + 1\n continue\n }\n }\n\n // Plain text until next < or &\n let textEnd = i + 1\n while (textEnd < len && code[textEnd] !== '<' && code[textEnd] !== '&') {\n textEnd++\n }\n tokens.push({ text: code.slice(i, textEnd), className: null })\n i = textEnd\n }\n\n return tokens\n}\n\n/**\n * Parse an HTML tag starting at position i, pushing tokens.\n * Returns the new position after the tag.\n */\nfunction parseTag(code, i, tokens) {\n const len = code.length\n\n // Opening: < or </\n if (code[i + 1] === '/') {\n tokens.push({ text: '</', className: 'rmx-syn-tag' })\n i += 2\n } else {\n tokens.push({ text: '<', className: 'rmx-syn-tag' })\n i += 1\n }\n\n // Tag name\n let nameStart = i\n while (i < len && /[a-zA-Z0-9:-]/.test(code[i])) i++\n if (i > nameStart) {\n tokens.push({ text: code.slice(nameStart, i), className: 'rmx-syn-tag' })\n }\n\n // Attributes and closing\n while (i < len) {\n // Skip whitespace\n if (/\\s/.test(code[i])) {\n let wsStart = i\n while (i < len && /\\s/.test(code[i])) i++\n tokens.push({ text: code.slice(wsStart, i), className: null })\n continue\n }\n\n // Self-close or close: />, >\n if (code[i] === '/' && code[i + 1] === '>') {\n tokens.push({ text: '/>', className: 'rmx-syn-tag' })\n return i + 2\n }\n if (code[i] === '>') {\n tokens.push({ text: '>', className: 'rmx-syn-tag' })\n return i + 1\n }\n\n // Attribute name\n let attrStart = i\n while (i < len && /[^\\s=/>]/.test(code[i])) i++\n if (i > attrStart) {\n tokens.push({ text: code.slice(attrStart, i), className: 'rmx-syn-attr-name' })\n }\n\n // Skip whitespace around =\n while (i < len && /\\s/.test(code[i])) {\n tokens.push({ text: code[i], className: null })\n i++\n }\n\n // = sign\n if (i < len && code[i] === '=') {\n tokens.push({ text: '=', className: null })\n i++\n\n // Skip whitespace after =\n while (i < len && /\\s/.test(code[i])) {\n tokens.push({ text: code[i], className: null })\n i++\n }\n\n // Attribute value\n if (i < len && (code[i] === '\"' || code[i] === \"'\")) {\n const quote = code[i]\n const valEnd = code.indexOf(quote, i + 1)\n const end = valEnd === -1 ? len : valEnd + 1\n tokens.push({ text: code.slice(i, end), className: 'rmx-syn-attr-value' })\n i = end\n } else {\n // Unquoted value\n let valStart = i\n while (i < len && /[^\\s>]/.test(code[i])) i++\n if (i > valStart) {\n tokens.push({ text: code.slice(valStart, i), className: 'rmx-syn-attr-value' })\n }\n }\n }\n }\n\n return i\n}\n","/**\n * Lightweight Markdown tokenizer for syntax highlighting.\n * Operates line-by-line since Markdown is line-oriented.\n * Returns an array of { text, className } tokens.\n */\nexport function highlightMarkdown(code) {\n const lines = code.split('\\n')\n const tokens = []\n let inCodeBlock = false\n\n for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {\n const line = lines[lineIdx]\n\n // Add newline between lines (not before the first)\n if (lineIdx > 0) {\n tokens.push({ text: '\\n', className: null })\n }\n\n // Code fence toggle: ```\n if (/^```/.test(line.trimStart())) {\n tokens.push({ text: line, className: 'rmx-syn-code-fence' })\n inCodeBlock = !inCodeBlock\n continue\n }\n\n // Inside code block — all code\n if (inCodeBlock) {\n tokens.push({ text: line, className: 'rmx-syn-code' })\n continue\n }\n\n // Heading: # ... ######\n if (/^#{1,6}\\s/.test(line)) {\n tokens.push({ text: line, className: 'rmx-syn-heading' })\n continue\n }\n\n // Horizontal rule: ---, ***, ___\n if (/^(\\s*)([-*_])\\2{2,}\\s*$/.test(line)) {\n tokens.push({ text: line, className: 'rmx-syn-hr' })\n continue\n }\n\n // Blockquote: > text\n if (/^>\\s?/.test(line)) {\n const markerMatch = line.match(/^(>\\s?)/)\n tokens.push({ text: markerMatch[0], className: 'rmx-syn-blockquote' })\n highlightInline(line.slice(markerMatch[0].length), tokens)\n continue\n }\n\n // Unordered list: - item, * item, + item\n const ulMatch = line.match(/^(\\s*[-*+]\\s+)/)\n if (ulMatch) {\n tokens.push({ text: ulMatch[0], className: 'rmx-syn-list-marker' })\n highlightInline(line.slice(ulMatch[0].length), tokens)\n continue\n }\n\n // Ordered list: 1. item, 2) item\n const olMatch = line.match(/^(\\s*\\d+[.)]\\s+)/)\n if (olMatch) {\n tokens.push({ text: olMatch[0], className: 'rmx-syn-list-marker' })\n highlightInline(line.slice(olMatch[0].length), tokens)\n continue\n }\n\n // Table separator: |---|---|\n if (/^\\|[\\s:|-]+\\|$/.test(line.trim())) {\n tokens.push({ text: line, className: 'rmx-syn-hr' })\n continue\n }\n\n // Regular line — process inline formatting\n highlightInline(line, tokens)\n }\n\n return tokens\n}\n\n/**\n * Tokenize inline Markdown formatting within a line.\n * Handles: bold, italic, inline code, links, images.\n */\nfunction highlightInline(text, tokens) {\n let i = 0\n const len = text.length\n let plainStart = 0\n\n while (i < len) {\n // Inline code: `code`\n if (text[i] === '`') {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n const end = text.indexOf('`', i + 1)\n if (end !== -1) {\n tokens.push({ text: text.slice(i, end + 1), className: 'rmx-syn-code' })\n i = end + 1\n plainStart = i\n continue\n }\n }\n\n // Image: ![alt](url)\n if (text[i] === '!' && text[i + 1] === '[') {\n const closeBracket = text.indexOf(']', i + 2)\n if (closeBracket !== -1 && text[closeBracket + 1] === '(') {\n const closeParen = text.indexOf(')', closeBracket + 2)\n if (closeParen !== -1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n tokens.push({ text: text.slice(i, closeParen + 1), className: 'rmx-syn-image' })\n i = closeParen + 1\n plainStart = i\n continue\n }\n }\n }\n\n // Link: [text](url)\n if (text[i] === '[') {\n const closeBracket = text.indexOf(']', i + 1)\n if (closeBracket !== -1 && text[closeBracket + 1] === '(') {\n const closeParen = text.indexOf(')', closeBracket + 2)\n if (closeParen !== -1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n // [text]\n tokens.push({ text: text.slice(i, closeBracket + 1), className: 'rmx-syn-link' })\n // (url)\n tokens.push({ text: text.slice(closeBracket + 1, closeParen + 1), className: 'rmx-syn-url' })\n i = closeParen + 1\n plainStart = i\n continue\n }\n }\n }\n\n // Bold: **text** or __text__\n if ((text[i] === '*' && text[i + 1] === '*') || (text[i] === '_' && text[i + 1] === '_')) {\n const marker = text.slice(i, i + 2)\n const end = text.indexOf(marker, i + 2)\n if (end !== -1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n tokens.push({ text: text.slice(i, end + 2), className: 'rmx-syn-bold' })\n i = end + 2\n plainStart = i\n continue\n }\n }\n\n // Italic: *text* or _text_ (single, not preceded/followed by same)\n if ((text[i] === '*' || text[i] === '_') && text[i + 1] !== text[i]) {\n const marker = text[i]\n const end = text.indexOf(marker, i + 1)\n if (end !== -1 && end > i + 1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n tokens.push({ text: text.slice(i, end + 1), className: 'rmx-syn-italic' })\n i = end + 1\n plainStart = i\n continue\n }\n }\n\n i++\n }\n\n // Remaining plain text\n if (plainStart < len) {\n tokens.push({ text: text.slice(plainStart), className: null })\n }\n}\n","import { useRef, useMemo, useCallback, useState, useEffect } from 'react'\nimport { highlightHTML } from './highlightHTML.js'\nimport { highlightMarkdown } from './highlightMarkdown.js'\nimport './CodeEditor.css'\n\nconst HIGHLIGHT_DEBOUNCE_MS = 150\n\nexport function CodeEditor({ value, onChange, language = 'html' }) {\n const textareaRef = useRef(null)\n const preRef = useRef(null)\n const gutterRef = useRef(null)\n const highlightTimerRef = useRef(null)\n\n // Debounced value for highlighting — delays expensive tokenization\n const [debouncedValue, setDebouncedValue] = useState(value || '')\n\n useEffect(() => {\n highlightTimerRef.current = setTimeout(() => {\n setDebouncedValue(value || '')\n }, HIGHLIGHT_DEBOUNCE_MS)\n return () => clearTimeout(highlightTimerRef.current)\n }, [value])\n\n // Tokenize the debounced source for highlighting\n const highlighted = useMemo(() => {\n const highlighter = language === 'markdown' ? highlightMarkdown : highlightHTML\n return highlighter(debouncedValue)\n }, [debouncedValue, language])\n\n // Count lines for the gutter\n const lineCount = useMemo(() => {\n return (value || '').split('\\n').length\n }, [value])\n\n // Sync scroll between textarea, pre, and gutter\n const handleScroll = useCallback(() => {\n const ta = textareaRef.current\n if (!ta) return\n if (preRef.current) {\n preRef.current.scrollTop = ta.scrollTop\n preRef.current.scrollLeft = ta.scrollLeft\n }\n if (gutterRef.current) {\n gutterRef.current.scrollTop = ta.scrollTop\n }\n }, [])\n\n // Tab key inserts 2 spaces\n const handleKeyDown = useCallback((e) => {\n if (e.key === 'Tab') {\n e.preventDefault()\n const ta = e.target\n const start = ta.selectionStart\n const end = ta.selectionEnd\n // Use setRangeText to insert text while preserving undo stack\n if (typeof ta.setRangeText === 'function') {\n ta.setRangeText(' ', start, end, 'end')\n ta.dispatchEvent(new Event('input', { bubbles: true }))\n } else {\n const newValue = value.substring(0, start) + ' ' + value.substring(end)\n onChange(newValue)\n requestAnimationFrame(() => {\n ta.selectionStart = ta.selectionEnd = start + 2\n })\n }\n }\n }, [value, onChange])\n\n return (\n <div className=\"rmx-code-editor\">\n {/* Line number gutter */}\n <div ref={gutterRef} className=\"rmx-code-gutter\" aria-hidden=\"true\">\n {Array.from({ length: lineCount }, (_, i) => (\n <div key={i} className=\"rmx-code-line-number\">{i + 1}</div>\n ))}\n </div>\n\n {/* Editor body: highlighted pre + transparent textarea */}\n <div className=\"rmx-code-body\">\n <pre ref={preRef} className=\"rmx-code-highlight\" aria-hidden=\"true\">\n <code>\n {highlighted.map((token, i) =>\n token.className\n ? <span key={i} className={token.className}>{token.text}</span>\n : token.text\n )}\n {'\\n'}\n </code>\n </pre>\n\n <textarea\n ref={textareaRef}\n className=\"rmx-code-input\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onScroll={handleScroll}\n onKeyDown={handleKeyDown}\n spellCheck={false}\n autoCapitalize=\"off\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n data-gramm=\"false\"\n />\n </div>\n </div>\n )\n}\n","import { useState, useEffect, useRef, useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { ModalOverlay } from './ModalOverlay.jsx'\nimport { CodeEditor } from './CodeEditor/CodeEditor.jsx'\nimport { htmlToMarkdown, markdownToHtml, formatHTML } from '@remyxjs/core'\n\nexport function SourceModal({ open, onClose, engine }) {\n const [source, setSource] = useState('')\n const [initialSource, setInitialSource] = useState('')\n const isMarkdown = engine?.outputFormat === 'markdown'\n\n useEffect(() => {\n if (open && engine) {\n const html = engine.getHTML()\n const formatted = isMarkdown ? htmlToMarkdown(html) : formatHTML(html)\n setSource(formatted)\n setInitialSource(formatted)\n }\n }, [open, engine, isMarkdown])\n\n const handleApply = () => {\n engine.history.snapshot()\n const rawHtml = isMarkdown ? markdownToHtml(source) : source\n // Re-sanitize user-edited HTML to prevent XSS injection via source mode\n const htmlToApply = engine.sanitizer.sanitize(rawHtml)\n // Notify if sanitizer modified the input (unsafe content was stripped)\n if (htmlToApply !== rawHtml) {\n engine.eventBus.emit('source:sanitized', {\n message: 'Some HTML elements or attributes were removed for security.',\n })\n }\n engine.setHTML(htmlToApply)\n engine.eventBus.emit('content:change')\n onClose()\n }\n\n // #33: Confirm before discarding unsaved changes\n const handleClose = useCallback(() => {\n if (source !== initialSource) {\n const confirmed = window.confirm('You have unsaved changes. Discard them?')\n if (!confirmed) return\n }\n onClose()\n }, [source, initialSource, onClose])\n\n return (\n <ModalOverlay title={isMarkdown ? 'Markdown Source' : 'Source Code'} open={open} onClose={handleClose} width={750}>\n <div className=\"rmx-modal-form\">\n <CodeEditor\n value={source}\n onChange={setSource}\n language={isMarkdown ? 'markdown' : 'html'}\n />\n <div className=\"rmx-modal-actions\">\n <button type=\"button\" className=\"rmx-btn\" onClick={handleClose}>Cancel</button>\n <button type=\"button\" className=\"rmx-btn rmx-btn-primary\" onClick={handleApply}>Apply</button>\n </div>\n </div>\n </ModalOverlay>\n )\n}\n\nSourceModal.propTypes = {\n open: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n engine: PropTypes.object,\n}\n"],"names":["highlightHTML","code","tokens","i","len","length","startsWith","end","indexOf","commentEnd","push","text","slice","className","test","doctypeEnd","parseTag","semi","textEnd","nameStart","wsStart","attrStart","quote","valEnd","valStart","highlightMarkdown","lines","split","inCodeBlock","lineIdx","line","trimStart","markerMatch","match","highlightInline","ulMatch","olMatch","trim","plainStart","closeBracket","closeParen","marker","CodeEditor","value","onChange","language","textareaRef","useRef","preRef","gutterRef","highlightTimerRef","debouncedValue","setDebouncedValue","useState","useEffect","current","setTimeout","clearTimeout","highlighted","useMemo","lineCount","handleScroll","useCallback","ta","scrollTop","scrollLeft","handleKeyDown","e","key","preventDefault","target","start","selectionStart","selectionEnd","setRangeText","dispatchEvent","Event","bubbles","newValue","substring","requestAnimationFrame","jsxs","children","jsx","ref","Array","from","_","map","token","onScroll","onKeyDown","spellCheck","autoCapitalize","autoComplete","autoCorrect","SourceModal","open","onClose","engine","source","setSource","initialSource","setInitialSource","isMarkdown","outputFormat","html","getHTML","formatted","htmlToMarkdown","formatHTML","handleClose","window","confirm","ModalOverlay","title","width","type","onClick","history","snapshot","rawHtml","markdownToHtml","htmlToApply","sanitizer","sanitize","eventBus","emit","message","setHTML","propTypes","PropTypes","bool","isRequired","func","object"],"mappings":"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"}
1
+ {"version":3,"file":"SourceModal-CHKC5xcv.cjs","sources":["../src/components/Modals/CodeEditor/highlightHTML.js","../src/components/Modals/CodeEditor/highlightMarkdown.js","../src/components/Modals/CodeEditor/CodeEditor.jsx","../src/components/Modals/SourceModal.jsx"],"sourcesContent":["/**\n * Lightweight HTML tokenizer for syntax highlighting.\n * Returns an array of { text, className } tokens.\n */\nexport function highlightHTML(code) {\n const tokens = []\n let i = 0\n const len = code.length\n\n while (i < len) {\n // Comment: <!-- ... -->\n if (code[i] === '<' && code.startsWith('!--', i + 1)) {\n const end = code.indexOf('-->', i + 4)\n const commentEnd = end === -1 ? len : end + 3\n tokens.push({ text: code.slice(i, commentEnd), className: 'rmx-syn-comment' })\n i = commentEnd\n continue\n }\n\n // Doctype: <!DOCTYPE ...>\n if (code[i] === '<' && code.startsWith('!', i + 1) && /^<![a-zA-Z]/.test(code.slice(i, i + 3))) {\n const end = code.indexOf('>', i)\n const doctypeEnd = end === -1 ? len : end + 1\n tokens.push({ text: code.slice(i, doctypeEnd), className: 'rmx-syn-doctype' })\n i = doctypeEnd\n continue\n }\n\n // Tag: < ... >\n if (code[i] === '<' && (code[i + 1] === '/' || /[a-zA-Z]/.test(code[i + 1] || ''))) {\n i = parseTag(code, i, tokens)\n continue\n }\n\n // Entity: &...;\n if (code[i] === '&') {\n const semi = code.indexOf(';', i + 1)\n if (semi !== -1 && semi - i < 12 && /^&[#a-zA-Z0-9]+;$/.test(code.slice(i, semi + 1))) {\n tokens.push({ text: code.slice(i, semi + 1), className: 'rmx-syn-entity' })\n i = semi + 1\n continue\n }\n }\n\n // Plain text until next < or &\n let textEnd = i + 1\n while (textEnd < len && code[textEnd] !== '<' && code[textEnd] !== '&') {\n textEnd++\n }\n tokens.push({ text: code.slice(i, textEnd), className: null })\n i = textEnd\n }\n\n return tokens\n}\n\n/**\n * Parse an HTML tag starting at position i, pushing tokens.\n * Returns the new position after the tag.\n */\nfunction parseTag(code, i, tokens) {\n const len = code.length\n\n // Opening: < or </\n if (code[i + 1] === '/') {\n tokens.push({ text: '</', className: 'rmx-syn-tag' })\n i += 2\n } else {\n tokens.push({ text: '<', className: 'rmx-syn-tag' })\n i += 1\n }\n\n // Tag name\n let nameStart = i\n while (i < len && /[a-zA-Z0-9:-]/.test(code[i])) i++\n if (i > nameStart) {\n tokens.push({ text: code.slice(nameStart, i), className: 'rmx-syn-tag' })\n }\n\n // Attributes and closing\n while (i < len) {\n // Skip whitespace\n if (/\\s/.test(code[i])) {\n let wsStart = i\n while (i < len && /\\s/.test(code[i])) i++\n tokens.push({ text: code.slice(wsStart, i), className: null })\n continue\n }\n\n // Self-close or close: />, >\n if (code[i] === '/' && code[i + 1] === '>') {\n tokens.push({ text: '/>', className: 'rmx-syn-tag' })\n return i + 2\n }\n if (code[i] === '>') {\n tokens.push({ text: '>', className: 'rmx-syn-tag' })\n return i + 1\n }\n\n // Attribute name\n let attrStart = i\n while (i < len && /[^\\s=/>]/.test(code[i])) i++\n if (i > attrStart) {\n tokens.push({ text: code.slice(attrStart, i), className: 'rmx-syn-attr-name' })\n }\n\n // Skip whitespace around =\n while (i < len && /\\s/.test(code[i])) {\n tokens.push({ text: code[i], className: null })\n i++\n }\n\n // = sign\n if (i < len && code[i] === '=') {\n tokens.push({ text: '=', className: null })\n i++\n\n // Skip whitespace after =\n while (i < len && /\\s/.test(code[i])) {\n tokens.push({ text: code[i], className: null })\n i++\n }\n\n // Attribute value\n if (i < len && (code[i] === '\"' || code[i] === \"'\")) {\n const quote = code[i]\n const valEnd = code.indexOf(quote, i + 1)\n const end = valEnd === -1 ? len : valEnd + 1\n tokens.push({ text: code.slice(i, end), className: 'rmx-syn-attr-value' })\n i = end\n } else {\n // Unquoted value\n let valStart = i\n while (i < len && /[^\\s>]/.test(code[i])) i++\n if (i > valStart) {\n tokens.push({ text: code.slice(valStart, i), className: 'rmx-syn-attr-value' })\n }\n }\n }\n }\n\n return i\n}\n","/**\n * Lightweight Markdown tokenizer for syntax highlighting.\n * Operates line-by-line since Markdown is line-oriented.\n * Returns an array of { text, className } tokens.\n */\nexport function highlightMarkdown(code) {\n const lines = code.split('\\n')\n const tokens = []\n let inCodeBlock = false\n\n for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {\n const line = lines[lineIdx]\n\n // Add newline between lines (not before the first)\n if (lineIdx > 0) {\n tokens.push({ text: '\\n', className: null })\n }\n\n // Code fence toggle: ```\n if (/^```/.test(line.trimStart())) {\n tokens.push({ text: line, className: 'rmx-syn-code-fence' })\n inCodeBlock = !inCodeBlock\n continue\n }\n\n // Inside code block — all code\n if (inCodeBlock) {\n tokens.push({ text: line, className: 'rmx-syn-code' })\n continue\n }\n\n // Heading: # ... ######\n if (/^#{1,6}\\s/.test(line)) {\n tokens.push({ text: line, className: 'rmx-syn-heading' })\n continue\n }\n\n // Horizontal rule: ---, ***, ___\n if (/^(\\s*)([-*_])\\2{2,}\\s*$/.test(line)) {\n tokens.push({ text: line, className: 'rmx-syn-hr' })\n continue\n }\n\n // Blockquote: > text\n if (/^>\\s?/.test(line)) {\n const markerMatch = line.match(/^(>\\s?)/)\n tokens.push({ text: markerMatch[0], className: 'rmx-syn-blockquote' })\n highlightInline(line.slice(markerMatch[0].length), tokens)\n continue\n }\n\n // Unordered list: - item, * item, + item\n const ulMatch = line.match(/^(\\s*[-*+]\\s+)/)\n if (ulMatch) {\n tokens.push({ text: ulMatch[0], className: 'rmx-syn-list-marker' })\n highlightInline(line.slice(ulMatch[0].length), tokens)\n continue\n }\n\n // Ordered list: 1. item, 2) item\n const olMatch = line.match(/^(\\s*\\d+[.)]\\s+)/)\n if (olMatch) {\n tokens.push({ text: olMatch[0], className: 'rmx-syn-list-marker' })\n highlightInline(line.slice(olMatch[0].length), tokens)\n continue\n }\n\n // Table separator: |---|---|\n if (/^\\|[\\s:|-]+\\|$/.test(line.trim())) {\n tokens.push({ text: line, className: 'rmx-syn-hr' })\n continue\n }\n\n // Regular line — process inline formatting\n highlightInline(line, tokens)\n }\n\n return tokens\n}\n\n/**\n * Tokenize inline Markdown formatting within a line.\n * Handles: bold, italic, inline code, links, images.\n */\nfunction highlightInline(text, tokens) {\n let i = 0\n const len = text.length\n let plainStart = 0\n\n while (i < len) {\n // Inline code: `code`\n if (text[i] === '`') {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n const end = text.indexOf('`', i + 1)\n if (end !== -1) {\n tokens.push({ text: text.slice(i, end + 1), className: 'rmx-syn-code' })\n i = end + 1\n plainStart = i\n continue\n }\n }\n\n // Image: ![alt](url)\n if (text[i] === '!' && text[i + 1] === '[') {\n const closeBracket = text.indexOf(']', i + 2)\n if (closeBracket !== -1 && text[closeBracket + 1] === '(') {\n const closeParen = text.indexOf(')', closeBracket + 2)\n if (closeParen !== -1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n tokens.push({ text: text.slice(i, closeParen + 1), className: 'rmx-syn-image' })\n i = closeParen + 1\n plainStart = i\n continue\n }\n }\n }\n\n // Link: [text](url)\n if (text[i] === '[') {\n const closeBracket = text.indexOf(']', i + 1)\n if (closeBracket !== -1 && text[closeBracket + 1] === '(') {\n const closeParen = text.indexOf(')', closeBracket + 2)\n if (closeParen !== -1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n // [text]\n tokens.push({ text: text.slice(i, closeBracket + 1), className: 'rmx-syn-link' })\n // (url)\n tokens.push({ text: text.slice(closeBracket + 1, closeParen + 1), className: 'rmx-syn-url' })\n i = closeParen + 1\n plainStart = i\n continue\n }\n }\n }\n\n // Bold: **text** or __text__\n if ((text[i] === '*' && text[i + 1] === '*') || (text[i] === '_' && text[i + 1] === '_')) {\n const marker = text.slice(i, i + 2)\n const end = text.indexOf(marker, i + 2)\n if (end !== -1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n tokens.push({ text: text.slice(i, end + 2), className: 'rmx-syn-bold' })\n i = end + 2\n plainStart = i\n continue\n }\n }\n\n // Italic: *text* or _text_ (single, not preceded/followed by same)\n if ((text[i] === '*' || text[i] === '_') && text[i + 1] !== text[i]) {\n const marker = text[i]\n const end = text.indexOf(marker, i + 1)\n if (end !== -1 && end > i + 1) {\n if (i > plainStart) {\n tokens.push({ text: text.slice(plainStart, i), className: null })\n }\n tokens.push({ text: text.slice(i, end + 1), className: 'rmx-syn-italic' })\n i = end + 1\n plainStart = i\n continue\n }\n }\n\n i++\n }\n\n // Remaining plain text\n if (plainStart < len) {\n tokens.push({ text: text.slice(plainStart), className: null })\n }\n}\n","import { useRef, useMemo, useCallback, useState, useEffect } from 'react'\nimport { highlightHTML } from './highlightHTML.js'\nimport { highlightMarkdown } from './highlightMarkdown.js'\nimport './CodeEditor.css'\n\nconst HIGHLIGHT_DEBOUNCE_MS = 150\n\nexport function CodeEditor({ value, onChange, language = 'html' }) {\n const textareaRef = useRef(null)\n const preRef = useRef(null)\n const gutterRef = useRef(null)\n const highlightTimerRef = useRef(null)\n\n // Debounced value for highlighting — delays expensive tokenization\n const [debouncedValue, setDebouncedValue] = useState(value || '')\n\n useEffect(() => {\n highlightTimerRef.current = setTimeout(() => {\n setDebouncedValue(value || '')\n }, HIGHLIGHT_DEBOUNCE_MS)\n return () => clearTimeout(highlightTimerRef.current)\n }, [value])\n\n // Tokenize the debounced source for highlighting\n const highlighted = useMemo(() => {\n const highlighter = language === 'markdown' ? highlightMarkdown : highlightHTML\n return highlighter(debouncedValue)\n }, [debouncedValue, language])\n\n // Count lines for the gutter\n const lineCount = useMemo(() => {\n return (value || '').split('\\n').length\n }, [value])\n\n // Sync scroll between textarea, pre, and gutter\n const handleScroll = useCallback(() => {\n const ta = textareaRef.current\n if (!ta) return\n if (preRef.current) {\n preRef.current.scrollTop = ta.scrollTop\n preRef.current.scrollLeft = ta.scrollLeft\n }\n if (gutterRef.current) {\n gutterRef.current.scrollTop = ta.scrollTop\n }\n }, [])\n\n // Tab key inserts 2 spaces\n const handleKeyDown = useCallback((e) => {\n if (e.key === 'Tab') {\n e.preventDefault()\n const ta = e.target\n const start = ta.selectionStart\n const end = ta.selectionEnd\n // Use setRangeText to insert text while preserving undo stack\n if (typeof ta.setRangeText === 'function') {\n ta.setRangeText(' ', start, end, 'end')\n ta.dispatchEvent(new Event('input', { bubbles: true }))\n } else {\n const newValue = value.substring(0, start) + ' ' + value.substring(end)\n onChange(newValue)\n requestAnimationFrame(() => {\n ta.selectionStart = ta.selectionEnd = start + 2\n })\n }\n }\n }, [value, onChange])\n\n return (\n <div className=\"rmx-code-editor\">\n {/* Line number gutter */}\n <div ref={gutterRef} className=\"rmx-code-gutter\" aria-hidden=\"true\">\n {Array.from({ length: lineCount }, (_, i) => (\n <div key={i} className=\"rmx-code-line-number\">{i + 1}</div>\n ))}\n </div>\n\n {/* Editor body: highlighted pre + transparent textarea */}\n <div className=\"rmx-code-body\">\n <pre ref={preRef} className=\"rmx-code-highlight\" aria-hidden=\"true\">\n <code>\n {highlighted.map((token, i) =>\n token.className\n ? <span key={i} className={token.className}>{token.text}</span>\n : token.text\n )}\n {'\\n'}\n </code>\n </pre>\n\n <textarea\n ref={textareaRef}\n className=\"rmx-code-input\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onScroll={handleScroll}\n onKeyDown={handleKeyDown}\n spellCheck={false}\n autoCapitalize=\"off\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n data-gramm=\"false\"\n />\n </div>\n </div>\n )\n}\n","import { useState, useEffect, useRef, useCallback } from 'react'\nimport PropTypes from 'prop-types'\nimport { ModalOverlay } from './ModalOverlay.jsx'\nimport { CodeEditor } from './CodeEditor/CodeEditor.jsx'\nimport { htmlToMarkdown, markdownToHtml, formatHTML } from '@remyxjs/core'\n\nexport function SourceModal({ open, onClose, engine }) {\n const [source, setSource] = useState('')\n const [initialSource, setInitialSource] = useState('')\n const isMarkdown = engine?.outputFormat === 'markdown'\n\n useEffect(() => {\n if (open && engine) {\n const html = engine.getHTML()\n const formatted = isMarkdown ? htmlToMarkdown(html) : formatHTML(html)\n setSource(formatted)\n setInitialSource(formatted)\n }\n }, [open, engine, isMarkdown])\n\n const handleApply = () => {\n engine.history.snapshot()\n const rawHtml = isMarkdown ? markdownToHtml(source) : source\n // Re-sanitize user-edited HTML to prevent XSS injection via source mode\n const htmlToApply = engine.sanitizer.sanitize(rawHtml)\n // Notify if sanitizer modified the input (unsafe content was stripped)\n if (htmlToApply !== rawHtml) {\n engine.eventBus.emit('source:sanitized', {\n message: 'Some HTML elements or attributes were removed for security.',\n })\n }\n engine.setHTML(htmlToApply)\n engine.eventBus.emit('content:change')\n onClose()\n }\n\n // #33: Confirm before discarding unsaved changes\n const handleClose = useCallback(() => {\n if (source !== initialSource) {\n const confirmed = window.confirm('You have unsaved changes. Discard them?')\n if (!confirmed) return\n }\n onClose()\n }, [source, initialSource, onClose])\n\n return (\n <ModalOverlay title={isMarkdown ? 'Markdown Source' : 'Source Code'} open={open} onClose={handleClose} width={750}>\n <div className=\"rmx-modal-form\">\n <CodeEditor\n value={source}\n onChange={setSource}\n language={isMarkdown ? 'markdown' : 'html'}\n />\n <div className=\"rmx-modal-actions\">\n <button type=\"button\" className=\"rmx-btn\" onClick={handleClose}>Cancel</button>\n <button type=\"button\" className=\"rmx-btn rmx-btn-primary\" onClick={handleApply}>Apply</button>\n </div>\n </div>\n </ModalOverlay>\n )\n}\n\nSourceModal.propTypes = {\n open: PropTypes.bool.isRequired,\n onClose: PropTypes.func.isRequired,\n engine: PropTypes.object,\n}\n"],"names":["highlightHTML","code","tokens","i","len","length","startsWith","end","indexOf","commentEnd","push","text","slice","className","test","doctypeEnd","parseTag","semi","textEnd","nameStart","wsStart","attrStart","quote","valEnd","valStart","highlightMarkdown","lines","split","inCodeBlock","lineIdx","line","trimStart","markerMatch","match","highlightInline","ulMatch","olMatch","trim","plainStart","closeBracket","closeParen","marker","CodeEditor","value","onChange","language","textareaRef","useRef","preRef","gutterRef","highlightTimerRef","debouncedValue","setDebouncedValue","useState","useEffect","current","setTimeout","clearTimeout","highlighted","useMemo","lineCount","handleScroll","useCallback","ta","scrollTop","scrollLeft","handleKeyDown","e","key","preventDefault","target","start","selectionStart","selectionEnd","setRangeText","dispatchEvent","Event","bubbles","newValue","substring","requestAnimationFrame","jsxs","children","jsx","ref","Array","from","_","map","token","onScroll","onKeyDown","spellCheck","autoCapitalize","autoComplete","autoCorrect","SourceModal","open","onClose","engine","source","setSource","initialSource","setInitialSource","isMarkdown","outputFormat","html","getHTML","formatted","htmlToMarkdown","formatHTML","handleClose","window","confirm","ModalOverlay","title","width","type","onClick","history","snapshot","rawHtml","markdownToHtml","htmlToApply","sanitizer","sanitize","eventBus","emit","message","setHTML","propTypes","PropTypes","bool","isRequired","func","object"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useRef as s,useState as n,useEffect as l,useMemo as c,useCallback as a}from"react";import{P as i}from"./index-C720tbJA.js";import{M as r}from"./ModalOverlay-CLvRNHmp.js";import{htmlToMarkdown as o,formatHTML as m,markdownToHtml as u}from"@remyxjs/core";function x(e){const t=[];let s=0;const n=e.length;for(;s<n;){if("<"===e[s]&&e.startsWith("!--",s+1)){const l=e.indexOf("--\x3e",s+4),c=-1===l?n:l+3;t.push({text:e.slice(s,c),className:"rmx-syn-comment"}),s=c;continue}if("<"===e[s]&&e.startsWith("!",s+1)&&/^<![a-zA-Z]/.test(e.slice(s,s+3))){const l=e.indexOf(">",s),c=-1===l?n:l+1;t.push({text:e.slice(s,c),className:"rmx-syn-doctype"}),s=c;continue}if("<"===e[s]&&("/"===e[s+1]||/[a-zA-Z]/.test(e[s+1]||""))){s=f(e,s,t);continue}if("&"===e[s]){const n=e.indexOf(";",s+1);if(-1!==n&&n-s<12&&/^&[#a-zA-Z0-9]+;$/.test(e.slice(s,n+1))){t.push({text:e.slice(s,n+1),className:"rmx-syn-entity"}),s=n+1;continue}}let l=s+1;for(;l<n&&"<"!==e[l]&&"&"!==e[l];)l++;t.push({text:e.slice(s,l),className:null}),s=l}return t}function f(e,t,s){const n=e.length;"/"===e[t+1]?(s.push({text:"</",className:"rmx-syn-tag"}),t+=2):(s.push({text:"<",className:"rmx-syn-tag"}),t+=1);let l=t;for(;t<n&&/[a-zA-Z0-9:-]/.test(e[t]);)t++;for(t>l&&s.push({text:e.slice(l,t),className:"rmx-syn-tag"});t<n;){if(/\s/.test(e[t])){let l=t;for(;t<n&&/\s/.test(e[t]);)t++;s.push({text:e.slice(l,t),className:null});continue}if("/"===e[t]&&">"===e[t+1])return s.push({text:"/>",className:"rmx-syn-tag"}),t+2;if(">"===e[t])return s.push({text:">",className:"rmx-syn-tag"}),t+1;let l=t;for(;t<n&&/[^\s=/>]/.test(e[t]);)t++;for(t>l&&s.push({text:e.slice(l,t),className:"rmx-syn-attr-name"});t<n&&/\s/.test(e[t]);)s.push({text:e[t],className:null}),t++;if(t<n&&"="===e[t]){for(s.push({text:"=",className:null}),t++;t<n&&/\s/.test(e[t]);)s.push({text:e[t],className:null}),t++;if(t<n&&('"'===e[t]||"'"===e[t])){const l=e[t],c=e.indexOf(l,t+1),a=-1===c?n:c+1;s.push({text:e.slice(t,a),className:"rmx-syn-attr-value"}),t=a}else{let l=t;for(;t<n&&/[^\s>]/.test(e[t]);)t++;t>l&&s.push({text:e.slice(l,t),className:"rmx-syn-attr-value"})}}}return t}function h(e){const t=e.split("\n"),s=[];let n=!1;for(let l=0;l<t.length;l++){const e=t[l];if(l>0&&s.push({text:"\n",className:null}),/^```/.test(e.trimStart())){s.push({text:e,className:"rmx-syn-code-fence"}),n=!n;continue}if(n){s.push({text:e,className:"rmx-syn-code"});continue}if(/^#{1,6}\s/.test(e)){s.push({text:e,className:"rmx-syn-heading"});continue}if(/^(\s*)([-*_])\2{2,}\s*$/.test(e)){s.push({text:e,className:"rmx-syn-hr"});continue}if(/^>\s?/.test(e)){const t=e.match(/^(>\s?)/);s.push({text:t[0],className:"rmx-syn-blockquote"}),p(e.slice(t[0].length),s);continue}const c=e.match(/^(\s*[-*+]\s+)/);if(c){s.push({text:c[0],className:"rmx-syn-list-marker"}),p(e.slice(c[0].length),s);continue}const a=e.match(/^(\s*\d+[.)]\s+)/);a?(s.push({text:a[0],className:"rmx-syn-list-marker"}),p(e.slice(a[0].length),s)):/^\|[\s:|-]+\|$/.test(e.trim())?s.push({text:e,className:"rmx-syn-hr"}):p(e,s)}return s}function p(e,t){let s=0;const n=e.length;let l=0;for(;s<n;){if("`"===e[s]){s>l&&t.push({text:e.slice(l,s),className:null});const n=e.indexOf("`",s+1);if(-1!==n){t.push({text:e.slice(s,n+1),className:"rmx-syn-code"}),s=n+1,l=s;continue}}if("!"===e[s]&&"["===e[s+1]){const n=e.indexOf("]",s+2);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,c+1),className:"rmx-syn-image"}),s=c+1,l=s;continue}}}if("["===e[s]){const n=e.indexOf("]",s+1);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,n+1),className:"rmx-syn-link"}),t.push({text:e.slice(n+1,c+1),className:"rmx-syn-url"}),s=c+1,l=s;continue}}}if("*"===e[s]&&"*"===e[s+1]||"_"===e[s]&&"_"===e[s+1]){const n=e.slice(s,s+2),c=e.indexOf(n,s+2);if(-1!==c){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,c+2),className:"rmx-syn-bold"}),s=c+2,l=s;continue}}if(("*"===e[s]||"_"===e[s])&&e[s+1]!==e[s]){const n=e[s],c=e.indexOf(n,s+1);if(-1!==c&&c>s+1){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,c+1),className:"rmx-syn-italic"}),s=c+1,l=s;continue}}s++}l<n&&t.push({text:e.slice(l),className:null})}function d({value:i,onChange:r,language:o="html"}){const m=s(null),u=s(null),f=s(null),p=s(null),[d,N]=n(i||"");l((()=>(p.current=setTimeout((()=>{N(i||"")}),150),()=>clearTimeout(p.current))),[i]);const y=c((()=>("markdown"===o?h:x)(d)),[d,o]),g=c((()=>(i||"").split("\n").length),[i]),v=a((()=>{const e=m.current;e&&(u.current&&(u.current.scrollTop=e.scrollTop,u.current.scrollLeft=e.scrollLeft),f.current&&(f.current.scrollTop=e.scrollTop))}),[]),b=a((e=>{if("Tab"===e.key){e.preventDefault();const t=e.target,s=t.selectionStart,n=t.selectionEnd;if("function"==typeof t.setRangeText)t.setRangeText(" ",s,n,"end"),t.dispatchEvent(new Event("input",{bubbles:!0}));else{const e=i.substring(0,s)+" "+i.substring(n);r(e),requestAnimationFrame((()=>{t.selectionStart=t.selectionEnd=s+2}))}}}),[i,r]);/* @__PURE__ */
1
+ import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useRef as s,useState as n,useEffect as l,useMemo as c,useCallback as a}from"react";import{P as i}from"./index-DL-qBZZU.js";import{M as r}from"./ModalOverlay-Dt0JiW3M.js";import{htmlToMarkdown as o,formatHTML as m,markdownToHtml as u}from"@remyxjs/core";function x(e){const t=[];let s=0;const n=e.length;for(;s<n;){if("<"===e[s]&&e.startsWith("!--",s+1)){const l=e.indexOf("--\x3e",s+4),c=-1===l?n:l+3;t.push({text:e.slice(s,c),className:"rmx-syn-comment"}),s=c;continue}if("<"===e[s]&&e.startsWith("!",s+1)&&/^<![a-zA-Z]/.test(e.slice(s,s+3))){const l=e.indexOf(">",s),c=-1===l?n:l+1;t.push({text:e.slice(s,c),className:"rmx-syn-doctype"}),s=c;continue}if("<"===e[s]&&("/"===e[s+1]||/[a-zA-Z]/.test(e[s+1]||""))){s=f(e,s,t);continue}if("&"===e[s]){const n=e.indexOf(";",s+1);if(-1!==n&&n-s<12&&/^&[#a-zA-Z0-9]+;$/.test(e.slice(s,n+1))){t.push({text:e.slice(s,n+1),className:"rmx-syn-entity"}),s=n+1;continue}}let l=s+1;for(;l<n&&"<"!==e[l]&&"&"!==e[l];)l++;t.push({text:e.slice(s,l),className:null}),s=l}return t}function f(e,t,s){const n=e.length;"/"===e[t+1]?(s.push({text:"</",className:"rmx-syn-tag"}),t+=2):(s.push({text:"<",className:"rmx-syn-tag"}),t+=1);let l=t;for(;t<n&&/[a-zA-Z0-9:-]/.test(e[t]);)t++;for(t>l&&s.push({text:e.slice(l,t),className:"rmx-syn-tag"});t<n;){if(/\s/.test(e[t])){let l=t;for(;t<n&&/\s/.test(e[t]);)t++;s.push({text:e.slice(l,t),className:null});continue}if("/"===e[t]&&">"===e[t+1])return s.push({text:"/>",className:"rmx-syn-tag"}),t+2;if(">"===e[t])return s.push({text:">",className:"rmx-syn-tag"}),t+1;let l=t;for(;t<n&&/[^\s=/>]/.test(e[t]);)t++;for(t>l&&s.push({text:e.slice(l,t),className:"rmx-syn-attr-name"});t<n&&/\s/.test(e[t]);)s.push({text:e[t],className:null}),t++;if(t<n&&"="===e[t]){for(s.push({text:"=",className:null}),t++;t<n&&/\s/.test(e[t]);)s.push({text:e[t],className:null}),t++;if(t<n&&('"'===e[t]||"'"===e[t])){const l=e[t],c=e.indexOf(l,t+1),a=-1===c?n:c+1;s.push({text:e.slice(t,a),className:"rmx-syn-attr-value"}),t=a}else{let l=t;for(;t<n&&/[^\s>]/.test(e[t]);)t++;t>l&&s.push({text:e.slice(l,t),className:"rmx-syn-attr-value"})}}}return t}function h(e){const t=e.split("\n"),s=[];let n=!1;for(let l=0;l<t.length;l++){const e=t[l];if(l>0&&s.push({text:"\n",className:null}),/^```/.test(e.trimStart())){s.push({text:e,className:"rmx-syn-code-fence"}),n=!n;continue}if(n){s.push({text:e,className:"rmx-syn-code"});continue}if(/^#{1,6}\s/.test(e)){s.push({text:e,className:"rmx-syn-heading"});continue}if(/^(\s*)([-*_])\2{2,}\s*$/.test(e)){s.push({text:e,className:"rmx-syn-hr"});continue}if(/^>\s?/.test(e)){const t=e.match(/^(>\s?)/);s.push({text:t[0],className:"rmx-syn-blockquote"}),p(e.slice(t[0].length),s);continue}const c=e.match(/^(\s*[-*+]\s+)/);if(c){s.push({text:c[0],className:"rmx-syn-list-marker"}),p(e.slice(c[0].length),s);continue}const a=e.match(/^(\s*\d+[.)]\s+)/);a?(s.push({text:a[0],className:"rmx-syn-list-marker"}),p(e.slice(a[0].length),s)):/^\|[\s:|-]+\|$/.test(e.trim())?s.push({text:e,className:"rmx-syn-hr"}):p(e,s)}return s}function p(e,t){let s=0;const n=e.length;let l=0;for(;s<n;){if("`"===e[s]){s>l&&t.push({text:e.slice(l,s),className:null});const n=e.indexOf("`",s+1);if(-1!==n){t.push({text:e.slice(s,n+1),className:"rmx-syn-code"}),s=n+1,l=s;continue}}if("!"===e[s]&&"["===e[s+1]){const n=e.indexOf("]",s+2);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,c+1),className:"rmx-syn-image"}),s=c+1,l=s;continue}}}if("["===e[s]){const n=e.indexOf("]",s+1);if(-1!==n&&"("===e[n+1]){const c=e.indexOf(")",n+2);if(-1!==c){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,n+1),className:"rmx-syn-link"}),t.push({text:e.slice(n+1,c+1),className:"rmx-syn-url"}),s=c+1,l=s;continue}}}if("*"===e[s]&&"*"===e[s+1]||"_"===e[s]&&"_"===e[s+1]){const n=e.slice(s,s+2),c=e.indexOf(n,s+2);if(-1!==c){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,c+2),className:"rmx-syn-bold"}),s=c+2,l=s;continue}}if(("*"===e[s]||"_"===e[s])&&e[s+1]!==e[s]){const n=e[s],c=e.indexOf(n,s+1);if(-1!==c&&c>s+1){s>l&&t.push({text:e.slice(l,s),className:null}),t.push({text:e.slice(s,c+1),className:"rmx-syn-italic"}),s=c+1,l=s;continue}}s++}l<n&&t.push({text:e.slice(l),className:null})}function d({value:i,onChange:r,language:o="html"}){const m=s(null),u=s(null),f=s(null),p=s(null),[d,N]=n(i||"");l((()=>(p.current=setTimeout((()=>{N(i||"")}),150),()=>clearTimeout(p.current))),[i]);const y=c((()=>("markdown"===o?h:x)(d)),[d,o]),g=c((()=>(i||"").split("\n").length),[i]),v=a((()=>{const e=m.current;e&&(u.current&&(u.current.scrollTop=e.scrollTop,u.current.scrollLeft=e.scrollLeft),f.current&&(f.current.scrollTop=e.scrollTop))}),[]),b=a((e=>{if("Tab"===e.key){e.preventDefault();const t=e.target,s=t.selectionStart,n=t.selectionEnd;if("function"==typeof t.setRangeText)t.setRangeText(" ",s,n,"end"),t.dispatchEvent(new Event("input",{bubbles:!0}));else{const e=i.substring(0,s)+" "+i.substring(n);r(e),requestAnimationFrame((()=>{t.selectionStart=t.selectionEnd=s+2}))}}}),[i,r]);/* @__PURE__ */
2
2
  return e("div",{className:"rmx-code-editor",children:[
3
3
  /* @__PURE__ */t("div",{ref:f,className:"rmx-code-gutter","aria-hidden":"true",children:Array.from({length:g},((e,s)=>/* @__PURE__ */t("div",{className:"rmx-code-line-number",children:s+1},s)))}),
4
4
  /* @__PURE__ */e("div",{className:"rmx-code-body",children:[
@@ -9,4 +9,4 @@ return t(r,{title:N?"Markdown Source":"Source Code",open:s,onClose:y,width:750,c
9
9
  /* @__PURE__ */e("div",{className:"rmx-modal-actions",children:[
10
10
  /* @__PURE__ */t("button",{type:"button",className:"rmx-btn",onClick:y,children:"Cancel"}),
11
11
  /* @__PURE__ */t("button",{type:"button",className:"rmx-btn rmx-btn-primary",onClick:()=>{i.history.snapshot();const e=N?u(x):x,t=i.sanitizer.sanitize(e);t!==e&&i.eventBus.emit("source:sanitized",{message:"Some HTML elements or attributes were removed for security."}),i.setHTML(t),i.eventBus.emit("content:change"),c()},children:"Apply"})]})]})})}N.propTypes={open:i.bool.isRequired,onClose:i.func.isRequired,engine:i.object};export{N as SourceModal};
12
- //# sourceMappingURL=SourceModal-MdTGK3Uf.js.map
12
+ //# sourceMappingURL=SourceModal-ChhNVz7y.js.map