@jbpark/live-editor 4.6.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.ko.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/{boundary-BLB80tyw.js → boundary-6_nTsWxP.js} +2 -2
  4. package/dist/{boundary-BLB80tyw.js.map → boundary-6_nTsWxP.js.map} +1 -1
  5. package/dist/{compile-Dxas-D05.js → compile-DwOyWrmI.js} +8 -7
  6. package/dist/compile-DwOyWrmI.js.map +1 -0
  7. package/dist/constants-D-XKuEY2.js +58 -0
  8. package/dist/constants-D-XKuEY2.js.map +1 -0
  9. package/dist/{context-B8MzP7_p.js → context-DDR1xVKo.js} +3 -3
  10. package/dist/{context-B8MzP7_p.js.map → context-DDR1xVKo.js.map} +1 -1
  11. package/dist/{core-Bgfek364.js → core-CKazr4tT.js} +2 -2
  12. package/dist/core-CKazr4tT.js.map +1 -0
  13. package/dist/{detect-typescript-Dr_oLniM.js → detect-typescript-CoAO-QUJ.js} +2 -2
  14. package/dist/{detect-typescript-Dr_oLniM.js.map → detect-typescript-CoAO-QUJ.js.map} +1 -1
  15. package/dist/dnd/index.d.ts +2 -2
  16. package/dist/dnd/index.js +2 -2
  17. package/dist/dnd-BlC1gqUy.js +4446 -0
  18. package/dist/dnd-BlC1gqUy.js.map +1 -0
  19. package/dist/document-BQhb7YR8.d.ts +17 -0
  20. package/dist/document-DcwIEHRV.js +34077 -0
  21. package/dist/document-DcwIEHRV.js.map +1 -0
  22. package/dist/editor/index.js +2 -2
  23. package/dist/{editor-CMElfHer.js → editor-Bty5XzpV.js} +2 -2
  24. package/dist/{editor-CMElfHer.js.map → editor-Bty5XzpV.js.map} +1 -1
  25. package/dist/error/index.d.ts +1 -1
  26. package/dist/error/index.js +2 -2
  27. package/dist/{error-CN_GCnXB.js → error-DyYx2NQ2.js} +17 -31
  28. package/dist/error-DyYx2NQ2.js.map +1 -0
  29. package/dist/{index-C69Lv-jR.d.ts → index-0VB5C3Jk.d.ts} +28 -50
  30. package/dist/{index-DpDU1IAw.d.ts → index-92L7F440.d.ts} +2 -2
  31. package/dist/index-C8h8TcIl.d.ts +15 -0
  32. package/dist/{index-DQkL37eL.d.ts → index-Cl79M7ZJ.d.ts} +6 -4
  33. package/dist/{index-CRwEhJ7w.d.ts → index-kKUjo9lr.d.ts} +2 -2
  34. package/dist/{index-DrWtSKXu.d.ts → index-tAiuHZsC.d.ts} +2 -2
  35. package/dist/index.d.ts +9 -9
  36. package/dist/index.js +6 -6
  37. package/dist/index.js.map +1 -1
  38. package/dist/{messages-CSrMI4Rm.js → messages-Bt5WXKTE.js} +5 -2
  39. package/dist/messages-Bt5WXKTE.js.map +1 -0
  40. package/dist/{messages-IBPs4TkZ.d.ts → messages-Yb3b7YJt.d.ts} +5 -2
  41. package/dist/preview/index.d.ts +1 -1
  42. package/dist/preview/index.js +2 -2
  43. package/dist/{preview-CtyG5UbH.js → preview-DC0pyOdu.js} +4 -4
  44. package/dist/preview-DC0pyOdu.js.map +1 -0
  45. package/dist/provider/index.d.ts +2 -2
  46. package/dist/provider/index.js +2 -2
  47. package/dist/{sections-BYWOBISr.js → sections-4uirsXRU.js} +4 -7
  48. package/dist/sections-4uirsXRU.js.map +1 -0
  49. package/dist/style.css +776 -346
  50. package/dist/{validate-DB59Z_Nx.d.ts → types-Czps1Txy.d.ts} +12 -28
  51. package/dist/update-2PJbwoS8.d.ts +68 -0
  52. package/dist/{items-B6OXxcLG.js → update-DNInQSM7.js} +261 -512
  53. package/dist/update-DNInQSM7.js.map +1 -0
  54. package/dist/{use-dynamic-tailwind-BP1toJkW.js → use-dynamic-tailwind-CSYKXDmX.js} +301 -273
  55. package/dist/use-dynamic-tailwind-CSYKXDmX.js.map +1 -0
  56. package/dist/utils/ast/index.d.ts +47 -4
  57. package/dist/utils/ast/index.js +15 -77
  58. package/dist/utils/ast/index.js.map +1 -1
  59. package/dist/utils/index.d.ts +13 -32
  60. package/dist/utils/index.js +4 -26
  61. package/dist/validate-CZz30Pnb.js +122 -0
  62. package/dist/validate-CZz30Pnb.js.map +1 -0
  63. package/dist/validate-CiA1LF6S.d.ts +33 -0
  64. package/package.json +13 -15
  65. package/dist/compile-Dxas-D05.js.map +0 -1
  66. package/dist/constants-DU17Tdwo.js +0 -1459
  67. package/dist/constants-DU17Tdwo.js.map +0 -1
  68. package/dist/core-Bgfek364.js.map +0 -1
  69. package/dist/dnd-UoJILA75.js +0 -2756
  70. package/dist/dnd-UoJILA75.js.map +0 -1
  71. package/dist/document-CGbe6bSV.js +0 -38667
  72. package/dist/document-CGbe6bSV.js.map +0 -1
  73. package/dist/document-Ct4jW78J.d.ts +0 -1553
  74. package/dist/error-CN_GCnXB.js.map +0 -1
  75. package/dist/index-DKYUxi-E.d.ts +0 -227
  76. package/dist/items-B6OXxcLG.js.map +0 -1
  77. package/dist/messages-CSrMI4Rm.js.map +0 -1
  78. package/dist/preview-CtyG5UbH.js.map +0 -1
  79. package/dist/sections-BYWOBISr.js.map +0 -1
  80. package/dist/use-dynamic-tailwind-BP1toJkW.js.map +0 -1
  81. package/dist/utils/index.js.map +0 -1
  82. package/dist/validate-iLo8IONY.js +0 -64
  83. package/dist/validate-iLo8IONY.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"messages-CSrMI4Rm.js","names":[],"sources":["../src/components/context/messages.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\n\nimport {\n type ValidationMessages,\n defaultValidationMessages,\n} from '~/utils/ast/validate';\n\n// Every piece of text the editor shows or announces, grouped by where it\n// appears (#524). Text with values in it is a function, so a translation\n// can put them where its grammar needs them. Pass a partial set to `Live`'s\n// `messages` prop to replace any of it; the rest stays English.\nexport interface LiveMessages {\n // The section toolbar on the canvas and the panel header.\n section: {\n moveUp: string;\n moveDown: string;\n duplicate: string;\n delete: string;\n };\n canvas: {\n // The mobile palette button and Drawer title.\n palette: string;\n // The mobile panel Drawer title.\n properties: string;\n pickElement: string;\n pickElementActive: string;\n dropHere: string;\n dropAtBottom: string;\n empty: string;\n emptyHintTouch: string;\n emptyHintDrag: string;\n syntaxError: string;\n syntaxErrorDetail: string;\n missingContainer: (containerId: string) => string;\n missingContainerDetail: (containerId: string) => string;\n stale: string;\n };\n panel: {\n selectSection: string;\n noEditableElements: string;\n readOnly: string;\n expressionPreserved: string;\n useCodeEditor: string;\n invalidValue: string;\n urlPlaceholder: string;\n numberPlaceholder: string;\n textPlaceholder: string;\n };\n // The built-in editor for an array value.\n items: {\n heading: (count: number) => string;\n add: string;\n item: (position: number) => string;\n reorder: (item: string) => string;\n moveUp: string;\n moveDown: string;\n delete: string;\n collapseAll: string;\n expandAll: string;\n unreadable: string;\n empty: string;\n structureLocked: string;\n noNestedBindings: string;\n };\n // The built-in editor for child elements.\n children: {\n heading: (count: number) => string;\n add: string;\n child: (position: number, tagName: string) => string;\n moveUp: string;\n moveDown: string;\n delete: string;\n editableBindings: string;\n childNodes: string;\n };\n // The bar shown while items or children are selected.\n selection: {\n count: (count: number) => string;\n duplicate: string;\n moveUp: string;\n moveDown: string;\n delete: string;\n clear: string;\n };\n // The `title` and `description` of a `DndEditError`, which the default\n // toast shows.\n editErrors: {\n updateFailed: (label: string) => string;\n cannotEdit: (label: string) => string;\n cannotRemove: (label: string) => string;\n attributeNotFound: (property: string) => string;\n // `property` is set when the binding names one, otherwise `label` is the\n // one to show.\n bindingNotDeclared: (target: {\n label: string;\n property?: string;\n }) => string;\n duplicateBinding: (target: {\n count: number;\n label: string;\n property?: string;\n }) => string;\n reservedProperty: (property: string) => string;\n requiredProperty: (property: string) => string;\n noBinding: string;\n elementNotFound: string;\n unsupportedSyntax: (property: string) => string;\n selfClosing: (property: string) => string;\n checkConsole: string;\n syntaxError: string;\n syntaxErrorDetail: string;\n missingContainer: (containerId: string) => string;\n missingContainerDetail: (containerId: string) => string;\n sectionParseFailed: string;\n itemsParseFailed: string;\n itemUpdateFailed: string;\n itemUpdateFailedDetail: string;\n };\n // What a screen reader hears during a drag.\n announcements: {\n instructions: string;\n // Stands in for a section without a name.\n section: string;\n pickedUp: (name: string) => string;\n movedTo: (name: string, position: number, total: number) => string;\n notOver: (name: string) => string;\n droppedAt: (name: string, position: number, total: number) => string;\n dropped: (name: string) => string;\n cancelled: (name: string) => string;\n itemOver: (name: string, over: string) => string;\n itemMoved: (name: string, over: string) => string;\n };\n // The error boxes of `Live.Preview`, `Live.Error` and canvas sections.\n errors: {\n default: string;\n compile: string;\n runtime: string;\n rendering: string;\n sectionUnavailable: string;\n sectionNotRendered: string;\n tryAgain: string;\n // The message of a page error that carries none.\n unknown: string;\n // The message of an unhandled promise rejection that carries none.\n unhandledRejection: string;\n };\n validation: ValidationMessages;\n}\n\n// Every group of `LiveMessages`, each with any of its keys.\nexport type LiveMessagesInput = {\n [Group in keyof LiveMessages]?: Partial<LiveMessages[Group]>;\n};\n\nexport const defaultMessages: LiveMessages = {\n section: {\n moveUp: 'Move section up',\n moveDown: 'Move section down',\n duplicate: 'Duplicate section',\n delete: 'Delete section',\n },\n canvas: {\n palette: 'Components',\n properties: 'Properties',\n pickElement: 'Pick an element',\n pickElementActive: 'Click an element to edit it. Esc to cancel.',\n dropHere: 'Drop here',\n dropAtBottom: 'Drag here to add at bottom',\n empty: 'No sections available',\n emptyHintTouch: 'Tap a component to add it',\n emptyHintDrag: 'Drag a component from the left to add it',\n syntaxError: 'The document has a syntax error',\n syntaxErrorDetail: 'Fix it in the code to see its sections',\n missingContainer: containerId =>\n `No #${containerId} element in the document`,\n missingContainerDetail: containerId =>\n `Sections go inside the element with id=\"${containerId}\"`,\n stale:\n 'Showing the last version that parsed. Fix the syntax error in the code to edit here again.',\n },\n panel: {\n selectSection: 'Please select a section.',\n noEditableElements: 'No editable elements.',\n readOnly:\n \"The document has a syntax error. These fields are from the last version that parsed, and can't be edited until it parses again.\",\n expressionPreserved:\n 'This expression is preserved but is not editable here.',\n useCodeEditor: 'Use the code editor to change it.',\n invalidValue: 'Invalid value.',\n urlPlaceholder: 'https://example.com',\n numberPlaceholder: 'Enter a numeric value',\n textPlaceholder: 'Enter a value',\n },\n items: {\n heading: count => `Items (${count})`,\n add: 'Add Item',\n item: position => `Item ${position}`,\n reorder: item => `Reorder ${item}`,\n moveUp: 'Move item up',\n moveDown: 'Move item down',\n delete: 'Delete item',\n collapseAll: 'Collapse all',\n expandAll: 'Expand all',\n unreadable:\n 'This value could not be read as a list. Edit it in the code editor.',\n empty:\n 'No editable items. The panel copies an existing item rather than guessing the shape of a new one — add the first item in the code editor.',\n structureLocked:\n 'Values remain editable, but moving, copying, adding, and deleting require a dense array without spreads or parenthesized top-level items. Use the code editor for those structural changes.',\n noNestedBindings: 'No JSX bindings found',\n },\n children: {\n heading: count => `Children Items (${count})`,\n add: 'Add Child',\n child: (position, tagName) => `Child ${position} (${tagName})`,\n moveUp: 'Move child up',\n moveDown: 'Move child down',\n delete: 'Delete child',\n editableBindings: 'Editable Bindings:',\n childNodes: 'Child Nodes:',\n },\n selection: {\n count: count => `${count} selected`,\n duplicate: 'Duplicate selected',\n moveUp: 'Move selected up',\n moveDown: 'Move selected down',\n delete: 'Delete selected',\n clear: 'Clear',\n },\n editErrors: {\n updateFailed: label => `Failed to update \"${label}\"`,\n cannotEdit: label => `Cannot edit \"${label}\" in the panel`,\n cannotRemove: label => `Cannot remove \"${label}\"`,\n attributeNotFound: property =>\n `This element has no \"${property}\" attribute — check the property in its data-binding.`,\n bindingNotDeclared: ({ label, property }) =>\n `No binding for ${\n property ? `property \"${property}\"` : `label \"${label}\"`\n } is declared on this element's data-binding.`,\n duplicateBinding: ({ count, label, property }) =>\n `${count} bindings share ${\n property ? `property \"${property}\"` : `label \"${label}\"`\n } on this element — remove the duplicate in its data-binding.`,\n reservedProperty: property =>\n `\"${property}\" is managed by the editor, so a binding can't change it.`,\n requiredProperty: property =>\n `\"${property}\" is marked required in its data-binding, so it can't be removed.`,\n noBinding: 'This element has no data-binding declaration.',\n elementNotFound: 'The target element could not be found in this section.',\n unsupportedSyntax: property =>\n `The \"${property}\" expression was preserved. Change it in the code editor instead.`,\n selfClosing: property =>\n `This element is self-closing, so it has no content for \"${property}\". Give it a closing tag in the code editor.`,\n checkConsole: 'Check the console for details.',\n syntaxError: 'The document has a syntax error',\n syntaxErrorDetail:\n 'The canvas shows the last version that parsed. Fix the error in the code, then edit here again.',\n missingContainer: containerId =>\n `No #${containerId} element in the document`,\n missingContainerDetail: containerId =>\n `Sections are the <section> elements inside the element with id=\"${containerId}\". Start from createDocument(), or set containerId to match your document.`,\n sectionParseFailed: 'Failed to parse this section',\n itemsParseFailed: 'Failed to parse items',\n itemUpdateFailed: 'Failed to update this item',\n itemUpdateFailedDetail:\n 'The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax.',\n },\n announcements: {\n instructions:\n 'On a palette item, press Enter to add it to the canvas. On a canvas section, press Enter to select it, the up and down arrow keys to go to the previous or next section, and Delete to remove it. Press Space to pick a section up, the arrow keys to move it, and Space or Enter to drop it. Press Escape to cancel.',\n section: 'section',\n pickedUp: name => `Picked up ${name}.`,\n movedTo: (name, position, total) =>\n `${name} moved to position ${position} of ${total}.`,\n notOver: name => `${name} is no longer over a position.`,\n droppedAt: (name, position, total) =>\n `${name} dropped at position ${position} of ${total}.`,\n dropped: name => `${name} dropped.`,\n cancelled: name => `Moving ${name} was cancelled.`,\n itemOver: (name, over) => `${name} is over ${over}.`,\n itemMoved: (name, over) => `${name} was moved to the place of ${over}.`,\n },\n errors: {\n default: 'An error occurred',\n compile: 'Compile Error',\n runtime: 'Runtime Error',\n rendering: 'Rendering Error',\n sectionUnavailable: 'Section Unavailable',\n sectionNotRendered: 'This section is not rendered in this editor.',\n tryAgain: 'Try Again',\n unknown: 'Unknown error',\n unhandledRejection: 'Unhandled promise rejection',\n },\n validation: defaultValidationMessages,\n};\n\n// `base` (the defaults, unless given) with each group's given keys on top.\nexport const mergeMessages = (\n input?: LiveMessagesInput,\n base: LiveMessages = defaultMessages,\n): LiveMessages => {\n if (!input) {\n return base;\n }\n\n const merged = { ...base };\n\n for (const group of Object.keys(base) as (keyof LiveMessages)[]) {\n if (input[group]) {\n merged[group] = { ...base[group], ...input[group] } as never;\n }\n }\n\n return merged;\n};\n\n// The English defaults outside a provider, so an error box rendered on its\n// own still has text.\nexport const MessagesContext = createContext<LiveMessages>(defaultMessages);\n\n// The messages in effect: the provider's, merged over the defaults. A custom\n// palette or panel can use it to show the same text as the built-in ones.\nexport const useLiveMessages = () => useContext(MessagesContext);\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"preview-CtyG5UbH.js","names":["LiveError"],"sources":["../src/components/preview/defaults.ts","../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["// Stable defaults for optional object props. A `= {}` default is a new\n// object on every render, which re-runs every memo keyed on it — the merged\n// module map, and so `compile()` — even when the caller passed nothing (#348).\nexport const NO_PROPS: Record<string, unknown> = {};\nexport const NO_MODULES: Record<string, unknown> = {};\n","'use client';\n\nimport { useMemo } from 'react';\n\nimport { useLiveMessages } from '~/components/context/messages';\nimport { useError, usePreview } from '~/components/context/states';\nimport LiveError from '~/components/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { cn } from '~/utils/cn';\n\nimport { NO_MODULES, NO_PROPS } from './defaults';\nimport { type Props } from './preview';\nimport { useCompiledModule } from './use-compiled-module';\nimport { useDynamicTailwind } from './use-dynamic-tailwind';\n\nconst Client = ({\n code: _code,\n className,\n showError,\n props = NO_PROPS,\n modules = NO_MODULES,\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n const { code } = usePreview();\n const { error, setError } = useError();\n const messages = useLiveMessages();\n const isError = !!showError && !!error;\n\n const classNames = cn(isError && 'hidden', className);\n\n const effectiveCode = _code === undefined ? code : _code;\n\n const module = useCompiledModule(effectiveCode, modules);\n\n // Attached to the wrapper below; scans the rendered DOM so classes coming\n // from an imported component are picked up too. See the hook for details.\n const { ref: contentRef, css: dynamicCSS } = useDynamicTailwind(\n effectiveCode,\n dynamicTailwind,\n );\n\n const componentProps = useMemo(\n () => ({\n ...props,\n }),\n [props],\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n if (module && module.error) {\n return (\n <>\n <div className={cn('relative h-full w-full', classNames)}>\n <LiveError message={module.error} title={messages.errors.compile} />\n </div>\n <LiveError.Runtime open={isError} />\n </>\n );\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <>\n {frame ? (\n <div className={cn('h-full w-full', classNames)}>\n <Frame {...(frame as FrameProps)}>\n {container => (\n <div ref={contentRef} style={{ display: 'contents' }}>\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={(e: Error) => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} container={container} />\n {dynamicTailwind && dynamicCSS && (\n <style>{dynamicCSS}</style>\n )}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n </Frame>\n </div>\n ) : (\n <div\n ref={contentRef}\n className={cn(\n 'relative h-full w-full overflow-x-hidden overflow-y-auto',\n classNames,\n )}\n style={{\n isolation: 'isolate',\n transform: 'translateZ(0)',\n containerType: 'inline-size',\n }}\n >\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={e => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n <LiveError.Runtime open={isError} />\n </>\n );\n};\n\nexport default Client;\n","import type React from 'react';\n\nimport type { FrameProps } from '../frame';\nimport Client from './client';\nimport { NO_MODULES, NO_PROPS } from './defaults';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n code?: string;\n showError?: boolean;\n props?: Record<string, unknown>;\n container?: HTMLElement | null;\n frame?: boolean | FrameProps;\n modules?: Record<string, unknown>;\n dynamicTailwind?: boolean;\n provider?: (children: React.ReactNode) => React.ReactNode;\n}\n\n// `Live.Preview`: a thin wrapper around `Client`, which compiles, handles\n// errors and wraps the frame. One render path for both `code` and the\n// provider's code (#187).\nconst Preview = ({\n code,\n props = NO_PROPS,\n modules = NO_MODULES,\n dynamicTailwind = false,\n provider,\n ...restProps\n}: Props) => {\n return (\n <Client\n code={code}\n props={props}\n modules={modules}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...restProps}\n />\n );\n};\n\nexport default Preview;\n"],"mappings":";;;;;;;;AAGA,MAAa,WAAoC,CAAC;AAClD,MAAa,aAAsC,CAAC;;;ACWpD,MAAM,UAAU,EACd,MAAM,OACN,WACA,WACA,QAAQ,UACR,UAAU,YACV,OACA,kBAAkB,OAClB,eACW;CACX,MAAM,EAAE,SAAS,WAAW;CAC5B,MAAM,EAAE,OAAO,aAAa,SAAS;CACrC,MAAM,WAAW,gBAAgB;CACjC,MAAM,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;CAEjC,MAAM,aAAa,GAAG,WAAW,UAAU,SAAS;CAEpD,MAAM,gBAAgB,UAAU,KAAA,IAAY,OAAO;CAEnD,MAAM,SAAS,kBAAkB,eAAe,OAAO;CAIvD,MAAM,EAAE,KAAK,YAAY,KAAK,eAAe,mBAC3C,eACA,eACF;CAEA,MAAM,iBAAiB,eACd,EACL,GAAG,MACL,IACA,CAAC,KAAK,CACR;CAEA,MAAM,kBAAkB,cAA+B;EACrD,OAAO,WAAW,SAAS,SAAS,IAAI;CAC1C;CAEA,IAAI,UAAU,OAAO,OACnB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAW,GAAG,0BAA0B,UAAU;EACrD,UAAA,oBAACA,OAAD;GAAW,SAAS,OAAO;GAAO,OAAO,SAAS,OAAO;EAAU,CAAA;CAChE,CAAA,GACL,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;CAIN,MAAM,YAAY,QAAQ,SAAS;CAEnC,IAAI,CAAC,WACH,OAAO;CAGT,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,QACC,oBAAC,OAAD;EAAK,WAAW,GAAG,iBAAiB,UAAU;EAC5C,UAAA,oBAAC,OAAD;GAAO,GAAK;GACT,WAAA,cACC,oBAAC,OAAD;IAAK,KAAK;IAAY,OAAO,EAAE,SAAS,WAAW;IACjD,UAAA,oBAACA,MAAU,UAAX;KACE,WAAW,CAAC,aAAa;KACzB,UAAU,MAAa,SAAS,EAAE,OAAO;KAExC,UAAA,eACC,qBAACA,MAAU,OAAX;MAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;MAAjD,UAAA,CACE,oBAAC,WAAD;OAAW,GAAI;OAA2B;MAAY,CAAA,GACrD,mBAAmB,cAClB,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAEb;KACnB,CAAA,CAAA;IACkB,CAAA;GACjB,CAAA;EAEF,CAAA;CACJ,CAAA,IAEL,oBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,4DACA,UACF;EACA,OAAO;GACL,WAAW;GACX,WAAW;GACX,eAAe;EACjB;EAEA,UAAA,oBAACA,MAAU,UAAX;GACE,WAAW,CAAC,aAAa;GACzB,UAAS,MAAK,SAAS,EAAE,OAAO;GAE/B,UAAA,eACC,qBAACA,MAAU,OAAX;IAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;IAAjD,UAAA,CACE,oBAAC,WAAD,EAAW,GAAI,eAAiB,CAAA,GAC/B,mBAAmB,cAAc,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAC7C;GACnB,CAAA,CAAA;EACkB,CAAA;CACjB,CAAA,GAEP,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;AAEN;;;ACxGA,MAAM,WAAW,EACf,MACA,QAAQ,UACR,UAAU,YACV,kBAAkB,OAClB,UACA,GAAG,gBACQ;CACX,OACE,oBAAC,QAAD;EACQ;EACC;EACE;EACQ;EACP;EACV,GAAI;CACL,CAAA;AAEL"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sections-BYWOBISr.js","names":[],"sources":["../src/utils/sections.ts"],"sourcesContent":["import { DEFAULT_CONTAINER_ID, documentTemplate } from '~/constants';\nimport type { Section } from '~/types';\n\nimport {\n type DocumentOptions,\n type DocumentProblem,\n type SectionOptions,\n createSectionPreviewCache,\n generateSectionPreview,\n generateSectionPreviews,\n getSections,\n inspectDocument,\n parseDocument,\n replaceDocumentSections,\n} from './ast/document';\n\nexport const extractSections = (\n code: string,\n options?: SectionOptions,\n): Section[] => {\n const doc = parseDocument(code, options);\n\n return doc ? getSections(doc, options) : [];\n};\n\nexport const replaceSections = (\n code: string,\n sections: string[],\n options?: DocumentOptions,\n): string => {\n return replaceDocumentSections(code, sections, options);\n};\n\nexport const generateSection = (\n code: string,\n fullCode: string,\n options?: DocumentOptions,\n) => {\n return generateSectionPreview(fullCode, code, options);\n};\n\n// `generateSection()` for every section, from one parse of `fullCode`. An\n// unchanged section gets the same string as before, so `React.memo` can skip\n// it.\nexport const generateSections = (\n codes: string[],\n fullCode: string,\n options?: DocumentOptions,\n): string[] => {\n return generateSectionPreviews(fullCode, codes, options);\n};\n\n// A new, empty document `Live.Dnd` can add sections to: an `App` component\n// rendering the container element and nothing else. Start a controlled\n// `Live.Dnd` from this rather than an empty string, which has no container,\n// so nothing dropped on the canvas would land anywhere (#449). Pass the same\n// `containerId` you give `Live.Dnd`.\nexport const createDocument = ({\n containerId = DEFAULT_CONTAINER_ID,\n}: DocumentOptions = {}): string => {\n // The id is written into a JSX attribute as-is, so anything that could end\n // the attribute or the tag is refused rather than producing broken source.\n if (!/^[^\\s\"'<>{}]+$/.test(containerId)) {\n throw new Error(\n `createDocument: containerId must be a plain element id, got ${JSON.stringify(containerId)}`,\n );\n }\n\n return documentTemplate(containerId);\n};\n\n// Whether `Live.Dnd` can edit a document: it parses, and it has the\n// container. A host can check one before saving or loading it, and gets the\n// same reasons `Live.Dnd` reports through `onEditError` (#522).\nexport type DocumentCheck = { ok: true } | ({ ok: false } & DocumentProblem);\n\nexport const checkDocument = (\n code: string,\n options?: DocumentOptions,\n): DocumentCheck => {\n const inspection = inspectDocument(code, options);\n\n if (inspection.ok) {\n return { ok: true };\n }\n\n // A copy: the inspection is cached and shared with `Live.Dnd`.\n return { ...inspection };\n};\n\n// `generateSections()` that reuses unchanged previews between calls (#131).\n// Keep one instance per editor, as `Live.Dnd` does.\nexport { createSectionPreviewCache };\nexport type {\n DocumentOptions,\n DocumentProblem,\n SectionOptions,\n SectionPreviewCache,\n} from './ast/document';\n"],"mappings":";;;AAgBA,MAAa,mBACX,MACA,YACc;CACd,MAAM,MAAM,cAAc,MAAM,OAAO;CAEvC,OAAO,MAAM,YAAY,KAAK,OAAO,IAAI,CAAC;AAC5C;AAEA,MAAa,mBACX,MACA,UACA,YACW;CACX,OAAO,wBAAwB,MAAM,UAAU,OAAO;AACxD;AAEA,MAAa,mBACX,MACA,UACA,YACG;CACH,OAAO,uBAAuB,UAAU,MAAM,OAAO;AACvD;AAKA,MAAa,oBACX,OACA,UACA,YACa;CACb,OAAO,wBAAwB,UAAU,OAAO,OAAO;AACzD;AAOA,MAAa,kBAAkB,EAC7B,cAAc,yBACK,CAAC,MAAc;CAGlC,IAAI,CAAC,iBAAiB,KAAK,WAAW,GACpC,MAAM,IAAI,MACR,+DAA+D,KAAK,UAAU,WAAW,GAC3F;CAGF,OAAO,iBAAiB,WAAW;AACrC;AAOA,MAAa,iBACX,MACA,YACkB;CAClB,MAAM,aAAa,gBAAgB,MAAM,OAAO;CAEhD,IAAI,WAAW,IACb,OAAO,EAAE,IAAI,KAAK;CAIpB,OAAO,EAAE,GAAG,WAAW;AACzB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-dynamic-tailwind-BP1toJkW.js","names":[],"sources":["../src/components/preview/use-stable-modules.ts","../src/components/frame/measure.ts","../src/components/frame/style-sync.ts","../src/components/frame/viewport-units.ts","../src/components/frame/iframe.tsx","../src/components/frame/shadow.tsx","../src/components/frame/frame.tsx","../src/components/preview/base-modules.ts","../src/components/preview/use-compiled-module.ts","../src/components/preview/use-dynamic-tailwind.ts"],"sourcesContent":["import { useState } from 'react';\n\ntype Modules = Record<string, unknown> | undefined;\n\n// Same keys, each value the same object. A module is compared by identity,\n// never deeply: a module replaced with a changed object has to recompile\n// (#329). This is also how the compilation cache tells modules apart.\nconst sameModules = (a: Modules, b: Modules): boolean => {\n if (a === b) {\n return true;\n }\n\n if (!a || !b) {\n return false;\n }\n\n const keys = Object.keys(a);\n\n return (\n keys.length === Object.keys(b).length &&\n keys.every(key => Object.hasOwn(b, key) && Object.is(a[key], b[key]))\n );\n};\n\n// Keeps the previous `modules` object while its entries are the same, since\n// hosts usually pass a new inline object every render, which would recompile\n// every section (#397).\nexport const useStableModules = <T extends Modules>(modules: T): T => {\n const [stable, setStable] = useState(modules);\n\n if (sameModules(stable, modules)) {\n return stable;\n }\n\n // Adjusted during render, so the changed modules are used in this render\n // rather than one render late.\n setStable(modules);\n\n return modules;\n};\n","// The calculations behind `iframe.tsx`'s `autoHeight`, kept free of the DOM\n// so they can be unit-tested. The DOM reads stay in `iframe.tsx`, which needs\n// a real browser to test.\n\n// The probe height when there's no `[data-frame-container]` scroll\n// container, as when `Frame` is used without `Live.Dnd`. A common mobile\n// viewport height.\nexport const FALLBACK_PROBE_HEIGHT = 812;\n\n// The vertical space an element takes around its content: margin, border\n// and padding, top and bottom. Margin counts (#440), or a `100vh` section in\n// a wrapper with a margin would overflow the container by that margin. A\n// margin that collapses through a parent is counted twice, which errs toward\n// a smaller probe that fits.\nexport const verticalInsets = (\n style: Pick<\n CSSStyleDeclaration,\n | 'marginTop'\n | 'marginBottom'\n | 'borderTopWidth'\n | 'borderBottomWidth'\n | 'paddingTop'\n | 'paddingBottom'\n >,\n): number =>\n [\n style.marginTop,\n style.marginBottom,\n style.borderTopWidth,\n style.borderBottomWidth,\n style.paddingTop,\n style.paddingBottom,\n ].reduce((sum, value) => sum + (parseFloat(value) || 0), 0);\n\n// The height the preview's `cq*` units resolve against: the scroll\n// container's `clientHeight` minus `wrapperInsets`, the space everything\n// between the iframe and the container takes (`verticalInsets`). `null`\n// while the container isn't laid out yet: skip the pass rather than guess a\n// height that nothing would correct later.\nexport const computeProbeHeight = (\n scrollContainerClientHeight: number,\n wrapperInsets: number,\n): number | null => {\n const usable = scrollContainerClientHeight - wrapperInsets;\n\n return usable > 0 ? usable : null;\n};\n\n// Whether an element is hidden but still takes height: `visibility: hidden`\n// or `opacity: 0` (`display: none` already reads 0), such as a closed bottom\n// sheet. A transparent element that `isAnimating` is a fade-in starting, so\n// it's measured (#374). `visibility: hidden` stays hidden even while\n// animating.\nexport const isVisuallyHidden = (\n computed: {\n visibility: string;\n opacity: string;\n },\n isAnimating = false,\n): boolean =>\n computed.visibility === 'hidden' ||\n (computed.opacity === '0' && !isAnimating);\n\n// The `playState`s that mean the element is still changing. Not just\n// `!== 'idle'`: a finished fade-out with `fill-mode: forwards` stays\n// `finished` at `opacity: 0` and is hidden for good. `paused` counts, since\n// a paused fade-in stopped part-way.\nexport const isAnimationActive = (playState: string): boolean =>\n playState === 'running' || playState === 'paused';\n\n// How far down a fixed or absolute element reaches, from its viewport `top`\n// and `bottom` read while the viewport is `probeHeight` tall: its bottom\n// edge, capped at `probeHeight` so one element placed past the viewport can't\n// stretch the whole preview. `null` for an element entirely outside the\n// viewport, such as a closed drawer moved off-screen, which shows nothing.\nexport const positionedElementBottom = (\n top: number,\n bottom: number,\n probeHeight: number,\n): number | null => {\n if (bottom <= 0 || top >= probeHeight) {\n return null;\n }\n\n return Math.min(bottom, probeHeight);\n};\n","const SYNCED_STYLE_ATTR = 'data-live-editor-synced-style';\n\ntype SourceStyle = HTMLLinkElement | HTMLStyleElement;\ntype SyncedStyle = HTMLLinkElement | HTMLStyleElement;\n\nexport interface StyleSyncManager {\n clones: Map<SourceStyle, SyncedStyle>;\n}\n\nexport const createStyleSyncManager = (): StyleSyncManager => ({\n clones: new Map(),\n});\n\nconst isDocument = (target: Document | ShadowRoot): target is Document =>\n target.nodeType === Node.DOCUMENT_NODE;\n\nconst sourceStyles = (document: Document): SourceStyle[] =>\n Array.from(\n document.head.querySelectorAll<HTMLLinkElement | HTMLStyleElement>(\n 'link[rel=\"stylesheet\"], style',\n ),\n );\n\nconst copyAttributes = (\n source: SourceStyle,\n clone: SyncedStyle,\n transformStyle: (content: string) => string,\n) => {\n Array.from(clone.attributes).forEach(attribute => {\n if (\n attribute.name !== SYNCED_STYLE_ATTR &&\n !source.hasAttribute(attribute.name)\n ) {\n clone.removeAttribute(attribute.name);\n }\n });\n\n Array.from(source.attributes).forEach(attribute => {\n clone.setAttribute(attribute.name, attribute.value);\n });\n\n if (source.tagName === 'LINK' && clone.tagName === 'LINK') {\n (clone as HTMLLinkElement).disabled = (source as HTMLLinkElement).disabled;\n }\n\n clone.textContent =\n source.tagName === 'STYLE'\n ? transformStyle(source.textContent || '')\n : source.textContent;\n};\n\nconst createClone = (\n source: SourceStyle,\n target: Document | ShadowRoot,\n transformStyle: (content: string) => string,\n): SyncedStyle => {\n const ownerDocument = isDocument(target) ? target : target.ownerDocument;\n const clone = ownerDocument.createElement(\n source.tagName.toLowerCase(),\n ) as SyncedStyle;\n\n clone.setAttribute(SYNCED_STYLE_ATTR, '');\n copyAttributes(source, clone, transformStyle);\n\n return clone;\n};\n\nconst targetContainer = (target: Document | ShadowRoot) =>\n isDocument(target) ? target.head : target;\n\nconst isSyncedStyle = (node: Node): node is SyncedStyle => {\n const element = node as Element;\n\n return (\n (element.tagName === 'LINK' || element.tagName === 'STYLE') &&\n element.hasAttribute(SYNCED_STYLE_ATTR)\n );\n};\n\nconst removeClone = (clone: SyncedStyle) => {\n clone.remove();\n};\n\n// `anchor`, when given, is an element the synced block has to stay in front\n// of. Without it, a first sync appends the block after whatever the target\n// already holds, so a rule the target added for itself could end up before\n// the host's copies and lose to them on order (#441).\nexport const reconcileStyles = (\n sourceDocument: Document,\n target: Document | ShadowRoot,\n manager: StyleSyncManager,\n enabled: boolean,\n transformStyle: (content: string) => string = content => content,\n anchor: Node | null = null,\n) => {\n if (!enabled) {\n manager.clones.forEach(removeClone);\n manager.clones.clear();\n\n return;\n }\n\n const sources = sourceStyles(sourceDocument);\n const sourceSet = new Set(sources);\n const container = targetContainer(target);\n\n manager.clones.forEach((clone, source) => {\n if (!sourceSet.has(source)) {\n removeClone(clone);\n manager.clones.delete(source);\n }\n });\n\n let previous: SyncedStyle | null = null;\n\n sources.forEach(source => {\n let clone = manager.clones.get(source);\n\n if (!clone) {\n clone = createClone(source, target, transformStyle);\n manager.clones.set(source, clone);\n } else {\n copyAttributes(source, clone, transformStyle);\n }\n\n const nextSibling = previous\n ? previous.nextSibling\n : (Array.from(container.childNodes).find(isSyncedStyle) ??\n (anchor?.parentNode === container ? anchor : null));\n\n if (clone !== nextSibling) {\n container.insertBefore(clone, nextSibling);\n }\n\n previous = clone;\n });\n};\n\n// What a root-attribute sync has written onto the target, so a later pass\n// removes exactly that and never what the target set for itself.\nexport interface RootAttributeSync {\n attributes: Set<string>;\n classes: Set<string>;\n}\n\nexport const createRootAttributeSync = (): RootAttributeSync => ({\n attributes: new Set(),\n classes: new Set(),\n});\n\nconst isMirroredAttribute = (name: string) => name.startsWith('data-');\n\n// Mirrors the host `<html>`'s classes and `data-*` attributes onto an iframe's\n// `<html>`. A theme is usually switched there (`.dark`, `data-theme=\"dark\"`),\n// and copying the host's stylesheets alone doesn't help an iframe: its\n// selectors look for those on an ancestor, and the iframe document has a root\n// of its own. A shadow root needs none of this, since it sits under the host's\n// `<html>` already (#497).\n//\n// Classes are synced token by token, so a class the preview put on its own\n// root survives. Other attributes (`style`, `lang`, `dir`, ...) are left\n// alone: the frame relies on its own root for sizing and layout.\nexport const reconcileRootAttributes = (\n source: Element,\n target: Element,\n sync: RootAttributeSync,\n enabled: boolean,\n) => {\n const attributes = enabled\n ? Array.from(source.attributes).filter(({ name }) =>\n isMirroredAttribute(name),\n )\n : [];\n const classes = enabled ? Array.from(source.classList) : [];\n const attributeNames = new Set(attributes.map(({ name }) => name));\n const classNames = new Set(classes);\n\n sync.attributes.forEach(name => {\n if (!attributeNames.has(name)) {\n target.removeAttribute(name);\n }\n });\n attributes.forEach(({ name, value }) => {\n if (target.getAttribute(name) !== value) {\n target.setAttribute(name, value);\n }\n });\n\n sync.classes.forEach(name => {\n if (!classNames.has(name)) {\n target.classList.remove(name);\n }\n });\n classes.forEach(name => target.classList.add(name));\n\n if (!target.classList.length) {\n target.removeAttribute('class');\n }\n\n sync.attributes = attributeNames;\n sync.classes = classNames;\n};\n","// Rewrites viewport units to container units for `autoHeight` (#132). The\n// iframe measures its content against a fixed-height size container\n// (`html { container-type: size; height: <probe>px }`), but a size container\n// doesn't change what `vh` resolves against, so `vh`, `svh`, `lvh`, `dvh`,\n// `vmin` and `vmax` become `cqh`, `cqmin` and `cqmax`. `vw` and `vi` are left\n// alone: they depend on width, which the measurement doesn't touch.\nconst UNIT_MAP: Record<string, string> = {\n vh: 'cqh',\n svh: 'cqh',\n lvh: 'cqh',\n dvh: 'cqh',\n vmin: 'cqmin',\n vmax: 'cqmax',\n};\n\n// Longest-unit-first so `svh`/`lvh`/`dvh` aren't shadowed by a shorter\n// alternative matching a prefix of them first.\nconst UNITS_PATTERN = Object.keys(UNIT_MAP)\n .sort((a, b) => b.length - a.length)\n .join('|');\n\n// A CSS dimension token: optional sign, then digits with an optional\n// fractional part on either side of the decimal point (`100`, `50.5`,\n// `-10`, `.5` all match; a bare `-` or `.` alone does not).\nconst NUMBER_PATTERN = '-?(?:\\\\d+\\\\.?\\\\d*|\\\\.\\\\d+)';\n\n// The number must not follow a letter, digit, `_`, `.` or `-`, so\n// `url(a5vh.png)`, `.a5vh{}` and `.hero-100vh{}` stay as they are: those\n// digits belong to a name. A real negative value (`margin-top: -10vh`) still\n// matches, since a space comes before its `-`. `--my-vh` never matches:\n// there's no number before `vh`.\nconst VIEWPORT_UNIT_RE = new RegExp(\n `(?<![\\\\w.-])(${NUMBER_PATTERN})(${UNITS_PATTERN})(?![a-zA-Z0-9_-])`,\n 'gi',\n);\n\n// Rewrites `vh`, `svh`, `lvh`, `dvh`, `vmin` and `vmax` to `cqh`, `cqmin` and\n// `cqmax` wherever they appear as a dimension, including inside `calc()` and\n// `var()` fallbacks. `vw` stays (see `UNIT_MAP`). A plain text replacement,\n// so a value in a CSS string such as `content: \"100vh\"` is rewritten too,\n// which doesn't affect layout.\nexport const convertViewportUnits = (css: string): string =>\n css.replace(\n VIEWPORT_UNIT_RE,\n (_match, number: string, unit: string) =>\n number + UNIT_MAP[unit.toLowerCase()],\n );\n\n// Rewrites viewport units in the two places `convertViewportUnits` doesn't\n// see: inline `style` attributes (which panel edits produce) and `<style>`\n// elements the preview renders itself. Without this, their `vh` would\n// resolve against the iframe's own height again (#132). Call it from\n// `updateHeight` after the container style is applied, before reading any\n// height.\n//\n// Idempotent: converted values no longer match the selectors, and a node is\n// written only when its text changes. A write would trigger the\n// MutationObserver in `iframe.tsx` again and loop.\nexport const rewriteInlineViewportUnits = (root: HTMLElement): void => {\n // `vh` as a substring already covers `svh`/`lvh`/`dvh`; `vmin`/`vmax` need\n // their own terms. Case-insensitive so `100VH` inline is caught too.\n const inlineTargets = root.querySelectorAll<HTMLElement>(\n '[style*=\"vh\" i], [style*=\"vmin\" i], [style*=\"vmax\" i]',\n );\n\n inlineTargets.forEach(el => {\n const current = el.getAttribute('style');\n\n if (current == null) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n el.setAttribute('style', converted);\n }\n });\n\n root.querySelectorAll<HTMLStyleElement>('style').forEach(styleEl => {\n const current = styleEl.textContent;\n\n if (!current) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n styleEl.textContent = converted;\n }\n });\n};\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n useEventListener,\n useMutationObserver,\n useResizeObserver,\n} from '@jbpark/use-hooks';\n\nimport { withScriptBlobs } from '~/utils/scripts';\n\nimport {\n FALLBACK_PROBE_HEIGHT,\n computeProbeHeight,\n isAnimationActive,\n isVisuallyHidden,\n positionedElementBottom,\n verticalInsets,\n} from './measure';\nimport {\n createRootAttributeSync,\n createStyleSyncManager,\n reconcileRootAttributes,\n reconcileStyles,\n} from './style-sync';\nimport {\n convertViewportUnits,\n rewriteInlineViewportUnits,\n} from './viewport-units';\n\n// The style that makes `<html>` a size container, found again by this id.\n// Scoped to `html`, so it only affects how `cq*` units resolve.\nconst CONTAINER_STYLE_ID = 'autoheight-container';\n\nexport interface Props {\n title?: string;\n /** Forwarded to the iframe's `sandbox` attribute for DOM/CSS isolation only — not a security boundary, since preview code executes in the host window's realm (see `compileModule` in `~/utils`). */\n sandbox?: string;\n style?: React.CSSProperties;\n scripts?: string[];\n styles?: string[];\n stylesheets?: string[];\n autoHeight?: boolean;\n syncStyle?: boolean;\n children: (container: HTMLElement) => ReactNode;\n onLoaded?: () => void;\n}\n\nconst EMPTY_STRING_ARRAY: string[] = [];\n\n// `getAnimations()` mixes CSS animations, CSS transitions and script\n// animations (`element.animate()`). Only the first two fire a bubbling event\n// when they end, so they're told apart. Both constructors are checked first,\n// since jsdom has neither.\nconst isCssAnimation = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSAnimation === 'function' &&\n animation instanceof win.CSSAnimation;\n\nconst isCssTransition = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSTransition === 'function' &&\n animation instanceof win.CSSTransition;\n\n// Whether the element is animating, which tells a passing `opacity: 0` (the\n// start of a fade-in, so measure it) from a lasting one (a closed overlay, so\n// skip it). Transitions count too: a measurement pass doesn't always freeze\n// them, so a fade-in can read `opacity: 0` with a transition running. Without\n// `getAnimations()` (jsdom, old browsers) this is false, which under-measures\n// a fading-in overlay rather than counting a closed one.\nconst hasActiveAnimation = (el: HTMLElement): boolean =>\n typeof el.getAnimations === 'function' &&\n el.getAnimations().some(animation => isAnimationActive(animation.playState));\n\n// An animation that repeats forever never resolves `finished`, so it gets no\n// handler. It's always animating, so `hasActiveAnimation` keeps it measured\n// anyway.\nconst neverFinishes = (animation: Animation): boolean => {\n const timing = animation.effect?.getComputedTiming();\n\n return timing?.iterations === Infinity || timing?.duration === Infinity;\n};\n\n// A style that is off (`media=\"not all\"`) except while a measurement runs.\n// It guards against two things:\n//\n// - Transitions: a transition on what the measurement changes would animate\n// the new probe height, and the read would catch a value part-way there.\n// Only on a pass that changes the probe height (`freezeTransitions`).\n// - Scrollbars: a new probe height can show or hide a scrollbar for that\n// pass, which narrows the content where scrollbars take space (Windows)\n// and changes the height. Only the scrollbar is hidden; scrolling still\n// works.\n//\n// One element that is never added or removed, so toggling it doesn't trigger\n// the MutationObserver that watches the content.\nconst MEASUREMENT_OVERRIDE_STYLE_ID = 'autoheight-measurement-overrides';\n\nconst SCROLLBAR_OVERRIDE_RULES = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n];\n\nconst FREEZE_TRANSITIONS_RULE =\n '*, *::before, *::after { transition: none !important; }';\n\n// Measures with the overrides above on. `freezeTransitions` is off unless\n// the pass changes the probe height: `transition: none` cancels a running\n// transition rather than pausing it, and the element jumps to its end state\n// for good. A pass that leaves the probe height alone changes nothing, so it\n// leaves the preview's transitions alone.\nconst withMeasurementOverrides = (\n doc: Document,\n freezeTransitions: boolean,\n measure: () => void,\n) => {\n let styleEl = doc.getElementById(\n MEASUREMENT_OVERRIDE_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = MEASUREMENT_OVERRIDE_STYLE_ID;\n styleEl.media = 'not all';\n doc.head?.appendChild(styleEl);\n }\n\n const text = (\n freezeTransitions\n ? [FREEZE_TRANSITIONS_RULE, ...SCROLLBAR_OVERRIDE_RULES]\n : SCROLLBAR_OVERRIDE_RULES\n ).join('\\n');\n\n if (styleEl.textContent !== text) {\n styleEl.textContent = text;\n }\n\n styleEl.media = 'all';\n measure();\n styleEl.media = 'not all';\n};\n\nconst IFrame = ({\n title = 'Live Preview',\n sandbox,\n style = {},\n scripts = EMPTY_STRING_ARRAY,\n styles = EMPTY_STRING_ARRAY,\n stylesheets = EMPTY_STRING_ARRAY,\n autoHeight = false,\n syncStyle = false,\n children,\n onLoaded,\n ...props\n}: Props) => {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const [mountNode, setMountNode] = useState<HTMLElement | null>(null);\n // The script srcs already added to this iframe's document, so a src added\n // to `scripts` later still loads.\n const loadedScriptsRef = useRef<Set<string>>(new Set());\n // The document those scripts went into. Moving the iframe, as reordering\n // canvas sections does, reloads it with a new document that has none\n // (#507).\n const loadedScriptsDocRef = useRef<Document | null>(null);\n const prevStyleCountRef = useRef(0);\n const prevStylesheetCountRef = useRef(0);\n // Animations that already have a re-measure handler, so a long one gets only\n // one. Weak, so it never keeps an animation or its element alive.\n const trackedAnimationsRef = useRef(new WeakSet<Animation>());\n // Lets those handlers call the current `updateHeight` without it depending\n // on itself.\n const updateHeightRef = useRef<(() => void) | null>(null);\n // The probe height the container style was last built for. A pass that\n // leaves it unchanged changes nothing, so it can measure without freezing\n // transitions.\n const lastProbeHeightRef = useRef<number | undefined>(undefined);\n const shouldAutoHeight = autoHeight && style.height == null;\n\n const styleManagerRef = useRef(createStyleSyncManager());\n const rootAttributeSyncRef = useRef(createRootAttributeSync());\n\n const applyStyle = useCallback(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc) {\n return;\n }\n\n // The container style goes after every copied host style. Both use\n // `!important`, so a host `html { height: 100% !important }` copied in after\n // it would win and fold the frame to a pixel (#441).\n reconcileStyles(\n document,\n doc,\n styleManagerRef.current,\n syncStyle,\n convertViewportUnits,\n doc.getElementById(CONTAINER_STYLE_ID),\n );\n // The host's theme class or attribute, which the copied styles select on\n // (#497).\n reconcileRootAttributes(\n document.documentElement,\n doc.documentElement,\n rootAttributeSyncRef.current,\n syncStyle,\n );\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced, since a stylesheet swap fires several head mutations in a\n // row.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n // A theme switch only changes the host's `<html>` attributes, which the head\n // observer above doesn't see.\n useMutationObserver(document.documentElement, debouncedApplyStyle, {\n enabled: syncStyle,\n attributes: true,\n });\n\n useEffect(() => {\n const $iframe = iframeRef.current;\n\n if (!$iframe) {\n return;\n }\n\n const onLoad = () => {\n const doc = $iframe.contentDocument;\n\n if (!doc) {\n return;\n }\n\n if (loadedScriptsDocRef.current !== doc) {\n loadedScriptsDocRef.current = doc;\n loadedScriptsRef.current = new Set();\n }\n\n doc.body.style.overflowX = 'hidden';\n doc.body.style.margin = '0';\n\n let node = doc.getElementById('iframe-root');\n\n if (!node) {\n node = doc.createElement('div');\n node.id = 'iframe-root';\n doc.body.appendChild(node);\n }\n\n setMountNode(node);\n\n applyStyle();\n\n const pendingScripts = scripts.filter(\n src => !loadedScriptsRef.current.has(src),\n );\n\n if (pendingScripts.length) {\n pendingScripts.forEach(src => loadedScriptsRef.current.add(src));\n\n withScriptBlobs(pendingScripts, blobUrls => {\n if (!doc.head) {\n return;\n }\n\n const fragment = doc.createDocumentFragment();\n blobUrls.forEach(blobUrl => {\n const script = doc.createElement('script');\n script.src = blobUrl;\n fragment.appendChild(script);\n });\n doc.head.appendChild(fragment);\n });\n }\n\n onLoaded?.();\n };\n\n $iframe.addEventListener('load', onLoad);\n\n if ($iframe.contentDocument?.readyState === 'complete') {\n onLoad();\n }\n\n return () => {\n $iframe.removeEventListener('load', onLoad);\n };\n }, [scripts, onLoaded, applyStyle]);\n\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n styles.forEach((css, index) => {\n const styleId = `injected-style-${index}`;\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = styleId;\n doc.head.appendChild(styleEl);\n }\n\n // The main source of `vh` units in a preview: compiled component CSS,\n // such as Tailwind's `h-screen`. See `ensureContainerStyle` for why they're\n // converted.\n const convertedCss = convertViewportUnits(css);\n\n if (styleEl.textContent !== convertedCss) {\n styleEl.textContent = convertedCss;\n }\n });\n\n // Remove what's left from a longer `styles` or `stylesheets` array.\n for (\n let index = styles.length;\n index < prevStyleCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-style-${index}`)?.remove();\n }\n prevStyleCountRef.current = styles.length;\n\n stylesheets.forEach((href, index) => {\n const linkId = `injected-stylesheet-${index}`;\n let linkEl = doc.getElementById(linkId) as HTMLLinkElement | null;\n\n if (!linkEl) {\n linkEl = doc.createElement('link');\n linkEl.id = linkId;\n linkEl.rel = 'stylesheet';\n doc.head.appendChild(linkEl);\n }\n\n if (linkEl.href !== href) {\n linkEl.href = href;\n }\n });\n\n for (\n let index = stylesheets.length;\n index < prevStylesheetCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-stylesheet-${index}`)?.remove();\n }\n prevStylesheetCountRef.current = stylesheets.length;\n }, [styles, stylesheets]);\n\n // Hides the iframe document's scrollbar while `autoHeight` sizes it.\n // Rounding can leave the document a fraction taller than the iframe, which\n // would draw a scrollbar in every section. Unlike the measurement override,\n // this stays on. Scrolling still works if the content ever outgrows it.\n const HIDE_SCROLLBAR_STYLE_ID = 'autoheight-hide-scrollbar';\n\n // Makes `<html>` a size container with a fixed height, `probeHeight`, the\n // scroll container's available height. Viewport units are rewritten to `cq*`\n // units (`convertViewportUnits`), so they resolve against this height\n // instead of the iframe's own. Against the iframe's own height, `100vh`\n // content would grow the iframe, which grows the content again, and never\n // settle (#132).\n const ensureContainerStyle = (doc: Document, probeHeight: number) => {\n let styleEl = doc.getElementById(\n CONTAINER_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = CONTAINER_STYLE_ID;\n doc.head?.appendChild(styleEl);\n }\n\n const text = `html { container-type: size !important; height: ${probeHeight}px !important; }`;\n\n // Written only when it differs, so a pass with the same probe height\n // changes nothing in the document (see `freezeTransitions`).\n if (styleEl.textContent !== text) {\n styleEl.textContent = text;\n }\n };\n\n // Script animations fire no event when they end, so each gets one\n // re-measure when its `finished` promise settles. CSS animations and\n // transitions are skipped: their end events already bubble to the mount node.\n // A cancelled animation rejects `finished` and snaps the element back, which\n // also changes the height, so both outcomes re-measure.\n const trackScriptAnimations = useCallback(\n (doc: Document, win: Window & typeof globalThis) => {\n if (typeof doc.getAnimations !== 'function') {\n return;\n }\n\n doc.getAnimations().forEach(animation => {\n if (\n trackedAnimationsRef.current.has(animation) ||\n !isAnimationActive(animation.playState) ||\n isCssAnimation(win, animation) ||\n isCssTransition(win, animation) ||\n neverFinishes(animation)\n ) {\n return;\n }\n\n trackedAnimationsRef.current.add(animation);\n\n animation.finished\n .catch(() => undefined)\n .then(() => updateHeightRef.current?.());\n });\n },\n [],\n );\n\n // There is no \"skip when `scrollHeight` and the probe height are unchanged\"\n // check, though setting the iframe's height can trigger the ResizeObserver\n // again. Opening or closing a fixed or absolute overlay often leaves\n // `scrollHeight` unchanged, so such a check would skip exactly the updates\n // the full-subtree walk is for.\n const updateHeight = useCallback(() => {\n if (!shouldAutoHeight || !mountNode || !iframeRef.current) {\n return;\n }\n\n const iframe = iframeRef.current;\n const doc = iframe.contentDocument;\n const win = doc?.defaultView;\n\n if (!doc || !win) {\n return;\n }\n\n const scrollParent = iframe.closest<HTMLElement>('[data-frame-container]');\n\n let probeHeight: number;\n\n if (!scrollParent) {\n // No scroll container (`Frame` used without `Live.Dnd`): use a fixed\n // default. See `FALLBACK_PROBE_HEIGHT`.\n probeHeight = FALLBACK_PROBE_HEIGHT;\n } else {\n // From the iframe up to the scroll container: the iframe's and each\n // wrapper's margin, border and padding take space, and the scroll container\n // adds only its padding, since `clientHeight` leaves out its border and\n // margin (#440).\n const scrollParentStyle = win.getComputedStyle(scrollParent);\n let wrapperInsets =\n (parseFloat(scrollParentStyle.paddingTop) || 0) +\n (parseFloat(scrollParentStyle.paddingBottom) || 0);\n let node: HTMLElement | null = iframe;\n\n while (node && node !== scrollParent) {\n wrapperInsets += verticalInsets(win.getComputedStyle(node));\n node = node.parentElement;\n }\n\n const computed = computeProbeHeight(\n scrollParent.clientHeight,\n wrapperInsets,\n );\n\n if (computed === null) {\n // Layout isn't ready yet: skip this pass. The observers call this again\n // once it settles.\n return;\n }\n\n probeHeight = computed;\n }\n\n let contentHeight = 0;\n\n // Only the first pass and a pass that moves the probe height change the\n // container, so only they freeze transitions.\n const freezeTransitions = probeHeight !== lastProbeHeightRef.current;\n\n lastProbeHeightRef.current = probeHeight;\n\n // Sizes the iframe's viewport to the probe height for the reads below, so\n // a fixed element's percentage `height` or `top` resolves against what the\n // section shows, not against the iframe's current height, which is itself\n // what is being measured (#565). The final height replaces it before the\n // next paint.\n const previousHeight = iframe.style.height;\n\n iframe.style.height = `${probeHeight}px`;\n\n withMeasurementOverrides(doc, freezeTransitions, () => {\n ensureContainerStyle(doc, probeHeight);\n\n // Rewrite viewport units in inline `style` attributes and in-preview\n // `<style>` tags, which the container style can't reach, so they resolve\n // against the probe height too. After `ensureContainerStyle` and before the\n // reads below. It's idempotent, so the observer pass its own rewrites trigger\n // changes nothing.\n rewriteInlineViewportUnits(mountNode);\n\n // No need to fold the iframe to 0px first: `cq*` content is sized against\n // the fixed probe height, so a direct read is stable (#132).\n contentHeight = mountNode.scrollHeight;\n\n // Every descendant, so an overlay nested deep in the tree counts too.\n const descendants = mountNode.querySelectorAll<HTMLElement>('*');\n\n descendants.forEach(el => {\n const style = win.getComputedStyle(el);\n\n // `visibility: hidden` and `opacity: 0` elements, such as a closed bottom\n // sheet, still have an `offsetHeight`, so they're skipped here\n // (`display: none` already reads 0). Animations are checked only for a fully\n // transparent element, to tell a fade-in apart from a hidden one.\n const isAnimating = style.opacity === '0' && hasActiveAnimation(el);\n\n if (isVisuallyHidden(style, isAnimating)) {\n return;\n }\n\n if (\n (style.position === 'fixed' || style.position === 'absolute') &&\n el.offsetHeight > 0\n ) {\n const rect = el.getBoundingClientRect();\n const bottom = positionedElementBottom(\n rect.top,\n rect.bottom,\n probeHeight,\n );\n\n if (bottom !== null) {\n contentHeight = Math.max(contentHeight, bottom);\n }\n }\n });\n });\n\n iframe.style.height =\n contentHeight > 0 ? `${Math.ceil(contentHeight)}px` : previousHeight;\n\n // After the measurement window, which can cancel transitions, so this sees\n // the document's real animations.\n trackScriptAnimations(doc, win);\n }, [shouldAutoHeight, mountNode, trackScriptAnimations]);\n\n useEffect(() => {\n updateHeightRef.current = updateHeight;\n }, [updateHeight]);\n\n // Removes the container style when `autoHeight` turns off or a height is\n // given, so `cq*` content goes back to sizing against the viewport.\n useEffect(() => {\n if (shouldAutoHeight) {\n return;\n }\n\n iframeRef.current?.contentDocument\n ?.getElementById(CONTAINER_STYLE_ID)\n ?.remove();\n }, [shouldAutoHeight]);\n\n // A fixed-height iframe scrolls its own document. A copied host\n // `body { overflow: hidden }` would stop that, so an inline value overrides\n // it. With `autoHeight` there's nothing to scroll, so the body is left\n // alone.\n useEffect(() => {\n const body = iframeRef.current?.contentDocument?.body;\n\n if (!body || !mountNode) {\n return;\n }\n\n if (shouldAutoHeight) {\n body.style.removeProperty('overflow-y');\n } else {\n body.style.setProperty('overflow-y', 'auto');\n }\n }, [shouldAutoHeight, mountNode]);\n\n // Depends on `mountNode` so it runs again once the iframe's document\n // exists.\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n const existing = doc.getElementById(HIDE_SCROLLBAR_STYLE_ID);\n\n if (!shouldAutoHeight) {\n existing?.remove();\n return;\n }\n\n if (existing) {\n return;\n }\n\n const styleEl = doc.createElement('style');\n styleEl.id = HIDE_SCROLLBAR_STYLE_ID;\n styleEl.textContent = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n ].join('\\n');\n doc.head.appendChild(styleEl);\n }, [shouldAutoHeight, mountNode]);\n\n useEffect(() => {\n updateHeight();\n }, [updateHeight]);\n\n const [resizeRef, resizeSize] = useResizeObserver<HTMLElement>();\n\n // Attached by hand, since `mountNode` is created by the portal, not\n // rendered here. Only used as a trigger: `updateHeight`'s own walk measures\n // more accurately than the mount node's size.\n useEffect(() => {\n if (!shouldAutoHeight || !mountNode) {\n return;\n }\n\n resizeRef(mountNode);\n return () => resizeRef(null);\n }, [shouldAutoHeight, mountNode, resizeRef]);\n\n useEffect(() => {\n updateHeight();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resizeSize]);\n\n useMutationObserver(mountNode, updateHeight, {\n enabled: shouldAutoHeight,\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n });\n\n // Re-measure when an animation or transition ends or is cancelled, which\n // neither observer sees. A fixed or absolute element read part-way through a\n // fade would otherwise keep its height until something else changed (#374).\n // All four events bubble, so one listener each on the mount node covers\n // every descendant.\n //\n // The mount node is wrapped in a ref that changes only with the node, and\n // `enabled` waits until it exists.\n const mountNodeRef = useMemo(() => ({ current: mountNode }), [mountNode]);\n const settleListenerEnabled = shouldAutoHeight && mountNode !== null;\n\n useEventListener('animationend', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('animationcancel', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('transitionend', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('transitioncancel', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n const content = mountNode\n ? createPortal(children(mountNode), mountNode)\n : null;\n\n return (\n <iframe\n ref={iframeRef}\n style={{\n // An iframe is inline by default and leaves a gap below it for text\n // descenders, which added up across canvas sections (#439).\n display: 'block',\n width: '100%',\n height: '100%',\n border: 'none',\n ...style,\n }}\n title={title}\n sandbox={sandbox}\n {...props}\n >\n {content}\n </iframe>\n );\n};\n\nexport default IFrame;\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useMutationObserver } from '@jbpark/use-hooks';\n\nimport { createStyleSyncManager, reconcileStyles } from './style-sync';\n\ninterface Props {\n // Copies the host page's stylesheets and `<style>` tags into the shadow\n // root, like `iframe.tsx`'s option of the same name. This brings the host's\n // compiled CSS, its own utilities and theme included. `dynamicTailwind`\n // covers what the host's build never saw, such as a class typed at runtime.\n syncStyle?: boolean;\n // Receives the overlay layer, the `container` to portal a modal or drawer\n // into so it opens inside the preview.\n children: (overlayLayer: HTMLElement | null) => ReactNode;\n}\n\nconst OVERLAY_LAYER_ATTR = 'data-live-editor-overlay-layer';\n\n// The layer lets clicks through to the preview under it. What is portaled\n// into it takes them again.\nconst OVERLAY_LAYER_STYLE = `[${OVERLAY_LAYER_ATTR}] > * { pointer-events: auto; }`;\n\n// The render target and the overlay layer in one grid cell, so the layer\n// covers exactly the preview's box. `min-height: 100%` stretches that box to\n// a parent with a set height, such as `Live.Preview`'s, so an overlay isn't\n// squeezed into short content. The wrapper isn't positioned, so it doesn't\n// change what an `absolute` element in the preview is placed against.\n// `isolation` keeps the layer's stacking inside the preview.\nconst createFrameNodes = () => {\n const wrapper = document.createElement('div');\n\n wrapper.style.display = 'grid';\n wrapper.style.gridTemplateColumns = 'minmax(0, 1fr)';\n wrapper.style.minHeight = '100%';\n wrapper.style.isolation = 'isolate';\n\n const renderTarget = document.createElement('div');\n\n renderTarget.style.gridArea = '1 / 1';\n\n // `contain: layout` makes the layer the containing block of the fixed\n // elements inside it, so an overlay covers the preview and not the page.\n const overlayLayer = document.createElement('div');\n\n overlayLayer.setAttribute(OVERLAY_LAYER_ATTR, '');\n overlayLayer.style.gridArea = '1 / 1';\n overlayLayer.style.zIndex = '1';\n overlayLayer.style.contain = 'layout';\n overlayLayer.style.pointerEvents = 'none';\n\n const style = document.createElement('style');\n\n style.textContent = OVERLAY_LAYER_STYLE;\n wrapper.append(style, renderTarget, overlayLayer);\n\n return { wrapper, renderTarget };\n};\n\n// The overlay layer `createFrameNodes` put next to `renderTarget`.\nconst overlayLayerOf = (renderTarget: HTMLElement) => {\n const layer = renderTarget.nextElementSibling;\n\n return layer instanceof HTMLElement && layer.hasAttribute(OVERLAY_LAYER_ATTR)\n ? layer\n : null;\n};\n\nconst Shadow = ({ syncStyle = false, children }: Props) => {\n const hostRef = useRef<HTMLDivElement>(null);\n const shadowRootRef = useRef<ShadowRoot | null>(null);\n const renderTargetRef = useRef<HTMLDivElement | null>(null);\n const [renderTarget, setRenderTarget] = useState<HTMLDivElement | null>(null);\n\n // Added next to the portal target, not inside it: React owns that subtree\n // and would remove anything added there.\n const styleManagerRef = useRef(createStyleSyncManager());\n\n const applyStyle = useCallback(() => {\n const shadowRoot = shadowRootRef.current;\n\n if (!shadowRoot) {\n return;\n }\n\n reconcileStyles(document, shadowRoot, styleManagerRef.current, syncStyle);\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced, since a stylesheet swap fires several head mutations in a\n // row, as in `iframe.tsx`.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n useLayoutEffect(() => {\n if (!hostRef.current) {\n return;\n }\n\n let shadowRoot = shadowRootRef.current;\n\n if (!shadowRoot) {\n shadowRoot =\n hostRef.current.shadowRoot ||\n hostRef.current.attachShadow({ mode: 'open' });\n shadowRootRef.current = shadowRoot;\n }\n\n let target = renderTargetRef.current;\n\n if (!target) {\n const nodes = createFrameNodes();\n\n shadowRoot.appendChild(nodes.wrapper);\n target = nodes.renderTarget;\n renderTargetRef.current = target;\n setRenderTarget(target);\n }\n\n applyStyle();\n // `click`, `pointerdown` and `pointerup` already cross the shadow boundary\n // (`composed: true`), so they aren't dispatched again here, which made\n // listeners outside see them twice (#92). `event.composedPath()[0]` gives\n // the element inside.\n }, [applyStyle]);\n\n useLayoutEffect(() => {\n if (renderTargetRef.current && !renderTarget) {\n setRenderTarget(renderTargetRef.current);\n }\n }, [renderTarget]);\n\n return (\n <div ref={hostRef} style={{ display: 'contents' }}>\n {renderTarget &&\n createPortal(children(overlayLayerOf(renderTarget)), renderTarget)}\n </div>\n );\n};\n\nexport default Shadow;\n","import { type ReactNode } from 'react';\n\nimport IFrame, { type Props as IframeProps } from './iframe';\nimport Shadow from './shadow';\n\nexport interface FrameProps extends Omit<IframeProps, 'children'> {\n mode?: 'iframe' | 'shadow';\n}\n\ninterface Props extends FrameProps {\n children: (container: HTMLElement) => ReactNode;\n}\n\nconst Frame = ({ mode, children, ...restProps }: Props) => {\n if (!mode) {\n return children(document.body);\n }\n\n if (mode === 'shadow') {\n return (\n <Shadow syncStyle={restProps.syncStyle}>\n {container => children(container || document.body)}\n </Shadow>\n );\n }\n\n return <IFrame {...restProps}>{children}</IFrame>;\n};\n\nexport default Frame;\n","import * as ui from '@jbpark/ui-kit';\nimport * as utils from '@jbpark/ui-kit/utils';\n\n// What every preview can import without the host passing it\n// (`import * as ui from 'ui-kit'`). Kept here, not in `~/utils`, because\n// loading ui-kit reaches its stylesheets, which would make `./utils`\n// unloadable in Node (#372).\nexport const baseModules = {\n 'ui-kit': ui,\n 'ui-kit/utils': utils,\n};\n","import { useMemo } from 'react';\n\nimport { useLiveMessages } from '~/components/context/messages';\nimport type { Module } from '~/types';\nimport { compile } from '~/utils/compile';\n\nimport { baseModules } from './base-modules';\nimport { useStableModules } from './use-stable-modules';\n\n// Compiles code into a component, for `Live.Preview` and each canvas\n// section, so both handle errors the same way (#246). `null` for empty code,\n// so a caller can tell \"nothing to render\" from a failed compile, which\n// comes back as a module with `error`.\nexport const useCompiledModule = (\n code: string,\n _modules?: Record<string, unknown>,\n): Module | null => {\n // An inline `modules` object from `Live.Preview`'s host is new each\n // render; only a changed entry should recompile (#397).\n const modules = useStableModules(_modules);\n const { unknown } = useLiveMessages().errors;\n\n const mergedModules = useMemo(\n () => ({ ...baseModules, ...modules }),\n [modules],\n );\n\n return useMemo(() => {\n if (!code) {\n return null;\n }\n\n try {\n return compile(code, mergedModules);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : unknown,\n };\n }\n }, [code, mergedModules, unknown]);\n};\n","import { useCallback, useEffect, useState } from 'react';\n\n// Compiles the Tailwind classes in the rendered DOM into CSS for a `<style>`\n// tag, for `Live.Preview` and each canvas section. Reading the DOM, not the\n// source, finds the classes imported components add too.\n//\n// The element is held in state through a callback ref: in shadow mode it\n// appears a commit later, and an effect reading a plain ref would miss it.\n// The compiler and theme load on first use, since they're large (#332).\nexport const useDynamicTailwind = (code: string, enabled: boolean) => {\n const [css, setCss] = useState('');\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const ref = useCallback((node: HTMLDivElement | null) => {\n setElement(node);\n }, []);\n\n useEffect(() => {\n if (!code || !enabled || !element) {\n return;\n }\n\n let cancelled = false;\n\n import('~/utils/tailwind')\n .then(({ generateTailwindCSSFromDOM }) =>\n generateTailwindCSSFromDOM(element),\n )\n .then(next => {\n if (!cancelled) {\n setCss(next);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [code, enabled, element]);\n\n return { ref, css };\n};\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["_transformCode","_detectTypeScript","_registerEditorSession","_getCachedScriptBlob","_clearScriptCache","_generateSection","_generateSections","_createSectionPreviewCache"],"sources":["../../src/utils/index.ts"],"sourcesContent":["// The public `./utils` entry. Each concern lives in its own module so that\n// library code imports only what it uses: `Live.Preview` needs `compile`,\n// not the AST layer behind the section helpers, and the provider needs\n// neither (#407). Import from those modules inside the library, not here.\nimport { transformCode as _transformCode } from './compile';\nimport { detectTypeScript as _detectTypeScript } from './detect-typescript';\nimport { registerEditorSession as _registerEditorSession } from './editor-caches';\nimport { getCachedScriptBlob as _getCachedScriptBlob } from './scripts';\nimport { clearScriptCache as _clearScriptCache } from './scripts';\nimport { generateSection as _generateSection } from './sections';\nimport { generateSections as _generateSections } from './sections';\nimport { createSectionPreviewCache as _createSectionPreviewCache } from './sections';\nimport type { SectionPreviewCache as _SectionPreviewCache } from './sections';\n\nexport { cn } from './cn';\nexport { clearCompilationCache, compile } from './compile';\nexport { clearEditorCaches } from './editor-caches';\nexport { preloadScripts } from './scripts';\nexport {\n checkDocument,\n createDocument,\n extractSections,\n replaceSections,\n} from './sections';\nexport type {\n DocumentCheck,\n DocumentOptions,\n DocumentProblem,\n SectionOptions,\n} from './sections';\n\n// Internal helpers, deprecated. Each still works, and leaves this entry in\n// the next major (#522). Re-exports only: a declaration here, such as\n// `export const x = _x`, moves the entry's types into the shared\n// declaration chunk that also pulls in React.\n/** @deprecated Internal. Use `compile`. Removed in the next major. */\nexport const transformCode = _transformCode;\n/** @deprecated Internal. Removed in the next major. */\nexport const detectTypeScript = _detectTypeScript;\n/** @deprecated Internal. `Live` registers its own session. Removed in the next major. */\nexport const registerEditorSession = _registerEditorSession;\n/** @deprecated Internal. Use `preloadScripts`. Removed in the next major. */\nexport const getCachedScriptBlob = _getCachedScriptBlob;\n/** @deprecated Internal. Use `clearEditorCaches`. Removed in the next major. */\nexport const clearScriptCache = _clearScriptCache;\n/** @deprecated Internal. `Live.Dnd` renders section previews itself. Removed in the next major. */\nexport const generateSection = _generateSection;\n/** @deprecated Internal. `Live.Dnd` renders section previews itself. Removed in the next major. */\nexport const generateSections = _generateSections;\n/** @deprecated Internal. `Live.Dnd` renders section previews itself. Removed in the next major. */\nexport const createSectionPreviewCache = _createSectionPreviewCache;\n/** @deprecated Internal. Removed in the next major. */\nexport type SectionPreviewCache = _SectionPreviewCache;\n"],"mappings":";;;;;;;;AAoCA,MAAa,gBAAgBA;;AAE7B,MAAa,mBAAmBC;;AAEhC,MAAa,wBAAwBC;;AAErC,MAAa,sBAAsBC;;AAEnC,MAAa,mBAAmBC;;AAEhC,MAAa,kBAAkBC;;AAE/B,MAAa,mBAAmBC;;AAEhC,MAAa,4BAA4BC"}
@@ -1,64 +0,0 @@
1
- //#region src/utils/ast/validate.ts
2
- const defaultValidationMessages = {
3
- required: "This field is required.",
4
- min: (min) => `Must be at least ${min}.`,
5
- max: (max) => `Must be at most ${max}.`,
6
- pattern: "Value does not match the required format.",
7
- url: "Must be a valid URL.",
8
- date: "Must be a valid date."
9
- };
10
- const VALID = { valid: true };
11
- const validateBindingValue = (binding, value, options = {}) => {
12
- const messages = {
13
- ...defaultValidationMessages,
14
- ...options.messages
15
- };
16
- if (value === "" || value === null || value === void 0) {
17
- if (binding.required) return {
18
- valid: false,
19
- message: messages.required
20
- };
21
- return VALID;
22
- }
23
- if (typeof value === "number") {
24
- if (binding.min !== void 0 && value < binding.min) return {
25
- valid: false,
26
- message: messages.min(binding.min)
27
- };
28
- if (binding.max !== void 0 && value > binding.max) return {
29
- valid: false,
30
- message: messages.max(binding.max)
31
- };
32
- }
33
- if (typeof value === "string" && binding.pattern) {
34
- let regex;
35
- try {
36
- regex = new RegExp(binding.pattern);
37
- } catch {
38
- return VALID;
39
- }
40
- if (!regex.test(value)) return {
41
- valid: false,
42
- message: messages.pattern
43
- };
44
- }
45
- if (typeof value === "string" && binding.type === "url") try {
46
- new URL(value);
47
- } catch {
48
- return {
49
- valid: false,
50
- message: messages.url
51
- };
52
- }
53
- if (typeof value === "string" && binding.type === "date") {
54
- if (Number.isNaN(Date.parse(value))) return {
55
- valid: false,
56
- message: messages.date
57
- };
58
- }
59
- return VALID;
60
- };
61
- //#endregion
62
- export { validateBindingValue as n, defaultValidationMessages as t };
63
-
64
- //# sourceMappingURL=validate-iLo8IONY.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validate-iLo8IONY.js","names":[],"sources":["../src/utils/ast/validate.ts"],"sourcesContent":["import type { BindingItem } from './types';\n\nexport interface ValidationResult {\n valid: boolean;\n message?: string;\n}\n\n// The messages a failed check returns. Pass your own through `options` to\n// translate them; the built-in panel passes the provider's `validation`\n// messages (#524).\nexport interface ValidationMessages {\n required: string;\n min: (min: number) => string;\n max: (max: number) => string;\n pattern: string;\n url: string;\n date: string;\n}\n\nexport const defaultValidationMessages: ValidationMessages = {\n required: 'This field is required.',\n min: min => `Must be at least ${min}.`,\n max: max => `Must be at most ${max}.`,\n pattern: 'Value does not match the required format.',\n url: 'Must be a valid URL.',\n date: 'Must be a valid date.',\n};\n\nexport interface ValidationOptions {\n messages?: Partial<ValidationMessages>;\n}\n\nconst VALID: ValidationResult = { valid: true };\n\nexport const validateBindingValue = (\n binding: BindingItem,\n value: unknown,\n options: ValidationOptions = {},\n): ValidationResult => {\n const messages = { ...defaultValidationMessages, ...options.messages };\n const isEmpty = value === '' || value === null || value === undefined;\n\n if (isEmpty) {\n if (binding.required) {\n return { valid: false, message: messages.required };\n }\n return VALID;\n }\n\n // `min` and `max` apply to numbers only; a `type: 'number'` field passes\n // a number (#238). Other values aren't range-checked.\n if (typeof value === 'number') {\n if (binding.min !== undefined && value < binding.min) {\n return { valid: false, message: messages.min(binding.min) };\n }\n if (binding.max !== undefined && value > binding.max) {\n return { valid: false, message: messages.max(binding.max) };\n }\n }\n\n if (typeof value === 'string' && binding.pattern) {\n let regex: RegExp;\n\n try {\n regex = new RegExp(binding.pattern);\n } catch {\n // An invalid `pattern` is the binding's mistake, so don't block the\n // input.\n return VALID;\n }\n\n if (!regex.test(value)) {\n return {\n valid: false,\n message: messages.pattern,\n };\n }\n }\n\n if (typeof value === 'string' && binding.type === 'url') {\n try {\n new URL(value);\n } catch {\n return { valid: false, message: messages.url };\n }\n }\n\n if (typeof value === 'string' && binding.type === 'date') {\n if (Number.isNaN(Date.parse(value))) {\n return { valid: false, message: messages.date };\n }\n }\n\n return VALID;\n};\n"],"mappings":";AAmBA,MAAa,4BAAgD;CAC3D,UAAU;CACV,MAAK,QAAO,oBAAoB,IAAI;CACpC,MAAK,QAAO,mBAAmB,IAAI;CACnC,SAAS;CACT,KAAK;CACL,MAAM;AACR;AAMA,MAAM,QAA0B,EAAE,OAAO,KAAK;AAE9C,MAAa,wBACX,SACA,OACA,UAA6B,CAAC,MACT;CACrB,MAAM,WAAW;EAAE,GAAG;EAA2B,GAAG,QAAQ;CAAS;CAGrE,IAFgB,UAAU,MAAM,UAAU,QAAQ,UAAU,KAAA,GAE/C;EACX,IAAI,QAAQ,UACV,OAAO;GAAE,OAAO;GAAO,SAAS,SAAS;EAAS;EAEpD,OAAO;CACT;CAIA,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,QAAQ,QAAQ,KAAA,KAAa,QAAQ,QAAQ,KAC/C,OAAO;GAAE,OAAO;GAAO,SAAS,SAAS,IAAI,QAAQ,GAAG;EAAE;EAE5D,IAAI,QAAQ,QAAQ,KAAA,KAAa,QAAQ,QAAQ,KAC/C,OAAO;GAAE,OAAO;GAAO,SAAS,SAAS,IAAI,QAAQ,GAAG;EAAE;CAE9D;CAEA,IAAI,OAAO,UAAU,YAAY,QAAQ,SAAS;EAChD,IAAI;EAEJ,IAAI;GACF,QAAQ,IAAI,OAAO,QAAQ,OAAO;EACpC,QAAQ;GAGN,OAAO;EACT;EAEA,IAAI,CAAC,MAAM,KAAK,KAAK,GACnB,OAAO;GACL,OAAO;GACP,SAAS,SAAS;EACpB;CAEJ;CAEA,IAAI,OAAO,UAAU,YAAY,QAAQ,SAAS,OAChD,IAAI;EACF,IAAI,IAAI,KAAK;CACf,QAAQ;EACN,OAAO;GAAE,OAAO;GAAO,SAAS,SAAS;EAAI;CAC/C;CAGF,IAAI,OAAO,UAAU,YAAY,QAAQ,SAAS,QAC5C;MAAA,OAAO,MAAM,KAAK,MAAM,KAAK,CAAC,GAChC,OAAO;GAAE,OAAO;GAAO,SAAS,SAAS;EAAK;CAAA;CAIlD,OAAO;AACT"}