@jbpark/live-editor 6.1.0 → 6.1.1

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 (67) hide show
  1. package/README.ko.md +8 -0
  2. package/README.md +8 -0
  3. package/dist/{boundary-CySnDUs2.js → boundary-CLMNMZFa.js} +4 -4
  4. package/dist/boundary-CLMNMZFa.js.map +1 -0
  5. package/dist/{cn-CAnad2vL.js → compile-BWZ5U59y.js} +135 -2
  6. package/dist/compile-BWZ5U59y.js.map +1 -0
  7. package/dist/{context-Bjq0CvBE.js → context-DJxX9epB.js} +2 -3
  8. package/dist/context-DJxX9epB.js.map +1 -0
  9. package/dist/{core-BNVuH8-l.js → core-BfJwD8Jx.js} +3 -6
  10. package/dist/core-BfJwD8Jx.js.map +1 -0
  11. package/dist/dnd/index.js +2 -2
  12. package/dist/{dnd-COjjjuD7.js → dnd-DAGjlJ0_.js} +206 -167
  13. package/dist/dnd-DAGjlJ0_.js.map +1 -0
  14. package/dist/{document-BkGWDZGc.js → document-MkQGxfry.js} +710 -318
  15. package/dist/document-MkQGxfry.js.map +1 -0
  16. package/dist/editor/index.js +2 -2
  17. package/dist/{editor-CvnzrM9J.js → editor-B_VOz3Q0.js} +2 -2
  18. package/dist/{editor-CvnzrM9J.js.map → editor-B_VOz3Q0.js.map} +1 -1
  19. package/dist/editor-caches-DXYXgWeD.js +63 -0
  20. package/dist/editor-caches-DXYXgWeD.js.map +1 -0
  21. package/dist/error/index.d.ts +1 -1
  22. package/dist/error/index.js +2 -2
  23. package/dist/{error-CFzvnLCf.js → error-E3T5CS3m.js} +13 -12
  24. package/dist/error-E3T5CS3m.js.map +1 -0
  25. package/dist/{index-DfIvkht8.d.ts → index-BC9hY7dI.d.ts} +5 -5
  26. package/dist/{index-CqsS207F.d.ts → index-D-Dfv65w.d.ts} +3 -2
  27. package/dist/index.d.ts +4 -4
  28. package/dist/index.js +5 -5
  29. package/dist/preview/index.d.ts +1 -1
  30. package/dist/preview/index.js +1 -1
  31. package/dist/{preview-8ejC5VP2.js → preview-DFb1pOqJ.js} +30 -11
  32. package/dist/preview-DFb1pOqJ.js.map +1 -0
  33. package/dist/provider/index.js +1 -1
  34. package/dist/{sections-rD8NuRI8.js → sections-CnG7OLr8.js} +3 -3
  35. package/dist/{sections-rD8NuRI8.js.map → sections-CnG7OLr8.js.map} +1 -1
  36. package/dist/states-Ci1AvoQ9.js.map +1 -1
  37. package/dist/style.css +74 -74
  38. package/dist/ui-kit/index.js +2 -2
  39. package/dist/ui-kit/style.css +22 -6
  40. package/dist/{update-DyFnX8yE.js → update-DnX2ibYn.js} +162 -43
  41. package/dist/update-DnX2ibYn.js.map +1 -0
  42. package/dist/{use-dynamic-tailwind-0nuRN57N.js → use-dynamic-tailwind-CjXeHjsr.js} +107 -25
  43. package/dist/use-dynamic-tailwind-CjXeHjsr.js.map +1 -0
  44. package/dist/{use-field-state-iQGW0vc6.js → use-field-state-B1VLhWfr.js} +2 -2
  45. package/dist/{use-field-state-iQGW0vc6.js.map → use-field-state-B1VLhWfr.js.map} +1 -1
  46. package/dist/utils/ast/index.js +1 -86
  47. package/dist/utils/index.js +3 -4
  48. package/package.json +2 -3
  49. package/dist/boundary-CySnDUs2.js.map +0 -1
  50. package/dist/cn-CAnad2vL.js.map +0 -1
  51. package/dist/compile-my0AjsCw.js +0 -136
  52. package/dist/compile-my0AjsCw.js.map +0 -1
  53. package/dist/constants-st9gnJ5g.js +0 -55
  54. package/dist/constants-st9gnJ5g.js.map +0 -1
  55. package/dist/context-Bjq0CvBE.js.map +0 -1
  56. package/dist/core-BNVuH8-l.js.map +0 -1
  57. package/dist/detect-typescript-CMF0FVKD.js +0 -10
  58. package/dist/detect-typescript-CMF0FVKD.js.map +0 -1
  59. package/dist/dnd-COjjjuD7.js.map +0 -1
  60. package/dist/document-BkGWDZGc.js.map +0 -1
  61. package/dist/editor-caches-ClMvdcQF.js +0 -23
  62. package/dist/editor-caches-ClMvdcQF.js.map +0 -1
  63. package/dist/error-CFzvnLCf.js.map +0 -1
  64. package/dist/preview-8ejC5VP2.js.map +0 -1
  65. package/dist/update-DyFnX8yE.js.map +0 -1
  66. package/dist/use-dynamic-tailwind-0nuRN57N.js.map +0 -1
  67. package/dist/utils/ast/index.js.map +0 -1
@@ -1,23 +0,0 @@
1
- //#region src/utils/editor-caches.ts
2
- const editorCaches = /* @__PURE__ */ new Set();
3
- const registerEditorCache = (clear) => {
4
- editorCaches.add(clear);
5
- };
6
- const clearEditorCaches = () => {
7
- editorCaches.forEach((clear) => clear());
8
- };
9
- let activeEditorSessions = 0;
10
- const registerEditorSession = () => {
11
- activeEditorSessions += 1;
12
- let released = false;
13
- return () => {
14
- if (released) return;
15
- released = true;
16
- activeEditorSessions -= 1;
17
- if (activeEditorSessions === 0) clearEditorCaches();
18
- };
19
- };
20
- //#endregion
21
- export { registerEditorCache as n, registerEditorSession as r, clearEditorCaches as t };
22
-
23
- //# sourceMappingURL=editor-caches-ClMvdcQF.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"editor-caches-ClMvdcQF.js","names":[],"sources":["../src/utils/editor-caches.ts"],"sourcesContent":["// The page-wide caches the editor owns: compiled modules, script blobs and\n// the AST parse caches. Each registers its own `clear` here when its module\n// loads, so this module imports none of them, and the provider doesn't pull\n// Babel into every bundle that mounts `Live` (#407). A section preview cache\n// belongs to its component and isn't listed here.\nconst editorCaches = new Set<() => void>();\n\nexport const registerEditorCache = (clear: () => void) => {\n editorCaches.add(clear);\n};\n\nexport const clearEditorCaches = () => {\n editorCaches.forEach(clear => clear());\n};\n\n// Shared by every editor on the page, so they're cleared only when the last\n// one unmounts. Clearing earlier could revoke a blob URL another editor is\n// about to load.\nlet activeEditorSessions = 0;\n\n// Returns the release function, so a caller can only release what it\n// acquired. Calling it twice is harmless, as React may in development.\nexport const registerEditorSession = (): (() => void) => {\n activeEditorSessions += 1;\n\n let released = false;\n\n return () => {\n if (released) {\n return;\n }\n\n released = true;\n activeEditorSessions -= 1;\n\n if (activeEditorSessions === 0) {\n clearEditorCaches();\n }\n };\n};\n"],"mappings":";AAKA,MAAM,+BAAe,IAAI,IAAgB;AAEzC,MAAa,uBAAuB,UAAsB;CACxD,aAAa,IAAI,KAAK;AACxB;AAEA,MAAa,0BAA0B;CACrC,aAAa,SAAQ,UAAS,MAAM,CAAC;AACvC;AAKA,IAAI,uBAAuB;AAI3B,MAAa,8BAA4C;CACvD,wBAAwB;CAExB,IAAI,WAAW;CAEf,aAAa;EACX,IAAI,UACF;EAGF,WAAW;EACX,wBAAwB;EAExB,IAAI,yBAAyB,GAC3B,kBAAkB;CAEtB;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"error-CFzvnLCf.js","names":["ErrorComponent","Error","ErrorImpl","ErrorRuntime","ErrorGuard"],"sources":["../src/components/error/guard.tsx","../src/components/error/runtime.tsx","../src/components/error/index.ts"],"sourcesContent":["import { useRef, useState } from 'react';\n\nimport { useEventListener, useLatest } from '@jbpark/use-hooks';\n\nimport { useLiveMessages } from '~/components/context/messages';\n\nimport ErrorComponent from './error';\n\n// Exported although no file imports it: the declaration of `App` in\n// `src/index.tsx` names it, and TypeScript can't name a type from another\n// module unless it is exported (TS4023).\nexport interface Props {\n children: React.ReactNode;\n onError?: (error: Error) => void;\n}\n\nconst Guard = ({ children, onError }: Props) => {\n const [error, setError] = useState<string | null>(null);\n const messages = useLiveMessages();\n\n const errorHandled = useRef(false);\n // Read by the listeners, so new messages don't subscribe them again.\n const messagesRef = useLatest(messages);\n\n useEventListener(\n 'error',\n event => {\n if (errorHandled.current) {\n return;\n }\n\n errorHandled.current = true;\n\n const errorMessage =\n event.error?.message ||\n event.message ||\n messagesRef.current.errors.unknown;\n\n console.error('⚡ [Guard] Event handler error:', errorMessage);\n\n event.preventDefault();\n\n setError(errorMessage);\n onError?.(event.error || new window.Error(errorMessage));\n\n setTimeout(() => {\n errorHandled.current = false;\n }, 100);\n },\n { capture: true },\n );\n\n useEventListener(\n 'unhandledrejection',\n event => {\n if (errorHandled.current) {\n return;\n }\n\n errorHandled.current = true;\n\n const errorMessage =\n event.reason?.message || messagesRef.current.errors.unhandledRejection;\n\n event.preventDefault();\n setError(errorMessage);\n onError?.(event.reason || new window.Error(errorMessage));\n\n setTimeout(() => {\n errorHandled.current = false;\n }, 100);\n },\n { capture: true },\n );\n\n if (error) {\n return (\n <ErrorComponent\n title={messages.errors.runtime}\n message={error}\n style={{ margin: 16 }}\n onReset={() => {\n setError(null);\n errorHandled.current = false;\n }}\n />\n );\n }\n\n return <div>{children}</div>;\n};\n\nexport default Guard;\n","import { useEffect } from 'react';\n\nimport { useEventListener } from '@jbpark/use-hooks';\n\nimport { useLiveMessages } from '~/components/context/messages';\nimport { useError } from '~/components/context/states';\n\nimport Error from './error';\n\n// Exported although no file imports it: the declaration of `App` in\n// `src/index.tsx` names it, and TypeScript can't name a type from another\n// module unless it is exported (TS4023).\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n open?: boolean;\n reset?: () => void;\n}\n\nconst Runtime = ({ open = true, reset }: Props) => {\n const { error: message, setError } = useError();\n const messages = useLiveMessages();\n\n useEventListener('error', e => {\n setError(e.message);\n e.preventDefault();\n });\n\n useEffect(() => {\n return () => setError(null);\n }, [setError]);\n\n if (!open) {\n return null;\n }\n\n return (\n <Error message={message} onReset={reset} title={messages.errors.runtime} />\n );\n};\n\nexport default Runtime;\n","import ErrorBoundary from './boundary';\nimport ErrorImpl, { type Props } from './error';\nimport ErrorGuard from './guard';\nimport ErrorRuntime from './runtime';\n\ntype ErrorComponent = typeof ErrorImpl & {\n Boundary: typeof ErrorBoundary;\n Runtime: typeof ErrorRuntime;\n Guard: typeof ErrorGuard;\n};\n\nconst Error = ErrorImpl as ErrorComponent;\n\nError.Boundary = ErrorBoundary;\nError.Runtime = ErrorRuntime;\nError.Guard = ErrorGuard;\n\nexport { ErrorBoundary, ErrorRuntime, ErrorGuard };\nexport type { Props };\nexport default Error;\n"],"mappings":";;;;;;;AAgBA,MAAM,SAAS,EAAE,UAAU,cAAqB;CAC9C,MAAM,CAAC,OAAO,YAAY,SAAwB,IAAI;CACtD,MAAM,WAAW,gBAAgB;CAEjC,MAAM,eAAe,OAAO,KAAK;CAEjC,MAAM,cAAc,UAAU,QAAQ;CAEtC,iBACE,UACA,UAAS;EACP,IAAI,aAAa,SACf;EAGF,aAAa,UAAU;EAEvB,MAAM,eACJ,MAAM,OAAO,WACb,MAAM,WACN,YAAY,QAAQ,OAAO;EAE7B,QAAQ,MAAM,kCAAkC,YAAY;EAE5D,MAAM,eAAe;EAErB,SAAS,YAAY;EACrB,UAAU,MAAM,SAAS,IAAI,OAAO,MAAM,YAAY,CAAC;EAEvD,iBAAiB;GACf,aAAa,UAAU;EACzB,GAAG,GAAG;CACR,GACA,EAAE,SAAS,KAAK,CAClB;CAEA,iBACE,uBACA,UAAS;EACP,IAAI,aAAa,SACf;EAGF,aAAa,UAAU;EAEvB,MAAM,eACJ,MAAM,QAAQ,WAAW,YAAY,QAAQ,OAAO;EAEtD,MAAM,eAAe;EACrB,SAAS,YAAY;EACrB,UAAU,MAAM,UAAU,IAAI,OAAO,MAAM,YAAY,CAAC;EAExD,iBAAiB;GACf,aAAa,UAAU;EACzB,GAAG,GAAG;CACR,GACA,EAAE,SAAS,KAAK,CAClB;CAEA,IAAI,OACF,OACE,oBAACA,SAAD;EACE,OAAO,SAAS,OAAO;EACvB,SAAS;EACT,OAAO,EAAE,QAAQ,GAAG;EACpB,eAAe;GACb,SAAS,IAAI;GACb,aAAa,UAAU;EACzB;CACD,CAAA;CAIL,OAAO,oBAAC,OAAD,EAAM,SAAc,CAAA;AAC7B;;;ACzEA,MAAM,WAAW,EAAE,OAAO,MAAM,YAAmB;CACjD,MAAM,EAAE,OAAO,SAAS,aAAa,SAAS;CAC9C,MAAM,WAAW,gBAAgB;CAEjC,iBAAiB,UAAS,MAAK;EAC7B,SAAS,EAAE,OAAO;EAClB,EAAE,eAAe;CACnB,CAAC;CAED,gBAAgB;EACd,aAAa,SAAS,IAAI;CAC5B,GAAG,CAAC,QAAQ,CAAC;CAEb,IAAI,CAAC,MACH,OAAO;CAGT,OACE,oBAACC,SAAD;EAAgB;EAAS,SAAS;EAAO,OAAO,SAAS,OAAO;CAAU,CAAA;AAE9E;;;AC1BA,MAAM,QAAQC;AAEd,MAAM,WAAW;AACjB,MAAM,UAAUC;AAChB,MAAM,QAAQC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"preview-8ejC5VP2.js","names":["styles","LiveError"],"sources":["../src/components/preview/preview.module.css","../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["@layer components {\n .fill {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .scroll {\n overflow-x: hidden;\n overflow-y: auto;\n }\n\n /* Hides the preview while the runtime error overlay covers it. */\n .hidden {\n display: none;\n }\n}\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 styles from './preview.module.css';\n\nimport { NO_MODULES, NO_PROPS } from './defaults';\nimport { renderStableComponent } from './stable-component';\nimport type { Props } from './types';\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 && styles.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(styles.fill, 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(styles.fill, 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 {/* Keeps the DOM when an edit leaves the hooks alone. */}\n {renderStableComponent(Component, effectiveCode, {\n ...componentProps,\n container,\n })}\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(styles.fill, styles.scroll, classNames)}\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 {renderStableComponent(\n Component,\n effectiveCode,\n componentProps,\n )}\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 Client from './client';\nimport { NO_MODULES, NO_PROPS } from './defaults';\nimport type { Props } from './types';\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":";;;;;;;;;;;;;;;ACkBA,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,WAAWA,uBAAO,QAAQ,SAAS;CAEzD,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,GAAGA,uBAAO,MAAM,UAAU;EACxC,UAAA,oBAACC,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,GAAGD,uBAAO,MAAM,UAAU;EACxC,UAAA,oBAAC,OAAD;GAAO,GAAK;GACT,WAAA,cACC,oBAAC,OAAD;IAAK,KAAK;IAAY,OAAO,EAAE,SAAS,WAAW;IACjD,UAAA,oBAACC,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,CAEG,sBAAsB,WAAW,eAAe;OAC/C,GAAG;OACH;MACF,CAAC,GACA,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,GAAGD,uBAAO,MAAMA,uBAAO,QAAQ,UAAU;EACpD,OAAO;GACL,WAAW;GACX,WAAW;GACX,eAAe;EACjB;EAEA,UAAA,oBAACC,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,CACG,sBACC,WACA,eACA,cACF,GACC,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;;;AC7HA,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":"update-DyFnX8yE.js","names":["t.stringLiteral","t.jsxExpressionContainer","t.numericLiteral","t.isTSAsExpression","t.isTSSatisfiesExpression","t.isTSNonNullExpression","t.isTSTypeAssertion","t.isParenthesizedExpression","t.isStringLiteral","t.isNumericLiteral","t.isBooleanLiteral","t.isNullLiteral","t.isUnaryExpression","t.isTemplateLiteral","t.isArrayExpression","t.isObjectExpression","t.isObjectProperty","t.isIdentifier","t.isJSXElement","t.isJSXFragment","t.isObjectExpression","t.isObjectProperty","t.isIdentifier","t.isStringLiteral","t.isTemplateLiteral","t.isJSXText","t.jsxIdentifier","t.jsxMemberExpression","t.isJSXAttribute","t.isJSXIdentifier","isStringLiteral","t.isStringLiteral","t.isJSXExpressionContainer","t.isArrayExpression","t.isObjectExpression","t.jsxText","t.jsxFragment","t.jsxOpeningFragment","t.jsxClosingFragment","t.jsxAttribute","t.jsxOpeningElement","t.jsxClosingElement","t.jsxElement","t.isJSXElement","t.isJSXFragment","t.isObjectProperty","t.isIdentifier","t.isParenthesizedExpression","t.isJSXOpeningElement","t.isJSXAttribute","t.isJSXIdentifier","t.isJSXSpreadAttribute","t.isStringLiteral","t.isJSXElement","t.isJSXFragment","t.booleanLiteral","t.numericLiteral","t.stringLiteral","t.nullLiteral","t.unaryExpression","t.arrayExpression","t.objectProperty","t.objectExpression","t.isJSXAttribute","t.isJSXIdentifier","t.isJSXText","t.jsxAttribute","t.jsxIdentifier","t.jsxExpressionContainer","t.objectExpression","t.objectProperty","t.identifier","t.stringLiteral","t.isJSXExpressionContainer","t.isArrayExpression","t.isObjectExpression","t.isJSXEmptyExpression","t.isJSXAttribute","t.isJSXIdentifier","t.isStringLiteral","t.isJSXExpressionContainer"],"sources":["../src/utils/ast/types.ts","../src/utils/ast/helpers.ts","../src/utils/ast/value.ts","../src/utils/ast/binding.ts","../src/utils/selection.ts","../src/utils/ast/extract.ts","../src/utils/ast/children.ts","../src/utils/ast/value-expression.ts","../src/utils/ast/edit-source.ts","../src/utils/ast/update.ts"],"sourcesContent":["export interface Attribute {\n name: string;\n value: string | null;\n isStringLiteral?: boolean;\n}\n\nexport interface DataAttrNode {\n id?: string;\n tagName: string;\n attributes: Attribute[];\n dataAttributes: Attribute[];\n textContent: string;\n rawChildren?: string;\n // Exact structural child source, used to validate source-preserving edits.\n source?: string;\n loc?: {\n start: { line: number; column: number };\n end: { line: number; column: number };\n };\n children?: DataAttrNode[];\n isFragment?: boolean;\n bindings?: BindingItem[];\n}\n\nexport interface BindingOption {\n label: string;\n value: string;\n}\n\n// The kinds of data a binding can hold: what a value is, not how to draw\n// it. How to draw it is `widget`, which the library passes through without\n// reading; the built-in panel renders the default control for each kind.\nexport const BINDING_TYPES = [\n 'array',\n 'object',\n 'string',\n 'number',\n 'boolean',\n 'color',\n 'jsx',\n 'richtext',\n 'date',\n 'url',\n 'email',\n 'tel',\n 'time',\n 'datetime',\n] as const;\n\nexport type BindingType = (typeof BINDING_TYPES)[number];\n\n// How to draw one field, as opposed to `type`, which is what its data is.\n// Written as a control name (`widget: 'slider'`) or as this object; parsing\n// turns the string into `{ type }`, so consumers see one shape.\n//\n// Constraints (`min`, `max`, `pattern`, `required` and the rest listed on\n// `BindingFieldSpec`) stay on the binding, not here, so\n// `validateBindingValue` checks them with or without a widget.\nexport interface BindingWidget {\n // The control name, any string (such as `'slider'`). A custom panel\n // switches on it; the built-in panel ignores it.\n type: string;\n // Common presentation hints, typed.\n step?: number;\n unit?: string;\n // Any other config for the control, kept as written (#234).\n [key: string]: unknown;\n}\n\n// The fields a binding declares about itself. Shared by `BindingItem` and\n// render-map leaves, so a nested field can say everything a top-level one\n// can (#383).\nexport interface BindingFieldSpec {\n // What the value is. A closed set, because validation and parsing switch\n // on it.\n type?: BindingType;\n // How to draw it, always in object form. See `BindingWidget`.\n widget?: BindingWidget;\n options?: BindingOption[];\n render?: BindingRenderMap;\n min?: number;\n max?: number;\n pattern?: string;\n // Shown instead of the provider's `pattern` message when `pattern` fails,\n // to say what the format is.\n patternMessage?: string;\n required?: boolean;\n // Length limits for a string value, in characters (an emoji counts once).\n minLength?: number;\n maxLength?: number;\n // A number value must be `min` (or 0) plus a whole number of steps, so\n // `step: 1` allows integers only.\n step?: number;\n // Item count limits for an array value. The built-in editor never removes\n // the last item (#316), so a `minItems` below 1 acts as 1 there.\n minItems?: number;\n maxItems?: number;\n // The earliest and latest `date` or `datetime` value, as `YYYY-MM-DD` or\n // `YYYY-MM-DDTHH:mm`. A date-only bound includes that whole day. Separate\n // from `min` and `max`, which are numbers.\n minDate?: string;\n maxDate?: string;\n // The schemes a `url` value may use, such as `['https:', 'mailto:']`. The\n // trailing colon is optional. Unset allows any scheme.\n protocols?: string[];\n // The app's own keys, anything not listed above, such as `group` or `tab`.\n // Kept apart so they can't collide with a field added later. Config for\n // the control goes in `widget` instead. `undefined` when there are none\n // (#234).\n meta?: Record<string, unknown>;\n}\n\n// A render-map entry is a leaf when it declares `type`, even an unknown\n// one, which then shows as an untyped field (#234). `label` and `property`\n// default to the entry's key.\nexport interface BindingRenderLeaf extends BindingFieldSpec {\n label?: string;\n property?: string;\n}\n\nexport interface BindingRenderMap {\n [key: string]: BindingRenderLeaf | BindingRenderMap;\n}\n\nexport interface BindingItem extends BindingFieldSpec {\n label: string;\n property: string;\n}\n\n// A component's tag name as written in the source: a member path\n// (`ui.Button`) or an identifier that doesn't start with a lowercase letter\n// (`Button`). Lowercase names are HTML elements.\nexport type BindingComponentName = `${string}.${string}` | Capitalize<string>;\n\n// One entry of `bindings` or `bindingKeys`, as written: a `BindingItem` plus\n// any key of the app's own (`group`, `tab`, `description`, ...), which\n// arrives in `binding.meta` just as it does from an inline `data-binding`.\n// `meta` itself isn't one of them: it's where those keys end up, so writing\n// it here would nest it under `meta.meta`.\nexport interface BindingSchema extends Omit<BindingItem, 'meta'> {\n [key: string]: unknown;\n}\n\n// Bindings for every element of a component, keyed by its tag name as\n// written, so markup doesn't have to repeat the same `data-binding` on each\n// one (#509). Components only: an entry for an HTML element such as `p` or\n// `h2` would make every one of them in every section editable, so those keys\n// are rejected by the type and ignored at runtime. An element's own\n// `data-binding`, even an empty one, takes precedence over its component's\n// entry. Matched elements still need a `data-id` to be edited.\nexport type BindingRegistry = Partial<\n Record<BindingComponentName, BindingSchema[]>\n>;\n\n// Bindings an element asks for by name, with `data-binding-key=\"hero-title\"`\n// in its markup, on an HTML element or a component alike (#513). Plain data,\n// so a host can load it from JSON or a CMS.\nexport type BindingKeyMap = Record<string, BindingSchema[]>;\n\n// Where bindings come from besides an element's own `data-binding`, in\n// order of precedence: the key its `data-binding-key` names in\n// `bindingKeys`, then its component's entry in `bindings`.\nexport interface BindingOptions {\n bindings?: BindingRegistry;\n bindingKeys?: BindingKeyMap;\n}\n\nexport type NodeValueType =\n 'boolean' | 'number' | 'string' | 'null' | 'array' | 'object' | 'unknown';\n\nexport interface ExtractedNodeValue {\n type: NodeValueType;\n value: string | number | boolean | null;\n}\n","import generate from '@babel/generator';\nimport { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\n\nimport { REGEX } from '../../constants';\nimport type { Attribute } from './types';\n\nexport const wrap = (code: string) => {\n return `<>${code}</>`;\n};\n\nexport const unwrap = (generated: string) => {\n return generated\n .replace(/^<>\\s*/g, '')\n .replace(/\\s*<\\/>\\s*;?\\s*$/g, '')\n .trim();\n};\n\nexport const attrValue = ({\n value,\n isStringLiteral,\n}: Attribute): t.JSXAttribute['value'] => {\n if (value === null) {\n return null;\n }\n\n if (isStringLiteral) {\n return t.stringLiteral(value);\n }\n\n const trimmed = value.trim();\n\n if (REGEX.NUMBER.test(trimmed)) {\n return t.jsxExpressionContainer(t.numericLiteral(parseFloat(trimmed)));\n }\n\n if (REGEX.BOOLEAN_OR_NULL.test(trimmed)) {\n const expr = parseExpression(trimmed, {\n plugins: ['jsx', 'typescript'],\n });\n return t.jsxExpressionContainer(expr);\n }\n\n try {\n const expr = parseExpression(trimmed, {\n plugins: ['jsx', 'typescript'],\n });\n return t.jsxExpressionContainer(expr);\n } catch {\n return t.stringLiteral(trimmed);\n }\n};\n\nexport const generateCode = (node: t.Node): string => {\n return generate(node, { jsescOption: { minimal: true } }).code;\n};\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\n\nimport { REGEX } from '../../constants';\nimport { generateCode } from './helpers';\nimport type { ExtractedNodeValue } from './types';\n\n// Reads values out of the AST without running code: literals, binding values\n// and array or object expressions.\n\nconst dedent = (str: string): string => {\n const lines = str\n .replace(/^\\n/, '')\n .replace(/\\n\\s*$/, '')\n .split('\\n');\n\n const indent = lines.reduce((min, line) => {\n if (!line.trim()) {\n return min;\n }\n const match = line.match(/^(\\s*)/);\n return Math.min(min, match?.[1]?.length ?? 0);\n }, Infinity);\n\n return indent === Infinity\n ? str.trim()\n : lines.map(line => line.slice(indent)).join('\\n');\n};\n\n// Removes type-only wrappers (`satisfies`, `as const`, type assertions) and\n// parentheses, so the literal underneath can be read. Without this, a\n// `data-binding={[...] satisfies BindingItem[]}` would read as no bindings.\nexport const unwrapExpression = (node: t.Node): t.Node => {\n let current = node;\n\n while (\n t.isTSAsExpression(current) ||\n t.isTSSatisfiesExpression(current) ||\n t.isTSNonNullExpression(current) ||\n t.isTSTypeAssertion(current) ||\n t.isParenthesizedExpression(current)\n ) {\n current = current.expression;\n }\n\n return current;\n};\n\n// Whether `evaluateLiteral()` and `valueToExpression()` can round-trip the\n// value without losing calls, references, spreads, holes or computed keys.\n// The panel uses it to disable editors, and edits use it as the last check,\n// so both agree on what is editable.\nexport const isLosslesslyEvaluable = (node: t.Node): boolean => {\n const value = unwrapExpression(node);\n\n if (\n t.isStringLiteral(value) ||\n t.isNumericLiteral(value) ||\n t.isBooleanLiteral(value) ||\n t.isNullLiteral(value)\n ) {\n return true;\n }\n\n if (\n t.isUnaryExpression(value) &&\n value.operator === '-' &&\n t.isNumericLiteral(value.argument)\n ) {\n return true;\n }\n\n if (t.isTemplateLiteral(value)) {\n return value.expressions.length === 0;\n }\n\n if (t.isArrayExpression(value)) {\n return value.elements.every(\n element => element !== null && isLosslesslyEvaluable(element),\n );\n }\n\n if (t.isObjectExpression(value)) {\n return value.properties.every(\n property =>\n t.isObjectProperty(property) &&\n !property.computed &&\n (t.isIdentifier(property.key) ||\n t.isStringLiteral(property.key) ||\n t.isNumericLiteral(property.key)) &&\n isLosslesslyEvaluable(property.value),\n );\n }\n\n return false;\n};\n\nexport const canLosslesslyEvaluateSource = (source: string): boolean => {\n try {\n return isLosslesslyEvaluable(\n parseExpression(source, { plugins: ['jsx', 'typescript'] }),\n );\n } catch {\n return false;\n }\n};\n\n// Reads a literal's value from its AST without running any code. Calls,\n// references and other non-literal expressions give `undefined`, so reading\n// a field never executes the document's code.\nexport const evaluateLiteral = (rawNode: t.Node): unknown => {\n const node = unwrapExpression(rawNode);\n\n if (t.isStringLiteral(node)) {\n return node.value;\n }\n\n if (t.isNumericLiteral(node)) {\n return node.value;\n }\n\n if (t.isBooleanLiteral(node)) {\n return node.value;\n }\n\n if (t.isNullLiteral(node)) {\n return null;\n }\n\n if (t.isIdentifier(node) && node.name === 'undefined') {\n return undefined;\n }\n\n if (\n t.isUnaryExpression(node) &&\n node.operator === '-' &&\n t.isNumericLiteral(node.argument)\n ) {\n return -node.argument.value;\n }\n\n if (t.isTemplateLiteral(node) && node.expressions.length === 0) {\n return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw ?? '';\n }\n\n if (t.isJSXElement(node) || t.isJSXFragment(node)) {\n return generateCode(node);\n }\n\n if (t.isArrayExpression(node)) {\n return node.elements.map(element =>\n element ? evaluateLiteral(element) : null,\n );\n }\n\n if (t.isObjectExpression(node)) {\n const result: Record<string, unknown> = {};\n\n for (const prop of node.properties) {\n if (!t.isObjectProperty(prop)) {\n continue;\n }\n\n let key: string | null = null;\n\n if (t.isIdentifier(prop.key)) {\n key = prop.key.name;\n } else if (t.isStringLiteral(prop.key)) {\n key = prop.key.value;\n } else if (t.isNumericLiteral(prop.key)) {\n key = String(prop.key.value);\n }\n\n if (key === null) {\n continue;\n }\n\n result[key] = evaluateLiteral(prop.value);\n }\n\n return result;\n }\n\n return undefined;\n};\n\nexport const parseValue = (value: unknown): unknown => {\n if (typeof value !== 'string') {\n return value;\n }\n\n const trimmed = value.trim();\n\n if (!trimmed) {\n return value;\n }\n\n if (REGEX.NUMBER.test(trimmed)) {\n return parseFloat(trimmed);\n }\n\n if (REGEX.BOOLEAN_OR_NULL.test(trimmed)) {\n if (trimmed === 'true') {\n return true;\n }\n if (trimmed === 'false') {\n return false;\n }\n if (trimmed === 'null') {\n return null;\n }\n if (trimmed === 'undefined') {\n return undefined;\n }\n }\n\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n const ast = parseExpression(trimmed, {\n plugins: ['jsx', 'typescript'],\n });\n\n if (t.isObjectExpression(ast) || t.isArrayExpression(ast)) {\n return evaluateLiteral(ast);\n }\n } catch {\n /* Not an object or array literal: keep the string. */\n }\n\n return value;\n }\n\n return value;\n};\n\nexport const extractNodeValue = (node: t.Node): ExtractedNodeValue => {\n if (t.isBooleanLiteral(node)) {\n return { type: 'boolean', value: node.value };\n }\n\n if (t.isNumericLiteral(node)) {\n return { type: 'number', value: node.value };\n }\n\n if (\n t.isUnaryExpression(node) &&\n node.operator === '-' &&\n t.isNumericLiteral(node.argument)\n ) {\n return { type: 'number', value: -node.argument.value };\n }\n\n if (t.isStringLiteral(node)) {\n return { type: 'string', value: node.value };\n }\n\n if (t.isTemplateLiteral(node)) {\n if (node.expressions.length === 0 && node.quasis.length === 1) {\n return {\n type: 'string',\n value: dedent(\n node.quasis[0]!.value.cooked ?? node.quasis[0]!.value.raw,\n ),\n };\n }\n return { type: 'string', value: generateCode(node) };\n }\n\n if (t.isNullLiteral(node)) {\n return { type: 'null', value: null };\n }\n\n if (t.isArrayExpression(node)) {\n return { type: 'array', value: generateCode(node) };\n }\n\n if (t.isObjectExpression(node)) {\n return { type: 'object', value: generateCode(node) };\n }\n\n if (t.isJSXElement(node) || t.isJSXFragment(node)) {\n return { type: 'string', value: generateCode(node) };\n }\n\n return { type: 'unknown', value: null };\n};\n\nexport const parseArrayExpression = (value: string) => {\n try {\n const ast = unwrapExpression(\n parseExpression(value, {\n plugins: ['jsx', 'typescript'],\n }),\n );\n\n if (!t.isArrayExpression(ast)) {\n return null;\n }\n\n return ast;\n } catch (error) {\n console.error('❌ Array parsing error:', error);\n return null;\n }\n};\n\nexport const extractObjectProperties = (\n element: t.ObjectExpression,\n): Record<string, ExtractedNodeValue & { astNode: t.Node }> => {\n const properties: Record<string, ExtractedNodeValue & { astNode: t.Node }> =\n {};\n\n element.properties.forEach(prop => {\n if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {\n const key = prop.key.name;\n\n // `children` and other JSX-valued properties (such as `label`) are\n // edited through `useDndItems`'s nested elements instead (#298).\n if (\n key === 'children' ||\n t.isJSXElement(prop.value) ||\n t.isJSXFragment(prop.value)\n ) {\n return;\n }\n\n const extracted = extractNodeValue(prop.value);\n\n properties[key] = {\n ...extracted,\n astNode: prop.value,\n };\n }\n });\n\n return properties;\n};\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { z } from 'zod';\n\nimport { BINDING_PROP, DATA_ATTR } from '../../constants';\nimport {\n BINDING_TYPES,\n type BindingItem,\n type BindingKeyMap,\n type BindingOption,\n type BindingOptions,\n type BindingRegistry,\n type BindingRenderLeaf,\n type BindingRenderMap,\n type BindingType,\n type BindingWidget,\n type DataAttrNode,\n} from './types';\nimport { evaluateLiteral, parseArrayExpression, parseValue } from './value';\n\nconst bindingTypeSchema = z.enum(BINDING_TYPES);\n// A length or an item count.\nconst countSchema = z.number().int().nonnegative();\nconst dateSchema = z.string().regex(/^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2})?$/);\n\nconst bindingOptionSchema = z.object({\n label: z.string(),\n value: z.string(),\n});\n\n// `widget.type` is any string, not an enum: the library implements no\n// widgets, so every value belongs to a custom panel (#236). `.passthrough()`\n// keeps that control's own config, such as `{ type: 'slider', snapTo: [...] }`.\nconst bindingWidgetSchema = z\n .object({\n type: z.string().min(1),\n step: z.number().optional(),\n unit: z.string().optional(),\n })\n .passthrough();\n\n// Parses one key on its own. A malformed value becomes absent instead of\n// failing the whole binding, so a typo in `min` loses only `min` (#234).\nconst pick = <T>(schema: z.ZodType<T>, value: unknown): T | undefined => {\n const parsed = schema.safeParse(value);\n\n return parsed.success ? parsed.data : undefined;\n};\n\n// Turns the string form (`widget: 'slider'`) into `{ type }`, so consumers\n// see one shape.\nconst sanitizeWidget = (value: unknown): BindingWidget | undefined => {\n if (typeof value === 'string') {\n return value ? { type: value } : undefined;\n }\n\n return pick(bindingWidgetSchema, value);\n};\n\n// Drops only the malformed options and keeps the valid ones.\nconst sanitizeOptions = (value: unknown): BindingOption[] | undefined => {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const options = value.flatMap(option => {\n const parsed = pick(bindingOptionSchema, option);\n\n return parsed ? [parsed] : [];\n });\n\n return options.length > 0 ? options : undefined;\n};\n\n// Every key the library reads from a binding. Any other key is the app's\n// own and goes into `meta`.\nconst KNOWN_BINDING_KEYS = new Set([\n 'label',\n 'property',\n 'type',\n 'widget',\n 'options',\n 'render',\n 'min',\n 'max',\n 'pattern',\n 'patternMessage',\n 'required',\n 'minLength',\n 'maxLength',\n 'step',\n 'minItems',\n 'maxItems',\n 'minDate',\n 'maxDate',\n 'protocols',\n]);\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n\n// Sanitizes the fields a binding declares. Shared by top-level bindings and\n// render-map leaves, so a new field reaches both. Absent fields are left\n// off, not set to `undefined`.\nconst sanitizeField = (raw: Record<string, unknown>): BindingRenderLeaf => {\n const metaEntries = Object.entries(raw).filter(\n ([key]) => !KNOWN_BINDING_KEYS.has(key),\n );\n const field: BindingRenderLeaf = {\n label: pick(z.string(), raw.label),\n property: pick(z.string(), raw.property),\n type: pick(bindingTypeSchema, raw.type),\n widget: sanitizeWidget(raw.widget),\n options: sanitizeOptions(raw.options),\n render: sanitizeRenderMap(raw.render),\n min: pick(z.number(), raw.min),\n max: pick(z.number(), raw.max),\n pattern: pick(z.string(), raw.pattern),\n patternMessage: pick(z.string(), raw.patternMessage),\n required: pick(z.boolean(), raw.required),\n minLength: pick(countSchema, raw.minLength),\n maxLength: pick(countSchema, raw.maxLength),\n step: pick(z.number().positive(), raw.step),\n minItems: pick(countSchema, raw.minItems),\n maxItems: pick(countSchema, raw.maxItems),\n minDate: pick(dateSchema, raw.minDate),\n maxDate: pick(dateSchema, raw.maxDate),\n protocols: pick(z.array(z.string().min(1)), raw.protocols),\n meta: metaEntries.length > 0 ? Object.fromEntries(metaEntries) : undefined,\n };\n\n return Object.fromEntries(\n Object.entries(field).filter(([, value]) => value !== undefined),\n );\n};\n\n// A render map entry is a leaf (it has `type`) or a nested map. Anything\n// else is dropped, without failing the whole map.\nfunction sanitizeRenderMap(value: unknown): BindingRenderMap | undefined {\n if (!isPlainObject(value)) {\n return undefined;\n }\n\n const map: BindingRenderMap = {};\n\n for (const [key, raw] of Object.entries(value)) {\n if (!isPlainObject(raw)) {\n continue;\n }\n\n if ('type' in raw) {\n // Keep the `type` key even when its value was dropped, so\n // `'type' in leaf` still marks it as a leaf: an unknown type shows as a\n // plain field instead of disappearing (#234).\n map[key] = { type: undefined, ...sanitizeField(raw) };\n continue;\n }\n\n const nested = sanitizeRenderMap(raw);\n\n if (nested) {\n map[key] = nested;\n }\n }\n\n return Object.keys(map).length > 0 ? map : undefined;\n}\n\n// Validates an evaluated `data-binding` array into `BindingItem[]`. Used by\n// `parseBinding` (from a string) and `parseBindingExpression` (from an AST).\nconst buildBindingItems = (raw: unknown): BindingItem[] => {\n if (!Array.isArray(raw)) {\n return [];\n }\n\n return raw.flatMap(rawItem => {\n if (!isPlainObject(rawItem)) {\n return [];\n }\n\n const { label, property, ...field } = sanitizeField(rawItem);\n\n if (label === undefined) {\n return [];\n }\n\n if (property === undefined && field.type !== 'richtext') {\n return [];\n }\n\n return [{ label, property: property ?? BINDING_PROP.INNER_HTML, ...field }];\n });\n};\n\n// Registry entries are validated like an inline `data-binding`. Cached per\n// registry object, which a host defines once rather than every render.\nconst registryEntries = new WeakMap<\n BindingRegistry,\n Map<string, BindingItem[]>\n>();\n\n// Whether a tag name is a component rather than an HTML element, by JSX's\n// own rule: a member path, or an identifier that doesn't start with a\n// lowercase letter. A namespaced name (`svg:rect`) resolves to `''` and is\n// neither.\nexport const isComponentTagName = (tagName: string): boolean =>\n tagName !== '' && (tagName.includes('.') || !/^[a-z]/.test(tagName));\n\n// The bindings `registry` gives an element of `tagName`, or `undefined` when\n// it has no entry for that component. HTML elements never match, even when\n// the registry has a key for them.\nexport const getRegistryBindings = (\n registry: BindingRegistry | undefined,\n tagName: string,\n): BindingItem[] | undefined => {\n if (!registry) {\n return undefined;\n }\n\n let entries = registryEntries.get(registry);\n\n if (!entries) {\n entries = new Map();\n registryEntries.set(registry, entries);\n\n // Once per registry, so a key the type would have rejected doesn't go\n // unnoticed in plain JavaScript or behind a cast.\n const ignored = Object.keys(registry).filter(\n key => !isComponentTagName(key),\n );\n\n if (ignored.length > 0) {\n console.warn(\n `Live.Dnd \\`bindings\\` only applies to components. Ignored: ${ignored.join(', ')}. Bind an HTML element with its own data-binding.`,\n );\n }\n }\n\n if (!isComponentTagName(tagName) || !Object.hasOwn(registry, tagName)) {\n return undefined;\n }\n\n let bindings = entries.get(tagName);\n\n if (!bindings) {\n bindings = buildBindingItems(\n (registry as Record<string, BindingItem[] | undefined>)[tagName],\n );\n entries.set(tagName, bindings);\n }\n\n return bindings;\n};\n\n// Key map entries are validated like inline ones and cached per map, as\n// registry entries are.\nconst keyEntries = new WeakMap<BindingKeyMap, Map<string, BindingItem[]>>();\n\n// Each problem is reported once per key, not on every read of a section.\nconst warnedKeys = new Set<string>();\n\nconst warnOnce = (id: string, message: string) => {\n if (!warnedKeys.has(id)) {\n warnedKeys.add(id);\n console.warn(message);\n }\n};\n\n// The bindings `bindingKeys` has under `key`, or `undefined` when it has no\n// such entry.\nexport const getKeyBindings = (\n bindingKeys: BindingKeyMap | undefined,\n key: string,\n): BindingItem[] | undefined => {\n if (!bindingKeys || !Object.hasOwn(bindingKeys, key)) {\n return undefined;\n }\n\n let entries = keyEntries.get(bindingKeys);\n\n if (!entries) {\n entries = new Map();\n keyEntries.set(bindingKeys, entries);\n }\n\n let bindings = entries.get(key);\n\n if (!bindings) {\n bindings = buildBindingItems(bindingKeys[key]);\n entries.set(key, bindings);\n }\n\n return bindings;\n};\n\n// One element's bindings, from the most specific source it has (#513):\n//\n// 1. `own`, its `data-binding`, parsed. `undefined` when it has none; an\n// empty array is still its own, which is how an element opts out.\n// 2. `key`, the string its `data-binding-key` names in `bindingKeys`.\n// `undefined` without the attribute, `null` when the attribute isn't a\n// plain string. A key with no entry gives no fields rather than falling\n// through to the registry.\n// 3. Its component's entry in `bindings`.\nexport const resolveBindings = (\n own: BindingItem[] | undefined,\n key: string | null | undefined,\n tagName: string,\n options: BindingOptions = {},\n): BindingItem[] => {\n if (own) {\n if (key !== undefined) {\n warnOnce(\n `both:${key}`,\n `Live.Dnd: an element has both data-binding and data-binding-key=\"${key ?? ''}\". Its data-binding is used; remove one of them.`,\n );\n }\n\n return own;\n }\n\n if (key === null) {\n warnOnce(\n 'not-a-string',\n 'Live.Dnd: data-binding-key must be a plain string, such as data-binding-key=\"hero-title\". The element has no fields.',\n );\n\n return [];\n }\n\n if (key !== undefined) {\n const bindings = getKeyBindings(options.bindingKeys, key);\n\n if (!bindings) {\n warnOnce(\n `missing:${key}`,\n `Live.Dnd: data-binding-key=\"${key}\" isn't in bindingKeys. The element has no fields.`,\n );\n }\n\n return bindings ?? [];\n }\n\n return getRegistryBindings(options.bindings, tagName) ?? [];\n};\n\nexport const parseBinding = (bindingValue: string | null): BindingItem[] => {\n if (!bindingValue) {\n return [];\n }\n\n const ast = parseArrayExpression(bindingValue);\n\n if (!ast) {\n return [];\n }\n\n return buildBindingItems(evaluateLiteral(ast));\n};\n\n// `parseBinding` for an array expression that is already parsed, as\n// `extract` has it. Saves printing it and parsing it again (#241).\nexport const parseBindingExpression = (\n expression: t.ArrayExpression,\n): BindingItem[] => buildBindingItems(evaluateLiteral(expression));\n\nexport const getCurrentValue = (\n node: DataAttrNode,\n property: string,\n): string => {\n switch (property) {\n case BINDING_PROP.INNER_TEXT: {\n return node.textContent || '';\n }\n\n case BINDING_PROP.INNER_HTML: {\n // A `richtext` value lives in `dangerouslySetInnerHTML={{ __html }}`.\n const dsiAttr = node.attributes.find(\n a => a.name === 'dangerouslySetInnerHTML',\n );\n if (dsiAttr?.value) {\n try {\n const expr = parseExpression(dsiAttr.value, {\n plugins: ['jsx', 'typescript'],\n });\n if (t.isObjectExpression(expr)) {\n const htmlProp = expr.properties.find(\n p =>\n t.isObjectProperty(p) &&\n t.isIdentifier(p.key) &&\n p.key.name === '__html',\n ) as t.ObjectProperty | undefined;\n if (htmlProp) {\n if (t.isStringLiteral(htmlProp.value)) {\n return htmlProp.value.value;\n }\n if (\n t.isTemplateLiteral(htmlProp.value) &&\n htmlProp.value.expressions.length === 0\n ) {\n return (\n htmlProp.value.quasis[0]?.value.cooked ??\n htmlProp.value.quasis[0]?.value.raw ??\n ''\n );\n }\n }\n }\n } catch {\n // Not a readable object: fall back to the children below.\n }\n }\n return node.rawChildren || node.textContent || '';\n }\n\n case BINDING_PROP.CHILDREN: {\n return JSON.stringify(node?.children || []);\n }\n\n default: {\n const customAttr = node.attributes.find(attr => attr.name === property);\n const value = customAttr?.value || '';\n\n return value;\n }\n }\n};\n\n// Types whose value stays a string, even when the text looks like a number\n// or an object. `jsx` and `richtext` hold source code, which `update` writes\n// back as an expression.\nexport const STRING_VALUED_TYPES: ReadonlySet<BindingType> = new Set([\n 'string',\n 'url',\n 'email',\n 'tel',\n 'date',\n 'time',\n 'datetime',\n 'color',\n 'jsx',\n 'richtext',\n]);\n\n// The value as its JS type (number, boolean, object, array or string), for\n// `PanelBinding.value`. `getCurrentValue` gives the source text, for\n// `PanelBinding.rawValue` (#238). A string literal in the source stays a\n// string whatever it contains; only expressions such as `count={3}` or\n// `data={[...]}` are read into their real shape.\nexport const getStructuredValue = (\n node: DataAttrNode,\n property: string,\n type?: BindingType,\n): unknown => {\n switch (property) {\n case BINDING_PROP.INNER_TEXT:\n case BINDING_PROP.INNER_HTML: {\n return getCurrentValue(node, property);\n }\n\n case BINDING_PROP.CHILDREN: {\n return node.children ?? [];\n }\n\n default: {\n const raw = getCurrentValue(node, property);\n const attr = node.attributes.find(a => a.name === property);\n\n if (attr?.isStringLiteral || (type && STRING_VALUED_TYPES.has(type))) {\n return raw;\n }\n\n return parseValue(raw);\n }\n }\n};\n\n// The node's bindings. `extract()` resolves them from all three sources\n// (#509, #513); a node built some other way may only have its\n// `data-binding` attribute, which is parsed here.\nexport const readNodeBindings = (node: DataAttrNode): BindingItem[] => {\n if (node.bindings) {\n return node.bindings;\n }\n\n const bindingAttr = node.dataAttributes.find(\n attr => attr.name === DATA_ATTR.BINDING,\n );\n\n return bindingAttr?.value ? parseBinding(bindingAttr.value) : [];\n};\n\nconst hasEditableBindings = (node: DataAttrNode): boolean =>\n readNodeBindings(node).length > 0;\n\nexport const findEditableChildren = (node: DataAttrNode): DataAttrNode[] => {\n const editableChildren: DataAttrNode[] = [];\n\n const traverse = (children: DataAttrNode[] | undefined) => {\n if (!children) {\n return;\n }\n\n for (const child of children) {\n if (hasEditableBindings(child)) {\n editableChildren.push(child);\n }\n traverse(child.children);\n }\n };\n\n traverse(node.children);\n\n return editableChildren;\n};\n","export const removeIndices = <T>(items: T[], indices: Set<number>): T[] => {\n return items.filter((_, index) => !indices.has(index));\n};\n\n/**\n * Shifts every selected index up/down by one step as a block, preserving\n * relative order — scattered selections stop moving individually once they\n * hit an unselected neighbor, so the whole group slides together instead of\n * items passing through each other.\n */\nexport const moveSelectedIndices = <T>(\n items: T[],\n indices: Set<number>,\n direction: 'up' | 'down',\n): { items: T[]; indices: Set<number> } => {\n const next = [...items];\n const nextIndices = new Set(indices);\n\n const ordered = [...indices].sort((a, b) =>\n direction === 'up' ? a - b : b - a,\n );\n\n for (const index of ordered) {\n const target = direction === 'up' ? index - 1 : index + 1;\n\n if (target < 0 || target >= next.length || nextIndices.has(target)) {\n continue;\n }\n\n [next[index], next[target]] = [next[target]!, next[index]!];\n nextIndices.delete(index);\n nextIndices.add(target);\n }\n\n return { items: next, indices: nextIndices };\n};\n","import { parse } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { nanoid } from 'nanoid';\n\nimport { BINDING_PROP, CONFIG, DATA_ATTR } from '../../constants';\nimport { type BoundedCache, createBoundedCache } from '../cache';\nimport { registerEditorCache } from '../editor-caches';\nimport {\n parseBinding,\n parseBindingExpression,\n resolveBindings,\n} from './binding';\nimport { traverse } from './document';\nimport { attrValue, generateCode, wrap } from './helpers';\nimport { getJSXTagName } from './jsx-name';\nimport type {\n Attribute,\n BindingItem,\n BindingOptions,\n DataAttrNode,\n} from './types';\nimport { unwrapExpression } from './value';\n\nconst collectText = (\n children: (\n | t.JSXText\n | t.JSXExpressionContainer\n | t.JSXElement\n | t.JSXFragment\n | t.JSXSpreadChild\n )[],\n) => {\n return children\n .filter(c => t.isJSXText(c))\n .map(c => (c as t.JSXText).value.trim())\n .filter(v => v.length)\n .join(' ');\n};\n\nconst parseJSXName = (\n tagName: string,\n): t.JSXIdentifier | t.JSXMemberExpression => {\n const parts = tagName.split('.');\n\n if (parts.length === 1) {\n return t.jsxIdentifier(parts[0]!);\n }\n\n let expr: t.JSXIdentifier | t.JSXMemberExpression = t.jsxIdentifier(\n parts[0]!,\n );\n\n for (let i = 1; i < parts.length; i++) {\n expr = t.jsxMemberExpression(expr, t.jsxIdentifier(parts[i]!));\n }\n\n return expr;\n};\n\nconst extractCache = createBoundedCache<string, DataAttrNode[]>(\n CONFIG.CACHE_LIMIT,\n);\n\n// One cache per combination of `bindings` and `bindingKeys`, since they\n// change what the same source extracts to (#509, #513). An absent map is\n// keyed by `NO_MAP`.\nconst NO_MAP = {};\nlet optionExtractCaches = new WeakMap<\n object,\n WeakMap<object, BoundedCache<string, DataAttrNode[]>>\n>();\n\nconst cacheFor = ({ bindings, bindingKeys }: BindingOptions) => {\n if (!bindings && !bindingKeys) {\n return extractCache;\n }\n\n let byKeys = optionExtractCaches.get(bindings ?? NO_MAP);\n\n if (!byKeys) {\n byKeys = new WeakMap();\n optionExtractCaches.set(bindings ?? NO_MAP, byKeys);\n }\n\n let cache = byKeys.get(bindingKeys ?? NO_MAP);\n\n if (!cache) {\n cache = createBoundedCache<string, DataAttrNode[]>(CONFIG.CACHE_LIMIT);\n byKeys.set(bindingKeys ?? NO_MAP, cache);\n }\n\n return cache;\n};\n\nconst extractAttributes = (\n attributes: (t.JSXAttribute | t.JSXSpreadAttribute)[],\n source?: string,\n): { allAttrs: Attribute[]; dataAttrs: Attribute[] } => {\n const allAttrs: Attribute[] = [];\n const dataAttrs: Attribute[] = [];\n\n for (const attr of attributes) {\n if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name)) {\n continue;\n }\n\n const name = attr.name.name;\n let value: string | null = null;\n let isStringLiteral = false;\n\n if (attr.value) {\n if (t.isStringLiteral(attr.value)) {\n value = attr.value.value;\n isStringLiteral = true;\n } else if (t.isJSXExpressionContainer(attr.value)) {\n try {\n const expression = attr.value.expression;\n const structural =\n t.isArrayExpression(unwrapExpression(expression)) ||\n t.isObjectExpression(unwrapExpression(expression));\n value =\n source &&\n structural &&\n expression.start != null &&\n expression.end != null\n ? source.slice(expression.start, expression.end)\n : generateCode(expression);\n isStringLiteral = false;\n } catch {\n value = null;\n }\n }\n }\n\n const entry = { name, value, isStringLiteral };\n\n allAttrs.push(entry);\n\n if (name.startsWith('data-')) {\n dataAttrs.push(entry);\n }\n }\n\n return { allAttrs, dataAttrs };\n};\n\nconst buildChildElements = (\n node: DataAttrNode,\n): (t.JSXText | t.JSXElement | t.JSXFragment)[] => {\n const childElements: (t.JSXText | t.JSXElement | t.JSXFragment)[] = [];\n\n if (node.textContent) {\n childElements.push(t.jsxText(node.textContent));\n }\n\n node.children?.forEach(child => {\n const childJSX = nodeToJSX(child);\n if (childJSX) {\n childElements.push(childJSX);\n }\n });\n\n return childElements;\n};\n\nexport const nodeToJSX = (\n node: DataAttrNode,\n): t.JSXElement | t.JSXFragment | null => {\n try {\n if (node.isFragment) {\n const childElements = buildChildElements(node);\n\n return t.jsxFragment(\n t.jsxOpeningFragment(),\n t.jsxClosingFragment(),\n childElements,\n );\n }\n\n if (\n node.tagName === 'div' &&\n node.dataAttributes.some(attr => attr.name === 'data-item')\n ) {\n if (node.children) {\n return nodeToJSX(node.children[0]!);\n }\n return null;\n }\n\n const attributes = node.attributes.map(attr => {\n const attrName = t.jsxIdentifier(attr.name);\n\n if (!attr.value) {\n return t.jsxAttribute(attrName, null);\n }\n\n return t.jsxAttribute(attrName, attrValue(attr));\n });\n\n const elementName = parseJSXName(node.tagName);\n\n const openingElement = t.jsxOpeningElement(elementName, attributes);\n\n const closingElement = t.jsxClosingElement(elementName);\n const children = buildChildElements(node);\n\n return t.jsxElement(openingElement, closingElement, children);\n } catch (error) {\n console.error('❌ DataAttrNode to JSX conversion error:', error);\n return null;\n }\n};\n\nconst createWrapperNode = (\n textContent: string,\n children: DataAttrNode[],\n): DataAttrNode => ({\n tagName: 'div',\n id: nanoid(6),\n attributes: [{ name: DATA_ATTR.ITEM, value: 'true' }],\n dataAttributes: [{ name: DATA_ATTR.ITEM, value: 'true' }],\n textContent,\n children,\n});\n\nconst createFragmentNode = (\n textContent: string,\n children: DataAttrNode[],\n): DataAttrNode => ({\n tagName: '',\n id: nanoid(6),\n attributes: [],\n dataAttributes: [],\n textContent,\n children,\n isFragment: true,\n});\n\nconst processChildrenBinding = (\n jsxElement: t.JSXElement,\n processedNodes?: WeakSet<t.JSXElement | t.JSXFragment>,\n shouldWrap: boolean = true,\n source?: string,\n options?: BindingOptions,\n): DataAttrNode[] | undefined => {\n const jsxChildren = jsxElement.children.filter(\n child => t.isJSXElement(child) || t.isJSXFragment(child),\n );\n\n if (!jsxChildren.length) {\n return undefined;\n }\n\n const childrenNodes: DataAttrNode[] = [];\n\n jsxChildren.forEach(child => {\n if (t.isJSXElement(child)) {\n const childResults = extractFromNode(\n child,\n processedNodes,\n source,\n options,\n );\n\n if (shouldWrap) {\n const wrapperNode = createWrapperNode(\n collectText(child.children),\n childResults,\n );\n wrapperNode.source = source?.slice(child.start!, child.end!);\n const dataId = childResults[0]?.dataAttributes.find(\n attr => attr.name === DATA_ATTR.ID,\n )?.value;\n\n if (dataId) {\n wrapperNode.id = `child:${dataId}`;\n }\n\n childrenNodes.push(wrapperNode);\n } else {\n childrenNodes.push(...childResults);\n }\n } else if (t.isJSXFragment(child)) {\n processedNodes?.add(child);\n\n const fragmentChildren: DataAttrNode[] = [];\n\n child.children.forEach(fragmentChild => {\n if (t.isJSXElement(fragmentChild)) {\n const childResults = extractFromNode(\n fragmentChild,\n processedNodes,\n source,\n options,\n );\n fragmentChildren.push(...childResults);\n }\n });\n\n if (fragmentChildren.length) {\n const fragmentNode = createFragmentNode(\n collectText(child.children),\n fragmentChildren,\n );\n fragmentNode.source = source?.slice(child.start!, child.end!);\n childrenNodes.push(fragmentNode);\n }\n }\n });\n\n return childrenNodes.length ? childrenNodes : undefined;\n};\n\nconst skipItemsChildren = (\n jsxElement: t.JSXElement,\n processedNodes: WeakSet<t.JSXElement | t.JSXFragment>,\n propertyName: string = 'items',\n): void => {\n const opening = jsxElement.openingElement;\n\n const itemsAttr = opening.attributes.find(\n attr =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === propertyName,\n );\n\n if (!itemsAttr || !t.isJSXAttribute(itemsAttr)) {\n return;\n }\n\n if (\n itemsAttr.value &&\n t.isJSXExpressionContainer(itemsAttr.value) &&\n t.isArrayExpression(itemsAttr.value.expression)\n ) {\n const arrayExpr = itemsAttr.value.expression;\n\n arrayExpr.elements.forEach(element => {\n if (t.isObjectExpression(element)) {\n element.properties.forEach(prop => {\n if (\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key) &&\n t.isJSXElement(prop.value)\n ) {\n markProcessedJSX(prop.value, processedNodes);\n }\n });\n }\n });\n }\n};\n\nconst markProcessedJSX = (\n node: t.Node,\n processedNodes: WeakSet<t.JSXElement | t.JSXFragment>,\n): void => {\n if (t.isJSXElement(node) || t.isJSXFragment(node)) {\n processedNodes.add(node as t.JSXElement | t.JSXFragment);\n node.children.forEach(child => markProcessedJSX(child, processedNodes));\n return;\n }\n\n const expression =\n t.isJSXExpressionContainer(node) || t.isParenthesizedExpression(node);\n\n if (expression) {\n markProcessedJSX(node.expression, processedNodes);\n }\n};\n\ninterface NodeBindingInfo {\n tagName: string;\n allAttrs: Attribute[];\n dataAttrs: Attribute[];\n bindings: BindingItem[];\n childrenBinding: BindingItem | undefined;\n arrayBindings: BindingItem[];\n rawChildren: string | undefined;\n}\n\n// The `data-binding` array expression, so bindings can be read from the AST\n// without printing and parsing it again. `null` when the attribute is\n// missing or a plain string, which goes through `parseBinding` instead.\nconst getBindingExpression = (\n opening: t.JSXOpeningElement,\n): t.ArrayExpression | null => {\n for (const attr of opening.attributes) {\n if (\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === DATA_ATTR.BINDING &&\n attr.value &&\n t.isJSXExpressionContainer(attr.value)\n ) {\n // Unwrap `satisfies BindingItem[]`, `as const` and parentheses.\n const expression = unwrapExpression(attr.value.expression);\n\n if (t.isArrayExpression(expression)) {\n return expression;\n }\n }\n }\n\n return null;\n};\n\n// Reads one element's tag name, attributes and bindings. Shared by the\n// top-level visitor in `parseToNodes` and by `extractFromNode`.\nconst readNodeBindingInfo = (\n node: t.JSXElement,\n source?: string,\n options?: BindingOptions,\n): NodeBindingInfo => {\n const opening = node.openingElement;\n const tagName = getJSXTagName(opening);\n const { allAttrs, dataAttrs } = extractAttributes(opening.attributes, source);\n\n const bindingAttr = dataAttrs.find(attr => attr.name === DATA_ATTR.BINDING);\n const bindingExpr = getBindingExpression(opening);\n const keyAttr = dataAttrs.find(attr => attr.name === DATA_ATTR.BINDING_KEY);\n // Its own `data-binding` first, even an empty one (how an element opts\n // out), then its `data-binding-key`, then its component's entry\n // (#509, #513).\n const bindings = resolveBindings(\n bindingExpr\n ? parseBindingExpression(bindingExpr)\n : bindingAttr\n ? parseBinding(bindingAttr.value)\n : undefined,\n keyAttr && (keyAttr.isStringLiteral ? keyAttr.value : null),\n tagName,\n options,\n );\n\n const childrenBinding = bindings.find(\n b => b.property === BINDING_PROP.CHILDREN,\n );\n const arrayBindings = bindings.filter(\n b => b.property === BINDING_PROP.ITEMS || b.type === 'array',\n );\n\n const innerHtmlBinding = bindings.find(\n b => b.property === BINDING_PROP.INNER_HTML,\n );\n\n let rawChildren: string | undefined;\n if (innerHtmlBinding && node.children.length > 0) {\n rawChildren = node.children\n .map(child => generateCode(child))\n .join('')\n .trim();\n }\n\n return {\n tagName,\n allAttrs,\n dataAttrs,\n bindings,\n childrenBinding,\n arrayBindings,\n rawChildren,\n };\n};\n\nconst parseToNodes = (\n raw: string,\n options?: BindingOptions,\n): DataAttrNode[] => {\n const wrapped = wrap(raw);\n const ast = parse(wrapped, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n errorRecovery: true,\n });\n\n const results: DataAttrNode[] = [];\n\n // Elements already recorded as another result's children, or skipped\n // inside an `items` array. `traverse()` visits every element, so the\n // visitor skips these to avoid recording them twice.\n const processedNodes = new WeakSet<t.JSXElement | t.JSXFragment>();\n\n traverse(ast, {\n JSXElement(path) {\n if (processedNodes.has(path.node)) {\n return;\n }\n\n const {\n tagName,\n allAttrs,\n dataAttrs,\n bindings,\n childrenBinding,\n arrayBindings,\n rawChildren,\n } = readNodeBindingInfo(path.node, wrapped, options);\n\n if (!tagName || !dataAttrs.length) {\n return;\n }\n\n let childrenNodes: DataAttrNode[] | undefined;\n\n if (childrenBinding) {\n childrenNodes = processChildrenBinding(\n path.node,\n processedNodes,\n true,\n wrapped,\n options,\n );\n }\n\n for (const arrayBinding of arrayBindings) {\n skipItemsChildren(path.node, processedNodes, arrayBinding.property);\n }\n\n results.push({\n tagName,\n attributes: allAttrs,\n dataAttributes: dataAttrs,\n textContent: collectText(path.node.children),\n rawChildren,\n children: childrenNodes,\n bindings,\n loc: path.node.loc\n ? {\n start: {\n line: path.node.loc.start.line,\n column: path.node.loc.start.column,\n },\n end: {\n line: path.node.loc.end.line,\n column: path.node.loc.end.column,\n },\n }\n : undefined,\n });\n },\n });\n\n return results;\n};\n\n// The elements of `raw` that carry `data-*` attributes, with their\n// bindings, as `DataAttrNode`s. Cached. `options` supplies bindings for\n// elements without their own `data-binding` (#509, #513).\nexport function extract(\n raw: string,\n options: BindingOptions = {},\n): DataAttrNode[] {\n const cache = cacheFor(options);\n\n if (cache.has(raw)) {\n return cache.get(raw)!;\n }\n\n const results = parseToNodes(raw, options);\n\n cache.set(raw, results);\n\n return results;\n}\n\nfunction extractFromNode(\n node: t.JSXElement,\n processedNodes?: WeakSet<t.JSXElement | t.JSXFragment>,\n source?: string,\n options?: BindingOptions,\n): DataAttrNode[] {\n processedNodes?.add(node);\n\n const {\n tagName,\n allAttrs,\n dataAttrs,\n bindings,\n childrenBinding,\n rawChildren,\n } = readNodeBindingInfo(node, source, options);\n\n let childrenNodes: DataAttrNode[] | undefined;\n\n if (childrenBinding) {\n childrenNodes = processChildrenBinding(\n node,\n processedNodes,\n true,\n source,\n options,\n );\n }\n\n if (!childrenNodes) {\n childrenNodes = processChildrenBinding(\n node,\n processedNodes,\n false,\n source,\n options,\n );\n }\n\n return [\n {\n tagName,\n attributes: allAttrs,\n dataAttributes: dataAttrs,\n textContent: collectText(node.children),\n rawChildren,\n children: childrenNodes,\n bindings,\n },\n ];\n}\n\nexport function clearExtractCache() {\n extractCache.clear();\n optionExtractCaches = new WeakMap();\n}\n\nregisterEditorCache(clearExtractCache);\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { nanoid } from 'nanoid';\n\nimport { moveSelectedIndices } from '../selection';\nimport { extract, nodeToJSX } from './extract';\nimport { generateCode } from './helpers';\nimport { type SourceEdit, applyEdits } from './patch';\nimport type { BindingOptions, DataAttrNode } from './types';\n\nexport type ChildrenAction =\n | { type: 'move'; from: number; to: number }\n | { type: 'move-selected'; indices: number[]; direction: 'up' | 'down' }\n | { type: 'remove' | 'duplicate'; indices: number[] }\n | { type: 'append' };\n\nexport interface ChildrenEdit {\n kind: 'children-edit';\n expected: string[];\n action: ChildrenAction;\n}\n\n// Signatures address the extracted list, not synthetic wrapper IDs. The\n// source editor checks them against the latest parent before using indices.\nconst modeledSignatures = (nodes: DataAttrNode[]): string[] =>\n nodes.map(node => {\n const jsx = nodeToJSX(node);\n\n if (!jsx) {\n throw new Error('Invalid child node');\n }\n\n return generateCode(jsx);\n });\n\nexport const getChildrenSignatures = (nodes: DataAttrNode[]): string[] => {\n const modeled = modeledSignatures(nodes);\n\n return nodes.map((node, index) =>\n JSON.stringify([node.source ?? null, modeled[index]]),\n );\n};\n\nconst indicesAreValid = (\n indices: unknown,\n count: number,\n): indices is number[] =>\n Array.isArray(indices) &&\n new Set(indices).size === indices.length &&\n indices.every(\n index => Number.isInteger(index) && index >= 0 && index < count,\n );\n\n// Only ID attributes are replaced: expressions, spreads, comments and text\n// in a copied subtree retain their exact source. Dynamic IDs are ambiguous.\nconst copySource = (source: string, usedIds: Set<string>): string => {\n const node = parseExpression(source, { plugins: ['jsx', 'typescript'] });\n const edits: SourceEdit[] = [];\n const newId = () => {\n let id = nanoid(12);\n\n while (usedIds.has(id)) {\n id = nanoid(12);\n }\n\n usedIds.add(id);\n\n return id;\n };\n\n t.traverseFast(node, child => {\n if (!t.isJSXOpeningElement(child)) {\n return;\n }\n\n const ids = child.attributes.filter(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name, { name: 'data-id' }),\n );\n\n if (ids.length > 1) {\n throw new Error('Duplicate data-id attributes');\n }\n\n const attr = ids[0];\n\n if (\n attr &&\n child.attributes\n .slice(child.attributes.indexOf(attr) + 1)\n .some(attribute => t.isJSXSpreadAttribute(attribute))\n ) {\n throw new Error('A spread may override the copied data-id');\n }\n\n if (attr) {\n const value = attr.value;\n\n if (\n !t.isStringLiteral(value) ||\n value.start == null ||\n value.end == null\n ) {\n throw new Error('Cannot copy a dynamic data-id');\n }\n\n edits.push({\n start: value.start,\n end: value.end,\n content: JSON.stringify(newId()),\n });\n } else {\n const at = child.attributes.at(-1)?.end ?? child.name.end;\n\n if (at == null) {\n throw new Error('Missing opening element span');\n }\n\n edits.push({\n start: at,\n end: at,\n content: ` data-id=\"${newId()}\"`,\n });\n }\n });\n\n return applyEdits(source, edits);\n};\n\n// The edit that adds new children after the existing ones. In a parent\n// written one child per line, each new child goes on its own line under the\n// last one, with the same indentation and line ending, so the list keeps its\n// layout. Anything else, such as a parent on one line or a comment after the\n// last child on its line, puts them right before the closing tag, where\n// nothing around them can move.\nconst insertChildren = (\n source: string,\n parent: t.JSXElement,\n last: t.JSXElement | t.JSXFragment | undefined,\n copies: string[],\n): SourceEdit => {\n const closing = parent.closingElement!.start!;\n\n if (last?.start != null && last.end != null) {\n const lineStart = source.lastIndexOf('\\n', last.start - 1) + 1;\n const indent = source.slice(lineStart, last.start);\n const after = /^[ \\t]*(\\r?\\n)/.exec(source.slice(last.end, closing));\n\n if (after && /^[ \\t]*$/.test(indent)) {\n return {\n start: last.end,\n end: last.end,\n content: copies.map(copy => `${after[1]}${indent}${copy}`).join(''),\n };\n }\n }\n\n return { start: closing, end: closing, content: copies.join('') };\n};\n\n// Coordinates refer to the caller's wrapped source, just like other update\n// editors. Non-element gaps stay at their original positions; moving a JSX\n// child moves its entire subtree but never regenerates intervening content.\nexport const editChildrenSource = (\n source: string,\n parent: t.JSXElement,\n input: unknown,\n // The binding sources the caller extracted the children with, so they're\n // modeled the same way here (#509, #513).\n options?: BindingOptions,\n): SourceEdit[] | null => {\n try {\n if (!parent.closingElement || parent.start == null || parent.end == null) {\n return null;\n }\n\n const value = typeof input === 'string' ? JSON.parse(input) : input;\n const children = parent.children.filter(\n (child): child is t.JSXElement | t.JSXFragment =>\n t.isJSXElement(child) || t.isJSXFragment(child),\n );\n const raw = children.map(child => source.slice(child.start!, child.end!));\n const models =\n extract(source.slice(parent.start, parent.end), options)[0]?.children ??\n [];\n\n // The extractor currently omits some empty/expression-only fragments.\n // Never interpret its visible indices as different source children.\n if (models.length !== children.length) {\n return null;\n }\n\n const signatures = modeledSignatures(models);\n const replaceSlots = (next: string[]): SourceEdit[] => {\n const edits = children.map((child, index) => ({\n start: child.start!,\n end: child.end!,\n content: next[index] ?? '',\n }));\n\n if (next.length > children.length) {\n edits.push(\n insertChildren(\n source,\n parent,\n children.at(-1),\n next.slice(children.length),\n ),\n );\n }\n\n return edits;\n };\n\n if (Array.isArray(value)) {\n // A full list of children (the JSON form). Unchanged children keep\n // their original source; other replacements are allowed only when\n // every original child can be represented without loss.\n const desired = modeledSignatures(value);\n const lossless = raw.every(\n (text, index) =>\n generateCode(\n parseExpression(text, { plugins: ['jsx', 'typescript'] }),\n ) === signatures[index],\n );\n const consumed = new Set<number>();\n const next = desired.map((signature, position) => {\n const index = signatures.findIndex(\n (candidate, i) =>\n candidate === signature &&\n !consumed.has(i) &&\n (value[position].source === undefined ||\n value[position].source === raw[i]),\n );\n\n if (index >= 0) {\n consumed.add(index);\n\n return raw[index]!;\n }\n\n if (\n !lossless ||\n (value[position].source !== undefined &&\n !raw.includes(value[position].source))\n ) {\n throw new Error(\n 'Use children commands to copy or edit unsupported source',\n );\n }\n\n return signature;\n });\n\n // The list may contain new children. Refuse a repeated `data-id`,\n // which would make later edits ambiguous.\n const countIds = (text: string) => {\n const counts = new Map<string, number>();\n t.traverseFast(\n parseExpression(text, { plugins: ['jsx', 'typescript'] }),\n node => {\n if (\n t.isJSXAttribute(node) &&\n t.isJSXIdentifier(node.name, { name: 'data-id' }) &&\n t.isStringLiteral(node.value)\n ) {\n counts.set(\n node.value.value,\n (counts.get(node.value.value) ?? 0) + 1,\n );\n }\n },\n );\n\n return counts;\n };\n const previousIds = countIds(source);\n const updatedParent = applyEdits(source, replaceSlots(next));\n const nextIds = countIds(updatedParent);\n\n if (\n [...nextIds].some(\n ([id, count]) => count > 1 && count > (previousIds.get(id) ?? 0),\n )\n ) {\n return null;\n }\n\n return replaceSlots(next);\n }\n\n const request = value as ChildrenEdit | null;\n\n if (\n request?.kind !== 'children-edit' ||\n !Array.isArray(request.expected) ||\n request.expected.length !== signatures.length ||\n !getChildrenSignatures(models).every(\n (signature, index) => signature === request.expected[index],\n ) ||\n !request.action\n ) {\n return null;\n }\n\n const { action } = request;\n const usedIds = new Set<string>();\n\n t.traverseFast(parent, node => {\n if (\n t.isJSXAttribute(node) &&\n t.isJSXIdentifier(node.name, { name: 'data-id' }) &&\n t.isStringLiteral(node.value)\n ) {\n usedIds.add(node.value.value);\n }\n });\n\n switch (action.type) {\n case 'move': {\n if (\n !indicesAreValid([action.from], raw.length) ||\n !indicesAreValid([action.to], raw.length)\n ) {\n return null;\n }\n\n const next = [...raw];\n const [moved] = next.splice(action.from, 1);\n next.splice(action.to, 0, moved!);\n\n return replaceSlots(next);\n }\n case 'move-selected': {\n if (\n !indicesAreValid(action.indices, raw.length) ||\n !['up', 'down'].includes(action.direction)\n ) {\n return null;\n }\n\n return replaceSlots(\n moveSelectedIndices(raw, new Set(action.indices), action.direction)\n .items,\n );\n }\n case 'remove': {\n if (!indicesAreValid(action.indices, raw.length)) {\n return null;\n }\n\n return action.indices.map(index => ({\n start: children[index]!.start!,\n end: children[index]!.end!,\n content: '',\n }));\n }\n case 'duplicate': {\n if (!indicesAreValid(action.indices, raw.length)) {\n return null;\n }\n\n const copies = [...action.indices]\n .sort((a, b) => a - b)\n .map(index => copySource(raw[index]!, usedIds));\n\n return [insertChildren(source, parent, children.at(-1), copies)];\n }\n case 'append': {\n const copy = copySource(raw[0] ?? '<div></div>', usedIds);\n\n return [insertChildren(source, parent, children.at(-1), [copy])];\n }\n default:\n return null;\n }\n } catch {\n return null;\n }\n};\n","import * as t from '@babel/types';\n\nimport type { NodeValueType } from './types';\n\n// Builds AST expressions and source text from JS values: the inverse of\n// reading them in `value.ts`.\n\nexport const createNodeFromValue = (\n type: NodeValueType,\n value: unknown,\n): t.Expression | null => {\n switch (type) {\n case 'boolean': {\n return t.booleanLiteral(value === true);\n }\n case 'number': {\n return t.numericLiteral(Number(value));\n }\n case 'string': {\n return t.stringLiteral(String(value));\n }\n case 'null': {\n return t.nullLiteral();\n }\n case 'array':\n case 'object':\n case 'unknown': {\n return null;\n }\n default: {\n return null;\n }\n }\n};\n\n// Builds an expression for a JS value: the inverse of `evaluateLiteral`\n// (#238). Each JS type maps to one kind of literal. Values with no literal\n// form (`undefined`, functions, symbols) give `null`. Inside an object the\n// property is left out; inside an array the item becomes `null`.\nexport const valueToExpression = (value: unknown): t.Expression | null => {\n if (typeof value === 'string') {\n return t.stringLiteral(value);\n }\n\n if (typeof value === 'number') {\n return value < 0\n ? t.unaryExpression('-', t.numericLiteral(-value))\n : t.numericLiteral(value);\n }\n\n if (typeof value === 'boolean') {\n return t.booleanLiteral(value);\n }\n\n if (value === null) {\n return t.nullLiteral();\n }\n\n if (Array.isArray(value)) {\n return t.arrayExpression(\n value.map(item => valueToExpression(item) ?? t.nullLiteral()),\n );\n }\n\n if (typeof value === 'object') {\n const properties: t.ObjectProperty[] = [];\n\n for (const [key, item] of Object.entries(value)) {\n const expr = valueToExpression(item);\n if (expr === null) {\n continue;\n }\n properties.push(t.objectProperty(t.stringLiteral(key), expr));\n }\n\n return t.objectExpression(properties);\n }\n\n return null;\n};\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\n\nimport { STRING_VALUED_TYPES } from './binding';\nimport { generateCode } from './helpers';\nimport type { SourceEdit } from './patch';\nimport type { BindingType } from './types';\nimport { isLosslesslyEvaluable, unwrapExpression } from './value';\nimport { valueToExpression } from './value-expression';\n\n// The source editors behind `update`: each turns one property edit on one\n// element into source spans, and never touches the tree.\n\n// What each editor below returns: the source spans to change, never a\n// changed tree, so everything else stays byte-identical (#239). An empty\n// array means \"handled, nothing to write\"; `null` means the edit failed.\nexport type EditResult = SourceEdit[] | null;\n\n// The span between `>` and `</`, i.e. everything the element encloses.\n// `null` for a self-closing element, which has nowhere to put children.\nexport const childrenRange = (\n element: t.JSXElement,\n): { start: number; end: number } | null => {\n const { openingElement, closingElement } = element;\n\n if (\n !closingElement ||\n openingElement.end == null ||\n closingElement.start == null\n ) {\n return null;\n }\n\n return { start: openingElement.end, end: closingElement.start };\n};\n\nexport const findAttribute = (\n opening: t.JSXOpeningElement,\n propertyName: string,\n): t.JSXAttribute | undefined => {\n return opening.attributes.find(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === propertyName,\n );\n};\n\n// Where a new attribute goes: after the last attribute, or after the\n// element name when there are none.\nconst attributeInsertPoint = (opening: t.JSXOpeningElement): number | null => {\n const last = opening.attributes[opening.attributes.length - 1];\n\n return last?.end ?? opening.name.end ?? null;\n};\n\n// Escapes a string for JSX text, where `<`, `>`, `{` and `}` are syntax and\n// `&` starts an entity. They are written as entities, which the panel reads\n// back as the typed characters. `&` is escaped only when it starts something\n// entity-like, so a typed `&amp;` stays literal and `Tom & Jerry` is written\n// as is. `&` goes first, so the entities added below aren't escaped again.\nconst escapeJsxText = (value: string): string =>\n value\n .replace(/&(?=#?[A-Za-z0-9]+;)/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\\{/g, '&#123;')\n .replace(/\\}/g, '&#125;');\n\n// Replaces the element's text. With a single text child, only the trimmed\n// text is replaced, so the line breaks and indentation around it stay\n// (#239). Otherwise every text child is removed and `value` is written just\n// before the closing tag; nested elements stay.\n//\n// A self-closing element has nowhere to put text: this returns no edits,\n// and `update` reports success without changing anything.\nexport const editInnerText = (\n source: string,\n element: t.JSXElement,\n value: string,\n): EditResult => {\n const range = childrenRange(element);\n\n if (!range) {\n return [];\n }\n\n const text = escapeJsxText(value);\n const [only] = element.children;\n\n if (\n element.children.length === 1 &&\n t.isJSXText(only) &&\n only.start != null &&\n only.end != null\n ) {\n // Measure the raw source, not `only.value`: Babel decodes entities and\n // CRLF in `value`, so its lengths don't match the source offsets.\n // `&nbsp;Old&nbsp;` would otherwise become `&New;`.\n const raw = source.slice(only.start, only.end);\n\n if (raw.trim() !== '') {\n const leadingSpace = raw.slice(0, raw.length - raw.trimStart().length);\n const trailingSpace = raw.slice(raw.trimEnd().length);\n // Only whitespace with a line break is layout. JSX keeps same-line\n // whitespace in the string while the panel value hides it, so the\n // edit overwrites that.\n const leading = /[\\r\\n]/.test(leadingSpace) ? leadingSpace.length : 0;\n const trailing = /[\\r\\n]/.test(trailingSpace) ? trailingSpace.length : 0;\n\n return [\n {\n start: only.start + leading,\n end: only.end - trailing,\n content: text,\n },\n ];\n }\n }\n\n const edits: SourceEdit[] = [];\n\n for (const child of element.children) {\n if (t.isJSXText(child) && child.start != null && child.end != null) {\n edits.push({ start: child.start, end: child.end, content: '' });\n }\n }\n\n edits.push({ start: range.end, end: range.end, content: text });\n\n return edits;\n};\n\n// Replaces the element's children with the raw HTML, as written.\nexport const editInnerHTML = (\n element: t.JSXElement,\n value: string,\n): EditResult => {\n const range = childrenRange(element);\n\n if (!range) {\n return [];\n }\n\n return [{ start: range.start, end: range.end, content: value }];\n};\n\nexport const editRichtext = (\n element: t.JSXElement,\n value: string,\n): EditResult => {\n const edits: SourceEdit[] = [];\n const range = childrenRange(element);\n\n // richtext owns the element's content, so any prior markup goes.\n if (range && range.start !== range.end) {\n edits.push({ start: range.start, end: range.end, content: '' });\n }\n\n const opening = element.openingElement;\n const attribute = t.jsxAttribute(\n t.jsxIdentifier('dangerouslySetInnerHTML'),\n t.jsxExpressionContainer(\n t.objectExpression([\n t.objectProperty(t.identifier('__html'), t.stringLiteral(value)),\n ]),\n ),\n );\n const content = generateCode(attribute);\n const existing = findAttribute(opening, 'dangerouslySetInnerHTML');\n\n if (existing && existing.start != null && existing.end != null) {\n edits.push({\n start: existing.start,\n end: existing.end,\n content,\n indent: true,\n });\n\n return edits;\n }\n\n const insertAt = attributeInsertPoint(opening);\n\n if (insertAt == null) {\n return null;\n }\n\n edits.push({\n start: insertAt,\n end: insertAt,\n content: ` ${content}`,\n indent: true,\n });\n\n return edits;\n};\n\n// A `type: 'jsx'` value is arbitrary user-authored JSX, so it goes in as\n// written rather than being parsed into nodes and printed back out.\nexport const editJsxAttribute = (\n opening: t.JSXOpeningElement,\n propertyName: string,\n value: unknown,\n): EditResult => {\n const attribute = findAttribute(opening, propertyName);\n\n if (!attribute) {\n return null;\n }\n\n const content = `{${String(value).trim()}}`;\n\n if (attribute.value?.start != null && attribute.value.end != null) {\n return [\n {\n start: attribute.value.start,\n end: attribute.value.end,\n content,\n },\n ];\n }\n\n // Valueless shorthand (`<Icon icon />`): there is no value span to\n // overwrite, so append one after the attribute name.\n const insertAt = attribute.name.end;\n\n if (insertAt == null) {\n return null;\n }\n\n return [{ start: insertAt, end: insertAt, content: `=${content}` }];\n};\n\n// Whether the attribute holds an array or object literal, such as\n// `items={[...]}`. Other expressions (`className={cn(...)}`,\n// `items={rows}`) don't count: the panel doesn't edit their source, so a\n// string committed to them stays a string.\nconst holdsStructuralExpression = (value?: t.JSXAttribute['value']): boolean =>\n t.isJSXExpressionContainer(value) &&\n (t.isArrayExpression(unwrapExpression(value.expression)) ||\n t.isObjectExpression(unwrapExpression(value.expression)));\n\n// Parses committed text as an array or object literal, or `null`. Only\n// those shapes are accepted: `hello` also parses, as an identifier, and\n// writing `items={hello}` would turn a value into a variable reference.\nconst structuralSource = (value: string): t.Expression | null => {\n try {\n const expression = parseExpression(value.trim(), {\n plugins: ['jsx', 'typescript'],\n });\n\n return t.isArrayExpression(unwrapExpression(expression)) ||\n t.isObjectExpression(unwrapExpression(expression))\n ? expression\n : null;\n } catch {\n return null;\n }\n};\n\n// Whether a string has a control character: a line break, a tab, and so on.\nconst hasControlCharacter = (value: string): boolean =>\n Array.from(value).some(char => char.charCodeAt(0) < 0x20);\n\n// A string as the value of a JSX attribute, which has its own rules: no\n// backslash escapes, and `&` starts an entity. Babel prints a string literal\n// by JavaScript rules (`\"a\\\"b\"`, `\"C:\\\\dir\"`), which JSX would read as a\n// different value or fail to parse, so the text is written as given\n// (`extra.raw`).\n//\n// - A control character goes in `{\"...\"}`. A line break in an attribute\n// string followed by spaces compiles to one space, so only the expression\n// form keeps it.\n// - Otherwise the quote with fewer escapes: `'` for a value that has `\"` and\n// no `'`, else `\"` with `&quot;` for any `\"` inside.\n// - `&` becomes `&amp;` when it starts something entity-like, so a typed\n// `&amp;` stays literal. A lone `&` is written as is.\nconst jsxStringValue = (\n value: string,\n): t.StringLiteral | t.JSXExpressionContainer => {\n if (hasControlCharacter(value)) {\n return t.jsxExpressionContainer(t.stringLiteral(value));\n }\n\n const quote = value.includes('\"') && !value.includes(\"'\") ? \"'\" : '\"';\n const text = value.replace(/&(?=#?[A-Za-z0-9]+;)/g, '&amp;');\n const escaped = quote === '\"' ? text.replace(/\"/g, '&quot;') : text;\n const literal = t.stringLiteral(value);\n\n literal.extra = { raw: `${quote}${escaped}${quote}`, rawValue: value };\n\n return literal;\n};\n\n// Builds the JSX attribute value for a value and its declared `type`\n// (#238). `current` is the value being replaced. Without a declared type,\n// as in most `items` bindings, `current` decides whether the value is\n// source code or a string, the same way `getStructuredValue` reads it.\nconst buildAttributeValue = (\n value: unknown,\n type?: BindingType,\n current?: t.JSXAttribute['value'],\n): t.JSXAttribute['value'] => {\n // Declared object or array: an expression. A string here is source text\n // from the Items or object editor, so parse it instead of quoting it.\n if (type === 'array' || type === 'object') {\n if (typeof value === 'string') {\n try {\n return t.jsxExpressionContainer(\n parseExpression(value.trim(), { plugins: ['jsx', 'typescript'] }),\n );\n } catch {\n return jsxStringValue(value);\n }\n }\n\n const expr = valueToExpression(value);\n return expr ? t.jsxExpressionContainer(expr) : t.stringLiteral('');\n }\n\n // Otherwise each JS type maps to one kind of literal. A string stays a\n // string literal whatever it contains.\n if (typeof value === 'string') {\n // Except when the attribute holds an array or object literal: then the\n // string is its source text from the array editor. Quoting it would turn\n // `items={[...]}` into a string and break the document.\n if (\n holdsStructuralExpression(current) &&\n !(type && STRING_VALUED_TYPES.has(type))\n ) {\n const structural = structuralSource(value);\n\n if (structural) {\n return t.jsxExpressionContainer(structural);\n }\n }\n\n return jsxStringValue(value);\n }\n\n const expr = valueToExpression(value);\n return expr ? t.jsxExpressionContainer(expr) : jsxStringValue(String(value));\n};\n\nexport const editAttribute = (\n opening: t.JSXOpeningElement,\n propertyName: string,\n value: unknown,\n type?: BindingType,\n): EditResult => {\n const attribute = findAttribute(opening, propertyName);\n\n if (!attribute || attribute.start == null || attribute.end == null) {\n return null;\n }\n\n // Array or object source from the editors: check its shape, then replace\n // only the expression, so the unchanged items keep their formatting.\n if (\n typeof value === 'string' &&\n (type === 'array' ||\n type === 'object' ||\n (holdsStructuralExpression(attribute.value) &&\n !(type && STRING_VALUED_TYPES.has(type))))\n ) {\n const expression = structuralSource(value);\n\n if (expression && t.isJSXExpressionContainer(attribute.value)) {\n const text = value.trim();\n const lineComment = expression.trailingComments?.some(\n comment => comment.type === 'CommentLine',\n );\n\n return [\n {\n start: attribute.value.expression.start!,\n end: attribute.value.expression.end!,\n content: `${text}${lineComment ? '\\n' : ''}`,\n },\n ];\n }\n }\n\n // Print the whole attribute, so Babel decides the quoting and escaping.\n // The parsed name node is reused, so namespaced and dashed names stay as\n // written.\n const content = generateCode(\n t.jsxAttribute(\n attribute.name,\n buildAttributeValue(value, type, attribute.value),\n ),\n );\n\n return [\n { start: attribute.start, end: attribute.end, content, indent: true },\n ];\n};\n\n// Up to and including the line break: spaces, single-line block comments\n// and one line comment.\nconst TRAILING_COMMENTS =\n /^[ \\t]*(?:\\/\\*[^\\r\\n]*?\\*\\/[ \\t]*)*(?:\\/\\/[^\\r\\n]*)?\\r?\\n/;\n\n// Removes an attribute and the whitespace before it, leaving no gap. A\n// caller asks for this with `undefined`, since React treats an `undefined`\n// prop like a missing one (#426). An attribute alone on its line goes with\n// the comments after it, so they don't end up beside the previous attribute.\nexport const removeAttribute = (\n source: string,\n attribute: t.JSXAttribute,\n): EditResult => {\n if (attribute.start == null || attribute.end == null) {\n return null;\n }\n\n const lineStart = source.lastIndexOf('\\n', attribute.start - 1) + 1;\n const rest = TRAILING_COMMENTS.exec(source.slice(attribute.end));\n\n if (/^[ \\t]*$/.test(source.slice(lineStart, attribute.start)) && rest) {\n return [\n { start: lineStart, end: attribute.end + rest[0].length, content: '' },\n ];\n }\n\n let start = attribute.start;\n\n while (start > 0 && /\\s/.test(source[start - 1]!)) {\n start -= 1;\n }\n\n return [{ start, end: attribute.end, content: '' }];\n};\n\n// Adds a missing attribute after the last one. Only for a real value:\n// clearing a field never creates the attribute (#426). When the last\n// attribute is on its own line, the new one goes on the next line with the\n// same indentation.\nexport const addAttribute = (\n source: string,\n opening: t.JSXOpeningElement,\n propertyName: string,\n value: unknown,\n type?: BindingType,\n): EditResult => {\n const insertAt = attributeInsertPoint(opening);\n\n if (insertAt == null) {\n return null;\n }\n\n // With `indent: true`, a newline is enough to line the new attribute up\n // under the last one.\n const lastStart = opening.attributes[opening.attributes.length - 1]?.start;\n const lineStart =\n lastStart == null ? -1 : source.lastIndexOf('\\n', lastStart - 1) + 1;\n const ownLine =\n lastStart != null &&\n lineStart > 0 &&\n /^\\s*$/.test(source.slice(lineStart, lastStart));\n const separator = ownLine ? '\\n' : ' ';\n\n const content =\n type === 'jsx'\n ? `${propertyName}={${String(value).trim()}}`\n : generateCode(\n t.jsxAttribute(\n t.jsxIdentifier(propertyName),\n buildAttributeValue(value, type),\n ),\n );\n\n return [\n {\n start: insertAt,\n end: insertAt,\n content: `${separator}${content}`,\n indent: true,\n },\n ];\n};\n\nexport const canEditAttributeValue = (\n attribute: t.JSXAttribute,\n value: unknown,\n type?: BindingType,\n) => {\n if (\n !t.isJSXExpressionContainer(attribute.value) ||\n t.isJSXEmptyExpression(attribute.value.expression) ||\n isLosslesslyEvaluable(attribute.value.expression)\n ) {\n return true;\n }\n\n // The array and object editors commit checked source text, which keeps\n // every expression, so accept it.\n return (\n typeof value === 'string' &&\n holdsStructuralExpression(attribute.value) &&\n !(type && STRING_VALUED_TYPES.has(type)) &&\n structuralSource(value) !== null\n );\n};\n","import { parse } from '@babel/parser';\nimport * as t from '@babel/types';\n\nimport {\n BINDING_PROP,\n DATA_ATTR,\n RESERVED_BINDING_PROPERTIES,\n} from '../../constants';\nimport { parseBinding, resolveBindings } from './binding';\nimport { editChildrenSource } from './children';\nimport { traverse } from './document';\nimport {\n type EditResult,\n addAttribute,\n canEditAttributeValue,\n childrenRange,\n editAttribute,\n editInnerHTML,\n editInnerText,\n editJsxAttribute,\n editRichtext,\n findAttribute,\n removeAttribute,\n} from './edit-source';\nimport { generateCode, unwrap, wrap } from './helpers';\nimport { getJSXTagName } from './jsx-name';\nimport { type SourceEdit, applyEdits } from './patch';\nimport type { BindingItem, BindingOptions } from './types';\n\n// Why an edit failed, with what a caller needs to name the cause (#270).\n// The cause is usually a wrong `property` or `label` in the element's\n// `data-binding`, not the value just typed.\nexport type UpdateFailure =\n | { reason: 'element-not-found'; dataId: string }\n | { reason: 'no-binding'; dataId: string }\n // The binding targets an attribute the editor owns (`data-id`,\n // `data-name`, `data-binding`), which a panel edit must not rewrite.\n | { reason: 'reserved-property'; dataId: string; property: string }\n // Asked to remove (`undefined`) a property whose binding is `required`.\n | { reason: 'required-property'; dataId: string; property: string }\n | {\n reason: 'binding-not-declared';\n dataId: string;\n label: string;\n property?: string;\n }\n | {\n reason: 'duplicate-binding';\n dataId: string;\n label: string;\n property?: string;\n count: number;\n }\n | { reason: 'attribute-not-found'; dataId: string; property: string }\n // `innerText` or `innerHTML` written to a self-closing element, which has\n // nowhere between its tags to put them (#552).\n | { reason: 'self-closing'; dataId: string; property: string }\n | { reason: 'unsupported-syntax'; dataId: string; property: string }\n | { reason: 'parse-error'; error: unknown };\n\nexport interface UpdateResult {\n code: string;\n success: boolean;\n // Set when `success` is false.\n failure?: UpdateFailure;\n}\n\n// What one `update` call asks for.\ninterface UpdateRequest {\n dataId: string;\n label: string;\n value: unknown;\n property?: string;\n options: BindingOptions;\n}\n\n// One element's outcome: the spans to write (possibly none, which still\n// counts as handled), or why it was refused.\ntype ElementEdit = { edits: SourceEdit[] } | { failure: UpdateFailure };\n\nconst hasDataId = (opening: t.JSXOpeningElement, dataId: string) =>\n opening.attributes.some(\n attr =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === DATA_ATTR.ID &&\n attr.value &&\n t.isStringLiteral(attr.value) &&\n attr.value.value === dataId,\n );\n\nconst findJSXAttribute = (opening: t.JSXOpeningElement, name: string) =>\n opening.attributes.find(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === name,\n );\n\n// Step 1: the element's binding for the request, from the same sources\n// `extract` reads (#509, #513). Found by `property` when given, otherwise by\n// `label`. More than one match is an authoring mistake, reported rather than\n// resolved by picking one (#240).\nconst findBinding = (\n opening: t.JSXOpeningElement,\n { dataId, label, property, options }: UpdateRequest,\n): { binding: BindingItem } | { failure: UpdateFailure } => {\n const bindingAttr = findJSXAttribute(opening, DATA_ATTR.BINDING);\n\n // An attribute with no value declares nothing to check against.\n if (bindingAttr && !bindingAttr.value) {\n return { failure: { reason: 'no-binding', dataId } };\n }\n\n let own: BindingItem[] | undefined;\n\n if (bindingAttr?.value) {\n let bindingValue = '';\n\n if (t.isStringLiteral(bindingAttr.value)) {\n bindingValue = bindingAttr.value.value;\n } else if (t.isJSXExpressionContainer(bindingAttr.value)) {\n try {\n bindingValue = generateCode(bindingAttr.value.expression);\n } catch (error) {\n return { failure: { reason: 'parse-error', error } };\n }\n }\n\n own = parseBinding(bindingValue);\n }\n\n const keyAttr = findJSXAttribute(opening, DATA_ATTR.BINDING_KEY);\n const bindings = resolveBindings(\n own,\n keyAttr &&\n (keyAttr.value && t.isStringLiteral(keyAttr.value)\n ? keyAttr.value.value\n : null),\n getJSXTagName(opening),\n options,\n );\n\n if (!own && bindings.length === 0) {\n return { failure: { reason: 'no-binding', dataId } };\n }\n\n const matches = bindings.filter(binding =>\n property !== undefined\n ? binding.property === property\n : binding.label === label,\n );\n\n if (matches.length === 0) {\n return {\n failure: { reason: 'binding-not-declared', dataId, label, property },\n };\n }\n\n if (matches.length > 1) {\n return {\n failure: {\n reason: 'duplicate-binding',\n dataId,\n label,\n property,\n count: matches.length,\n },\n };\n }\n\n return { binding: matches[0]! };\n};\n\n// Step 2: what no edit may do, whatever the property: rewrite an attribute\n// the editor owns, or remove a `required` one (#426).\nconst checkEdit = (\n binding: BindingItem,\n { dataId, value }: UpdateRequest,\n): UpdateFailure | undefined => {\n const property = binding.property;\n\n if (RESERVED_BINDING_PROPERTIES.includes(property)) {\n return { reason: 'reserved-property', dataId, property };\n }\n\n if (value === undefined && binding.required) {\n return { reason: 'required-property', dataId, property };\n }\n\n return undefined;\n};\n\n// An editor's result as an `ElementEdit`: `null` becomes `onNull`'s failure.\nconst toElementEdit = (\n result: EditResult,\n onNull: () => UpdateFailure,\n): ElementEdit => (result ? { edits: result } : { failure: onNull() });\n\n// Step 3: the spans that set `binding`'s property on `element`. `undefined`\n// asks for the property to go: an attribute is removed, content is emptied.\nconst editProperty = (\n source: string,\n element: t.JSXElement,\n binding: BindingItem,\n { dataId, value, options }: UpdateRequest,\n): ElementEdit => {\n const opening = element.openingElement;\n const prop = binding.property;\n const unset = value === undefined;\n const couldNotUpdate = (): UpdateFailure => ({\n reason: 'parse-error',\n error: new Error(`could not update \"${prop}\"`),\n });\n\n // Text and HTML go between the tags, so a self-closing element can't take\n // them. Clearing them is fine: there's nothing to clear (#552).\n const contentWithoutSlot =\n !unset && String(value) !== '' && !childrenRange(element);\n\n switch (prop) {\n case BINDING_PROP.INNER_TEXT: {\n if (contentWithoutSlot) {\n return { failure: { reason: 'self-closing', dataId, property: prop } };\n }\n\n return toElementEdit(\n editInnerText(source, element, unset ? '' : String(value)),\n couldNotUpdate,\n );\n }\n\n case BINDING_PROP.INNER_HTML: {\n // `richtext` is written to an attribute, so it doesn't need one.\n if (contentWithoutSlot && binding.type !== 'richtext') {\n return { failure: { reason: 'self-closing', dataId, property: prop } };\n }\n\n return toElementEdit(\n binding.type === 'richtext'\n ? editRichtext(element, unset ? '' : String(value))\n : editInnerHTML(element, unset ? '' : String(value)),\n couldNotUpdate,\n );\n }\n\n case BINDING_PROP.CHILDREN: {\n // Children are edited one at a time (move, add, remove), so they can't\n // be removed as a whole.\n if (unset) {\n return {\n failure: { reason: 'unsupported-syntax', dataId, property: prop },\n };\n }\n\n return toElementEdit(\n editChildrenSource(source, element, value, options),\n () => ({\n reason: 'parse-error',\n error: new Error(\n 'Unsupported or stale children edit; source was preserved',\n ),\n }),\n );\n }\n\n default: {\n const attribute = findAttribute(opening, prop);\n\n if (unset) {\n // Already absent: nothing to remove, and nothing went wrong.\n return toElementEdit(\n attribute ? removeAttribute(source, attribute) : [],\n () => ({\n reason: 'parse-error',\n error: new Error(`could not remove \"${prop}\"`),\n }),\n );\n }\n\n // A declared property the element doesn't have yet is added when it's\n // given a real value, so a field that was switched off can be switched\n // on again. An empty string leaves it absent (#426).\n if (!attribute) {\n return toElementEdit(\n value === ''\n ? []\n : addAttribute(source, opening, prop, value, binding.type),\n () => ({ reason: 'attribute-not-found', dataId, property: prop }),\n );\n }\n\n if (\n binding.type !== 'jsx' &&\n !canEditAttributeValue(attribute, value, binding.type)\n ) {\n return {\n failure: { reason: 'unsupported-syntax', dataId, property: prop },\n };\n }\n\n return toElementEdit(\n binding.type === 'jsx'\n ? editJsxAttribute(opening, prop, value)\n : editAttribute(opening, prop, value, binding.type),\n () => ({ reason: 'attribute-not-found', dataId, property: prop }),\n );\n }\n }\n};\n\n// The three steps for one element.\nconst editElement = (\n source: string,\n element: t.JSXElement,\n request: UpdateRequest,\n): ElementEdit => {\n const found = findBinding(element.openingElement, request);\n\n if ('failure' in found) {\n return found;\n }\n\n const refused = checkEdit(found.binding, request);\n\n if (refused) {\n return { failure: refused };\n }\n\n return editProperty(source, element, found.binding, request);\n};\n\n// Sets one bound property of the element with `dataId` to `value`, and\n// returns the new source or why it couldn't.\n//\n// The binding is found by `property` when given, otherwise by `label`.\n// Pass `property` when you have it: a label is display text and can repeat\n// (#240). `options` are the binding sources the bindings were read with\n// (#509, #513).\nexport const update = (\n code: string,\n dataId: string,\n label: string,\n value: unknown,\n property?: string,\n options: BindingOptions = {},\n): UpdateResult => {\n const request: UpdateRequest = { dataId, label, value, property, options };\n\n try {\n const wrapped = wrap(code);\n const ast = parse(wrapped, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n let changed = false;\n let failure: UpdateFailure | undefined;\n const edits: SourceEdit[] = [];\n\n // Every element carrying `dataId` is edited, so a duplicated id edits\n // each copy; the last refusal is the one reported.\n traverse(ast, {\n JSXElement(path) {\n if (!hasDataId(path.node.openingElement, dataId)) {\n return;\n }\n\n const result = editElement(wrapped, path.node, request);\n\n if ('failure' in result) {\n failure = result.failure;\n\n return;\n }\n\n edits.push(...result.edits);\n changed = true;\n },\n });\n\n if (!changed) {\n return {\n code,\n success: false,\n // No specific reason recorded means the traversal never reached the\n // target element at all.\n failure: failure ?? { reason: 'element-not-found', dataId },\n };\n }\n\n // Patch the original source: everything outside the recorded spans is\n // copied unchanged (#239).\n return { code: unwrap(applyEdits(wrapped, edits)), success: true };\n } catch (error) {\n console.error('❌ Code update error:', error);\n return { code, success: false, failure: { reason: 'parse-error', error } };\n }\n};\n\nexport interface UpdateEntry {\n dataId: string;\n label: string;\n value: unknown;\n property?: string;\n}\n\n// The result of `updateAll`: every entry applied, or none. On failure `code`\n// is the source as it came in, `index` says which entry was refused, and\n// `failure` says why.\nexport type UpdateAllResult =\n | { success: true; code: string }\n | { success: false; code: string; failure: UpdateFailure; index: number };\n\n// Applies several edits as one: all of them, in array order, or none. The\n// first entry that fails stops the run and the source comes back untouched,\n// so a caller can commit the result as a single change (#425). An entry sees\n// the source the earlier ones left, and a later entry for the same\n// `dataId`/`property` wins.\n//\n// Each entry re-parses the source the one before it produced, so every offset\n// is fresh, and the outcome matches applying the entries one at a time (#239).\nexport const updateAll = (\n raw: string,\n entries: UpdateEntry[],\n options: BindingOptions = {},\n): UpdateAllResult => {\n let current = raw;\n\n for (const [index, entry] of entries.entries()) {\n const result = update(\n current,\n entry.dataId,\n entry.label,\n entry.value,\n entry.property,\n options,\n );\n\n if (!result.success) {\n return {\n success: false,\n code: raw,\n failure: result.failure ?? {\n reason: 'element-not-found',\n dataId: entry.dataId,\n },\n index,\n };\n }\n\n current = result.code;\n }\n\n return { success: true, code: current };\n};\n"],"mappings":";;;;;;AAgCA,MAAa,gBAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;ACxCA,MAAa,QAAQ,SAAiB;CACpC,OAAO,KAAK,KAAK;AACnB;AAEA,MAAa,UAAU,cAAsB;CAC3C,OAAO,UACJ,QAAQ,WAAW,EAAE,CAAC,CACtB,QAAQ,qBAAqB,EAAE,CAAC,CAChC,KAAK;AACV;AAEA,MAAa,aAAa,EACxB,OACA,sBACwC;CACxC,IAAI,UAAU,MACZ,OAAO;CAGT,IAAI,iBACF,OAAOA,cAAgB,KAAK;CAG9B,MAAM,UAAU,MAAM,KAAK;CAE3B,IAAI,MAAM,OAAO,KAAK,OAAO,GAC3B,OAAOC,uBAAyBC,eAAiB,WAAW,OAAO,CAAC,CAAC;CAGvE,IAAI,MAAM,gBAAgB,KAAK,OAAO,GAAG;EACvC,MAAM,OAAO,gBAAgB,SAAS,EACpC,SAAS,CAAC,OAAO,YAAY,EAC/B,CAAC;EACD,OAAOD,uBAAyB,IAAI;CACtC;CAEA,IAAI;EACF,MAAM,OAAO,gBAAgB,SAAS,EACpC,SAAS,CAAC,OAAO,YAAY,EAC/B,CAAC;EACD,OAAOA,uBAAyB,IAAI;CACtC,QAAQ;EACN,OAAOD,cAAgB,OAAO;CAChC;AACF;AAEA,MAAa,gBAAgB,SAAyB;CACpD,OAAO,SAAS,MAAM,EAAE,aAAa,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC;AAC5D;;;AC7CA,MAAM,UAAU,QAAwB;CACtC,MAAM,QAAQ,IACX,QAAQ,OAAO,EAAE,CAAC,CAClB,QAAQ,UAAU,EAAE,CAAC,CACrB,MAAM,IAAI;CAEb,MAAM,SAAS,MAAM,QAAQ,KAAK,SAAS;EACzC,IAAI,CAAC,KAAK,KAAK,GACb,OAAO;EAET,MAAM,QAAQ,KAAK,MAAM,QAAQ;EACjC,OAAO,KAAK,IAAI,KAAK,QAAQ,EAAE,EAAE,UAAU,CAAC;CAC9C,GAAG,QAAQ;CAEX,OAAO,WAAW,WACd,IAAI,KAAK,IACT,MAAM,KAAI,SAAQ,KAAK,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;AACrD;AAKA,MAAa,oBAAoB,SAAyB;CACxD,IAAI,UAAU;CAEd,OACEG,iBAAmB,OAAO,KAC1BC,wBAA0B,OAAO,KACjCC,sBAAwB,OAAO,KAC/BC,kBAAoB,OAAO,KAC3BC,0BAA4B,OAAO,GAEnC,UAAU,QAAQ;CAGpB,OAAO;AACT;AAMA,MAAa,yBAAyB,SAA0B;CAC9D,MAAM,QAAQ,iBAAiB,IAAI;CAEnC,IACEC,gBAAkB,KAAK,KACvBC,iBAAmB,KAAK,KACxBC,iBAAmB,KAAK,KACxBC,cAAgB,KAAK,GAErB,OAAO;CAGT,IACEC,kBAAoB,KAAK,KACzB,MAAM,aAAa,OACnBH,iBAAmB,MAAM,QAAQ,GAEjC,OAAO;CAGT,IAAII,kBAAoB,KAAK,GAC3B,OAAO,MAAM,YAAY,WAAW;CAGtC,IAAIC,kBAAoB,KAAK,GAC3B,OAAO,MAAM,SAAS,OACpB,YAAW,YAAY,QAAQ,sBAAsB,OAAO,CAC9D;CAGF,IAAIC,mBAAqB,KAAK,GAC5B,OAAO,MAAM,WAAW,OACtB,aACEC,iBAAmB,QAAQ,KAC3B,CAAC,SAAS,aACTC,aAAe,SAAS,GAAG,KAC1BT,gBAAkB,SAAS,GAAG,KAC9BC,iBAAmB,SAAS,GAAG,MACjC,sBAAsB,SAAS,KAAK,CACxC;CAGF,OAAO;AACT;AAEA,MAAa,+BAA+B,WAA4B;CACtE,IAAI;EACF,OAAO,sBACL,gBAAgB,QAAQ,EAAE,SAAS,CAAC,OAAO,YAAY,EAAE,CAAC,CAC5D;CACF,QAAQ;EACN,OAAO;CACT;AACF;AAKA,MAAa,mBAAmB,YAA6B;CAC3D,MAAM,OAAO,iBAAiB,OAAO;CAErC,IAAID,gBAAkB,IAAI,GACxB,OAAO,KAAK;CAGd,IAAIC,iBAAmB,IAAI,GACzB,OAAO,KAAK;CAGd,IAAIC,iBAAmB,IAAI,GACzB,OAAO,KAAK;CAGd,IAAIC,cAAgB,IAAI,GACtB,OAAO;CAGT,IAAIM,aAAe,IAAI,KAAK,KAAK,SAAS,aACxC;CAGF,IACEL,kBAAoB,IAAI,KACxB,KAAK,aAAa,OAClBH,iBAAmB,KAAK,QAAQ,GAEhC,OAAO,CAAC,KAAK,SAAS;CAGxB,IAAII,kBAAoB,IAAI,KAAK,KAAK,YAAY,WAAW,GAC3D,OAAO,KAAK,OAAO,EAAE,EAAE,MAAM,UAAU,KAAK,OAAO,EAAE,EAAE,MAAM,OAAO;CAGtE,IAAIK,aAAe,IAAI,KAAKC,cAAgB,IAAI,GAC9C,OAAO,aAAa,IAAI;CAG1B,IAAIL,kBAAoB,IAAI,GAC1B,OAAO,KAAK,SAAS,KAAI,YACvB,UAAU,gBAAgB,OAAO,IAAI,IACvC;CAGF,IAAIC,mBAAqB,IAAI,GAAG;EAC9B,MAAM,SAAkC,CAAC;EAEzC,KAAK,MAAM,QAAQ,KAAK,YAAY;GAClC,IAAI,CAACC,iBAAmB,IAAI,GAC1B;GAGF,IAAI,MAAqB;GAEzB,IAAIC,aAAe,KAAK,GAAG,GACzB,MAAM,KAAK,IAAI;QACV,IAAIT,gBAAkB,KAAK,GAAG,GACnC,MAAM,KAAK,IAAI;QACV,IAAIC,iBAAmB,KAAK,GAAG,GACpC,MAAM,OAAO,KAAK,IAAI,KAAK;GAG7B,IAAI,QAAQ,MACV;GAGF,OAAO,OAAO,gBAAgB,KAAK,KAAK;EAC1C;EAEA,OAAO;CACT;AAGF;AAEA,MAAa,cAAc,UAA4B;CACrD,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,MAAM,UAAU,MAAM,KAAK;CAE3B,IAAI,CAAC,SACH,OAAO;CAGT,IAAI,MAAM,OAAO,KAAK,OAAO,GAC3B,OAAO,WAAW,OAAO;CAG3B,IAAI,MAAM,gBAAgB,KAAK,OAAO,GAAG;EACvC,IAAI,YAAY,QACd,OAAO;EAET,IAAI,YAAY,SACd,OAAO;EAET,IAAI,YAAY,QACd,OAAO;EAET,IAAI,YAAY,aACd;CAEJ;CAEA,IACG,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,KAC/C,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAChD;EACA,IAAI;GACF,MAAM,MAAM,gBAAgB,SAAS,EACnC,SAAS,CAAC,OAAO,YAAY,EAC/B,CAAC;GAED,IAAIM,mBAAqB,GAAG,KAAKD,kBAAoB,GAAG,GACtD,OAAO,gBAAgB,GAAG;EAE9B,QAAQ,CAER;EAEA,OAAO;CACT;CAEA,OAAO;AACT;AAEA,MAAa,oBAAoB,SAAqC;CACpE,IAAIJ,iBAAmB,IAAI,GACzB,OAAO;EAAE,MAAM;EAAW,OAAO,KAAK;CAAM;CAG9C,IAAID,iBAAmB,IAAI,GACzB,OAAO;EAAE,MAAM;EAAU,OAAO,KAAK;CAAM;CAG7C,IACEG,kBAAoB,IAAI,KACxB,KAAK,aAAa,OAClBH,iBAAmB,KAAK,QAAQ,GAEhC,OAAO;EAAE,MAAM;EAAU,OAAO,CAAC,KAAK,SAAS;CAAM;CAGvD,IAAID,gBAAkB,IAAI,GACxB,OAAO;EAAE,MAAM;EAAU,OAAO,KAAK;CAAM;CAG7C,IAAIK,kBAAoB,IAAI,GAAG;EAC7B,IAAI,KAAK,YAAY,WAAW,KAAK,KAAK,OAAO,WAAW,GAC1D,OAAO;GACL,MAAM;GACN,OAAO,OACL,KAAK,OAAO,EAAE,CAAE,MAAM,UAAU,KAAK,OAAO,EAAE,CAAE,MAAM,GACxD;EACF;EAEF,OAAO;GAAE,MAAM;GAAU,OAAO,aAAa,IAAI;EAAE;CACrD;CAEA,IAAIF,cAAgB,IAAI,GACtB,OAAO;EAAE,MAAM;EAAQ,OAAO;CAAK;CAGrC,IAAIG,kBAAoB,IAAI,GAC1B,OAAO;EAAE,MAAM;EAAS,OAAO,aAAa,IAAI;CAAE;CAGpD,IAAIC,mBAAqB,IAAI,GAC3B,OAAO;EAAE,MAAM;EAAU,OAAO,aAAa,IAAI;CAAE;CAGrD,IAAIG,aAAe,IAAI,KAAKC,cAAgB,IAAI,GAC9C,OAAO;EAAE,MAAM;EAAU,OAAO,aAAa,IAAI;CAAE;CAGrD,OAAO;EAAE,MAAM;EAAW,OAAO;CAAK;AACxC;AAEA,MAAa,wBAAwB,UAAkB;CACrD,IAAI;EACF,MAAM,MAAM,iBACV,gBAAgB,OAAO,EACrB,SAAS,CAAC,OAAO,YAAY,EAC/B,CAAC,CACH;EAEA,IAAI,CAACL,kBAAoB,GAAG,GAC1B,OAAO;EAGT,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,MAAM,0BAA0B,KAAK;EAC7C,OAAO;CACT;AACF;AAEA,MAAa,2BACX,YAC6D;CAC7D,MAAM,aACJ,CAAC;CAEH,QAAQ,WAAW,SAAQ,SAAQ;EACjC,IAAIE,iBAAmB,IAAI,KAAKC,aAAe,KAAK,GAAG,GAAG;GACxD,MAAM,MAAM,KAAK,IAAI;GAIrB,IACE,QAAQ,cACRC,aAAe,KAAK,KAAK,KACzBC,cAAgB,KAAK,KAAK,GAE1B;GAGF,MAAM,YAAY,iBAAiB,KAAK,KAAK;GAE7C,WAAW,OAAO;IAChB,GAAG;IACH,SAAS,KAAK;GAChB;EACF;CACF,CAAC;CAED,OAAO;AACT;;;AC/TA,MAAM,oBAAoB,EAAE,KAAK,aAAa;AAE9C,MAAM,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY;AACjD,MAAM,aAAa,EAAE,OAAO,CAAC,CAAC,MAAM,oCAAoC;AAExE,MAAM,sBAAsB,EAAE,OAAO;CACnC,OAAO,EAAE,OAAO;CAChB,OAAO,EAAE,OAAO;AAClB,CAAC;AAKD,MAAM,sBAAsB,EACzB,OAAO;CACN,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;CACtB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;CAC1B,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS;AAC5B,CAAC,CAAC,CACD,YAAY;AAIf,MAAM,QAAW,QAAsB,UAAkC;CACvE,MAAM,SAAS,OAAO,UAAU,KAAK;CAErC,OAAO,OAAO,UAAU,OAAO,OAAO,KAAA;AACxC;AAIA,MAAM,kBAAkB,UAA8C;CACpE,IAAI,OAAO,UAAU,UACnB,OAAO,QAAQ,EAAE,MAAM,MAAM,IAAI,KAAA;CAGnC,OAAO,KAAK,qBAAqB,KAAK;AACxC;AAGA,MAAM,mBAAmB,UAAgD;CACvE,IAAI,CAAC,MAAM,QAAQ,KAAK,GACtB;CAGF,MAAM,UAAU,MAAM,SAAQ,WAAU;EACtC,MAAM,SAAS,KAAK,qBAAqB,MAAM;EAE/C,OAAO,SAAS,CAAC,MAAM,IAAI,CAAC;CAC9B,CAAC;CAED,OAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;AACxC;AAIA,MAAM,qCAAqB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,iBAAiB,UAAqD;CAC1E,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAKA,MAAM,iBAAiB,QAAoD;CACzE,MAAM,cAAc,OAAO,QAAQ,GAAG,CAAC,CAAC,QACrC,CAAC,SAAS,CAAC,mBAAmB,IAAI,GAAG,CACxC;CACA,MAAM,QAA2B;EAC/B,OAAO,KAAK,EAAE,OAAO,GAAG,IAAI,KAAK;EACjC,UAAU,KAAK,EAAE,OAAO,GAAG,IAAI,QAAQ;EACvC,MAAM,KAAK,mBAAmB,IAAI,IAAI;EACtC,QAAQ,eAAe,IAAI,MAAM;EACjC,SAAS,gBAAgB,IAAI,OAAO;EACpC,QAAQ,kBAAkB,IAAI,MAAM;EACpC,KAAK,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG;EAC7B,KAAK,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG;EAC7B,SAAS,KAAK,EAAE,OAAO,GAAG,IAAI,OAAO;EACrC,gBAAgB,KAAK,EAAE,OAAO,GAAG,IAAI,cAAc;EACnD,UAAU,KAAK,EAAE,QAAQ,GAAG,IAAI,QAAQ;EACxC,WAAW,KAAK,aAAa,IAAI,SAAS;EAC1C,WAAW,KAAK,aAAa,IAAI,SAAS;EAC1C,MAAM,KAAK,EAAE,OAAO,CAAC,CAAC,SAAS,GAAG,IAAI,IAAI;EAC1C,UAAU,KAAK,aAAa,IAAI,QAAQ;EACxC,UAAU,KAAK,aAAa,IAAI,QAAQ;EACxC,SAAS,KAAK,YAAY,IAAI,OAAO;EACrC,SAAS,KAAK,YAAY,IAAI,OAAO;EACrC,WAAW,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,SAAS;EACzD,MAAM,YAAY,SAAS,IAAI,OAAO,YAAY,WAAW,IAAI,KAAA;CACnE;CAEA,OAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,CACjE;AACF;AAIA,SAAS,kBAAkB,OAA8C;CACvE,IAAI,CAAC,cAAc,KAAK,GACtB;CAGF,MAAM,MAAwB,CAAC;CAE/B,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,KAAK,GAAG;EAC9C,IAAI,CAAC,cAAc,GAAG,GACpB;EAGF,IAAI,UAAU,KAAK;GAIjB,IAAI,OAAO;IAAE,MAAM,KAAA;IAAW,GAAG,cAAc,GAAG;GAAE;GACpD;EACF;EAEA,MAAM,SAAS,kBAAkB,GAAG;EAEpC,IAAI,QACF,IAAI,OAAO;CAEf;CAEA,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,SAAS,IAAI,MAAM,KAAA;AAC7C;AAIA,MAAM,qBAAqB,QAAgC;CACzD,IAAI,CAAC,MAAM,QAAQ,GAAG,GACpB,OAAO,CAAC;CAGV,OAAO,IAAI,SAAQ,YAAW;EAC5B,IAAI,CAAC,cAAc,OAAO,GACxB,OAAO,CAAC;EAGV,MAAM,EAAE,OAAO,UAAU,GAAG,UAAU,cAAc,OAAO;EAE3D,IAAI,UAAU,KAAA,GACZ,OAAO,CAAC;EAGV,IAAI,aAAa,KAAA,KAAa,MAAM,SAAS,YAC3C,OAAO,CAAC;EAGV,OAAO,CAAC;GAAE;GAAO,UAAU,YAAY,aAAa;GAAY,GAAG;EAAM,CAAC;CAC5E,CAAC;AACH;AAIA,MAAM,kCAAkB,IAAI,QAG1B;AAMF,MAAa,sBAAsB,YACjC,YAAY,OAAO,QAAQ,SAAS,GAAG,KAAK,CAAC,SAAS,KAAK,OAAO;AAKpE,MAAa,uBACX,UACA,YAC8B;CAC9B,IAAI,CAAC,UACH;CAGF,IAAI,UAAU,gBAAgB,IAAI,QAAQ;CAE1C,IAAI,CAAC,SAAS;EACZ,0BAAU,IAAI,IAAI;EAClB,gBAAgB,IAAI,UAAU,OAAO;EAIrC,MAAM,UAAU,OAAO,KAAK,QAAQ,CAAC,CAAC,QACpC,QAAO,CAAC,mBAAmB,GAAG,CAChC;EAEA,IAAI,QAAQ,SAAS,GACnB,QAAQ,KACN,8DAA8D,QAAQ,KAAK,IAAI,EAAE,kDACnF;CAEJ;CAEA,IAAI,CAAC,mBAAmB,OAAO,KAAK,CAAC,OAAO,OAAO,UAAU,OAAO,GAClE;CAGF,IAAI,WAAW,QAAQ,IAAI,OAAO;CAElC,IAAI,CAAC,UAAU;EACb,WAAW,kBACR,SAAuD,QAC1D;EACA,QAAQ,IAAI,SAAS,QAAQ;CAC/B;CAEA,OAAO;AACT;AAIA,MAAM,6BAAa,IAAI,QAAmD;AAG1E,MAAM,6BAAa,IAAI,IAAY;AAEnC,MAAM,YAAY,IAAY,YAAoB;CAChD,IAAI,CAAC,WAAW,IAAI,EAAE,GAAG;EACvB,WAAW,IAAI,EAAE;EACjB,QAAQ,KAAK,OAAO;CACtB;AACF;AAIA,MAAa,kBACX,aACA,QAC8B;CAC9B,IAAI,CAAC,eAAe,CAAC,OAAO,OAAO,aAAa,GAAG,GACjD;CAGF,IAAI,UAAU,WAAW,IAAI,WAAW;CAExC,IAAI,CAAC,SAAS;EACZ,0BAAU,IAAI,IAAI;EAClB,WAAW,IAAI,aAAa,OAAO;CACrC;CAEA,IAAI,WAAW,QAAQ,IAAI,GAAG;CAE9B,IAAI,CAAC,UAAU;EACb,WAAW,kBAAkB,YAAY,IAAI;EAC7C,QAAQ,IAAI,KAAK,QAAQ;CAC3B;CAEA,OAAO;AACT;AAWA,MAAa,mBACX,KACA,KACA,SACA,UAA0B,CAAC,MACT;CAClB,IAAI,KAAK;EACP,IAAI,QAAQ,KAAA,GACV,SACE,QAAQ,OACR,oEAAoE,OAAO,GAAG,iDAChF;EAGF,OAAO;CACT;CAEA,IAAI,QAAQ,MAAM;EAChB,SACE,gBACA,wHACF;EAEA,OAAO,CAAC;CACV;CAEA,IAAI,QAAQ,KAAA,GAAW;EACrB,MAAM,WAAW,eAAe,QAAQ,aAAa,GAAG;EAExD,IAAI,CAAC,UACH,SACE,WAAW,OACX,+BAA+B,IAAI,mDACrC;EAGF,OAAO,YAAY,CAAC;CACtB;CAEA,OAAO,oBAAoB,QAAQ,UAAU,OAAO,KAAK,CAAC;AAC5D;AAEA,MAAa,gBAAgB,iBAA+C;CAC1E,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,MAAM,MAAM,qBAAqB,YAAY;CAE7C,IAAI,CAAC,KACH,OAAO,CAAC;CAGV,OAAO,kBAAkB,gBAAgB,GAAG,CAAC;AAC/C;AAIA,MAAa,0BACX,eACkB,kBAAkB,gBAAgB,UAAU,CAAC;AAEjE,MAAa,mBACX,MACA,aACW;CACX,QAAQ,UAAR;EACE,KAAK,aAAa,YAChB,OAAO,KAAK,eAAe;EAG7B,KAAK,aAAa,YAAY;GAE5B,MAAM,UAAU,KAAK,WAAW,MAC9B,MAAK,EAAE,SAAS,yBAClB;GACA,IAAI,SAAS,OACX,IAAI;IACF,MAAM,OAAO,gBAAgB,QAAQ,OAAO,EAC1C,SAAS,CAAC,OAAO,YAAY,EAC/B,CAAC;IACD,IAAIC,mBAAqB,IAAI,GAAG;KAC9B,MAAM,WAAW,KAAK,WAAW,MAC/B,MACEC,iBAAmB,CAAC,KACpBC,aAAe,EAAE,GAAG,KACpB,EAAE,IAAI,SAAS,QACnB;KACA,IAAI,UAAU;MACZ,IAAIC,gBAAkB,SAAS,KAAK,GAClC,OAAO,SAAS,MAAM;MAExB,IACEC,kBAAoB,SAAS,KAAK,KAClC,SAAS,MAAM,YAAY,WAAW,GAEtC,OACE,SAAS,MAAM,OAAO,EAAE,EAAE,MAAM,UAChC,SAAS,MAAM,OAAO,EAAE,EAAE,MAAM,OAChC;KAGN;IACF;GACF,QAAQ,CAER;GAEF,OAAO,KAAK,eAAe,KAAK,eAAe;EACjD;EAEA,KAAK,aAAa,UAChB,OAAO,KAAK,UAAU,MAAM,YAAY,CAAC,CAAC;EAG5C,SAIE,OAHmB,KAAK,WAAW,MAAK,SAAQ,KAAK,SAAS,QACvC,CAAC,EAAE,SAAS;CAIvC;AACF;AAKA,MAAa,sCAAgD,IAAI,IAAI;CACnE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAOD,MAAa,sBACX,MACA,UACA,SACY;CACZ,QAAQ,UAAR;EACE,KAAK,aAAa;EAClB,KAAK,aAAa,YAChB,OAAO,gBAAgB,MAAM,QAAQ;EAGvC,KAAK,aAAa,UAChB,OAAO,KAAK,YAAY,CAAC;EAG3B,SAAS;GACP,MAAM,MAAM,gBAAgB,MAAM,QAAQ;GAG1C,IAFa,KAAK,WAAW,MAAK,MAAK,EAAE,SAAS,QAE3C,CAAC,EAAE,mBAAoB,QAAQ,oBAAoB,IAAI,IAAI,GAChE,OAAO;GAGT,OAAO,WAAW,GAAG;EACvB;CACF;AACF;AAKA,MAAa,oBAAoB,SAAsC;CACrE,IAAI,KAAK,UACP,OAAO,KAAK;CAGd,MAAM,cAAc,KAAK,eAAe,MACtC,SAAQ,KAAK,SAAS,UAAU,OAClC;CAEA,OAAO,aAAa,QAAQ,aAAa,YAAY,KAAK,IAAI,CAAC;AACjE;AAEA,MAAM,uBAAuB,SAC3B,iBAAiB,IAAI,CAAC,CAAC,SAAS;AAElC,MAAa,wBAAwB,SAAuC;CAC1E,MAAM,mBAAmC,CAAC;CAE1C,MAAM,YAAY,aAAyC;EACzD,IAAI,CAAC,UACH;EAGF,KAAK,MAAM,SAAS,UAAU;GAC5B,IAAI,oBAAoB,KAAK,GAC3B,iBAAiB,KAAK,KAAK;GAE7B,SAAS,MAAM,QAAQ;EACzB;CACF;CAEA,SAAS,KAAK,QAAQ;CAEtB,OAAO;AACT;;;ACngBA,MAAa,iBAAoB,OAAY,YAA8B;CACzE,OAAO,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC;AACvD;;;;;;;AAQA,MAAa,uBACX,OACA,SACA,cACyC;CACzC,MAAM,OAAO,CAAC,GAAG,KAAK;CACtB,MAAM,cAAc,IAAI,IAAI,OAAO;CAEnC,MAAM,UAAU,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,MACpC,cAAc,OAAO,IAAI,IAAI,IAAI,CACnC;CAEA,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,SAAS,cAAc,OAAO,QAAQ,IAAI,QAAQ;EAExD,IAAI,SAAS,KAAK,UAAU,KAAK,UAAU,YAAY,IAAI,MAAM,GAC/D;EAGF,CAAC,KAAK,QAAQ,KAAK,WAAW,CAAC,KAAK,SAAU,KAAK,MAAO;EAC1D,YAAY,OAAO,KAAK;EACxB,YAAY,IAAI,MAAM;CACxB;CAEA,OAAO;EAAE,OAAO;EAAM,SAAS;CAAY;AAC7C;;;ACZA,MAAM,eACJ,aAOG;CACH,OAAO,SACJ,QAAO,MAAKC,UAAY,CAAC,CAAC,CAAC,CAC3B,KAAI,MAAM,EAAgB,MAAM,KAAK,CAAC,CAAC,CACvC,QAAO,MAAK,EAAE,MAAM,CAAC,CACrB,KAAK,GAAG;AACb;AAEA,MAAM,gBACJ,YAC4C;CAC5C,MAAM,QAAQ,QAAQ,MAAM,GAAG;CAE/B,IAAI,MAAM,WAAW,GACnB,OAAOC,cAAgB,MAAM,EAAG;CAGlC,IAAI,OAAgDA,cAClD,MAAM,EACR;CAEA,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAChC,OAAOC,oBAAsB,MAAMD,cAAgB,MAAM,EAAG,CAAC;CAG/D,OAAO;AACT;AAEA,MAAM,eAAe,mBACnB,OAAO,WACT;AAKA,MAAM,SAAS,CAAC;AAChB,IAAI,sCAAsB,IAAI,QAG5B;AAEF,MAAM,YAAY,EAAE,UAAU,kBAAkC;CAC9D,IAAI,CAAC,YAAY,CAAC,aAChB,OAAO;CAGT,IAAI,SAAS,oBAAoB,IAAI,YAAY,MAAM;CAEvD,IAAI,CAAC,QAAQ;EACX,yBAAS,IAAI,QAAQ;EACrB,oBAAoB,IAAI,YAAY,QAAQ,MAAM;CACpD;CAEA,IAAI,QAAQ,OAAO,IAAI,eAAe,MAAM;CAE5C,IAAI,CAAC,OAAO;EACV,QAAQ,mBAA2C,OAAO,WAAW;EACrE,OAAO,IAAI,eAAe,QAAQ,KAAK;CACzC;CAEA,OAAO;AACT;AAEA,MAAM,qBACJ,YACA,WACsD;CACtD,MAAM,WAAwB,CAAC;CAC/B,MAAM,YAAyB,CAAC;CAEhC,KAAK,MAAM,QAAQ,YAAY;EAC7B,IAAI,CAACE,eAAiB,IAAI,KAAK,CAACC,gBAAkB,KAAK,IAAI,GACzD;EAGF,MAAM,OAAO,KAAK,KAAK;EACvB,IAAI,QAAuB;EAC3B,IAAIC,oBAAkB;EAEtB,IAAI,KAAK,OAAO;GACd,IAAIC,gBAAkB,KAAK,KAAK,GAAG;IACjC,QAAQ,KAAK,MAAM;IACnB,oBAAkB;GACpB,OAAO,IAAIC,yBAA2B,KAAK,KAAK,GAC9C,IAAI;IACF,MAAM,aAAa,KAAK,MAAM;IAC9B,MAAM,aACJC,kBAAoB,iBAAiB,UAAU,CAAC,KAChDC,mBAAqB,iBAAiB,UAAU,CAAC;IACnD,QACE,UACA,cACA,WAAW,SAAS,QACpB,WAAW,OAAO,OACd,OAAO,MAAM,WAAW,OAAO,WAAW,GAAG,IAC7C,aAAa,UAAU;IAC7B,oBAAkB;GACpB,QAAQ;IACN,QAAQ;GACV;EAEJ;EAEA,MAAM,QAAQ;GAAE;GAAM;GAAO,iBAAA;EAAgB;EAE7C,SAAS,KAAK,KAAK;EAEnB,IAAI,KAAK,WAAW,OAAO,GACzB,UAAU,KAAK,KAAK;CAExB;CAEA,OAAO;EAAE;EAAU;CAAU;AAC/B;AAEA,MAAM,sBACJ,SACiD;CACjD,MAAM,gBAA8D,CAAC;CAErE,IAAI,KAAK,aACP,cAAc,KAAKC,QAAU,KAAK,WAAW,CAAC;CAGhD,KAAK,UAAU,SAAQ,UAAS;EAC9B,MAAM,WAAW,UAAU,KAAK;EAChC,IAAI,UACF,cAAc,KAAK,QAAQ;CAE/B,CAAC;CAED,OAAO;AACT;AAEA,MAAa,aACX,SACwC;CACxC,IAAI;EACF,IAAI,KAAK,YAAY;GACnB,MAAM,gBAAgB,mBAAmB,IAAI;GAE7C,OAAOC,YACLC,mBAAqB,GACrBC,mBAAqB,GACrB,aACF;EACF;EAEA,IACE,KAAK,YAAY,SACjB,KAAK,eAAe,MAAK,SAAQ,KAAK,SAAS,WAAW,GAC1D;GACA,IAAI,KAAK,UACP,OAAO,UAAU,KAAK,SAAS,EAAG;GAEpC,OAAO;EACT;EAEA,MAAM,aAAa,KAAK,WAAW,KAAI,SAAQ;GAC7C,MAAM,WAAWZ,cAAgB,KAAK,IAAI;GAE1C,IAAI,CAAC,KAAK,OACR,OAAOa,aAAe,UAAU,IAAI;GAGtC,OAAOA,aAAe,UAAU,UAAU,IAAI,CAAC;EACjD,CAAC;EAED,MAAM,cAAc,aAAa,KAAK,OAAO;EAE7C,MAAM,iBAAiBC,kBAAoB,aAAa,UAAU;EAElE,MAAM,iBAAiBC,kBAAoB,WAAW;EACtD,MAAM,WAAW,mBAAmB,IAAI;EAExC,OAAOC,WAAa,gBAAgB,gBAAgB,QAAQ;CAC9D,SAAS,OAAO;EACd,QAAQ,MAAM,2CAA2C,KAAK;EAC9D,OAAO;CACT;AACF;AAEA,MAAM,qBACJ,aACA,cACkB;CAClB,SAAS;CACT,IAAI,OAAO,CAAC;CACZ,YAAY,CAAC;EAAE,MAAM,UAAU;EAAM,OAAO;CAAO,CAAC;CACpD,gBAAgB,CAAC;EAAE,MAAM,UAAU;EAAM,OAAO;CAAO,CAAC;CACxD;CACA;AACF;AAEA,MAAM,sBACJ,aACA,cACkB;CAClB,SAAS;CACT,IAAI,OAAO,CAAC;CACZ,YAAY,CAAC;CACb,gBAAgB,CAAC;CACjB;CACA;CACA,YAAY;AACd;AAEA,MAAM,0BACJ,YACA,gBACA,aAAsB,MACtB,QACA,YAC+B;CAC/B,MAAM,cAAc,WAAW,SAAS,QACtC,UAASC,aAAe,KAAK,KAAKC,cAAgB,KAAK,CACzD;CAEA,IAAI,CAAC,YAAY,QACf;CAGF,MAAM,gBAAgC,CAAC;CAEvC,YAAY,SAAQ,UAAS;EAC3B,IAAID,aAAe,KAAK,GAAG;GACzB,MAAM,eAAe,gBACnB,OACA,gBACA,QACA,OACF;GAEA,IAAI,YAAY;IACd,MAAM,cAAc,kBAClB,YAAY,MAAM,QAAQ,GAC1B,YACF;IACA,YAAY,SAAS,QAAQ,MAAM,MAAM,OAAQ,MAAM,GAAI;IAC3D,MAAM,SAAS,aAAa,EAAE,EAAE,eAAe,MAC7C,SAAQ,KAAK,SAAS,UAAU,EAClC,CAAC,EAAE;IAEH,IAAI,QACF,YAAY,KAAK,SAAS;IAG5B,cAAc,KAAK,WAAW;GAChC,OACE,cAAc,KAAK,GAAG,YAAY;EAEtC,OAAO,IAAIC,cAAgB,KAAK,GAAG;GACjC,gBAAgB,IAAI,KAAK;GAEzB,MAAM,mBAAmC,CAAC;GAE1C,MAAM,SAAS,SAAQ,kBAAiB;IACtC,IAAID,aAAe,aAAa,GAAG;KACjC,MAAM,eAAe,gBACnB,eACA,gBACA,QACA,OACF;KACA,iBAAiB,KAAK,GAAG,YAAY;IACvC;GACF,CAAC;GAED,IAAI,iBAAiB,QAAQ;IAC3B,MAAM,eAAe,mBACnB,YAAY,MAAM,QAAQ,GAC1B,gBACF;IACA,aAAa,SAAS,QAAQ,MAAM,MAAM,OAAQ,MAAM,GAAI;IAC5D,cAAc,KAAK,YAAY;GACjC;EACF;CACF,CAAC;CAED,OAAO,cAAc,SAAS,gBAAgB,KAAA;AAChD;AAEA,MAAM,qBACJ,YACA,gBACA,eAAuB,YACd;CAGT,MAAM,YAFU,WAAW,eAED,WAAW,MACnC,SACEf,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,IAAI,KAC3B,KAAK,KAAK,SAAS,YACvB;CAEA,IAAI,CAAC,aAAa,CAACD,eAAiB,SAAS,GAC3C;CAGF,IACE,UAAU,SACVI,yBAA2B,UAAU,KAAK,KAC1CC,kBAAoB,UAAU,MAAM,UAAU,GAI9C,UAF4B,MAAM,WAExB,SAAS,SAAQ,YAAW;EACpC,IAAIC,mBAAqB,OAAO,GAC9B,QAAQ,WAAW,SAAQ,SAAQ;GACjC,IACEW,iBAAmB,IAAI,KACvBC,aAAe,KAAK,GAAG,KACvBH,aAAe,KAAK,KAAK,GAEzB,iBAAiB,KAAK,OAAO,cAAc;EAE/C,CAAC;CAEL,CAAC;AAEL;AAEA,MAAM,oBACJ,MACA,mBACS;CACT,IAAIA,aAAe,IAAI,KAAKC,cAAgB,IAAI,GAAG;EACjD,eAAe,IAAI,IAAoC;EACvD,KAAK,SAAS,SAAQ,UAAS,iBAAiB,OAAO,cAAc,CAAC;EACtE;CACF;CAKA,IAFEZ,yBAA2B,IAAI,KAAKe,0BAA4B,IAAI,GAGpE,iBAAiB,KAAK,YAAY,cAAc;AAEpD;AAeA,MAAM,wBACJ,YAC6B;CAC7B,KAAK,MAAM,QAAQ,QAAQ,YACzB,IACEnB,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,IAAI,KAC3B,KAAK,KAAK,SAAS,UAAU,WAC7B,KAAK,SACLG,yBAA2B,KAAK,KAAK,GACrC;EAEA,MAAM,aAAa,iBAAiB,KAAK,MAAM,UAAU;EAEzD,IAAIC,kBAAoB,UAAU,GAChC,OAAO;CAEX;CAGF,OAAO;AACT;AAIA,MAAM,uBACJ,MACA,QACA,YACoB;CACpB,MAAM,UAAU,KAAK;CACrB,MAAM,UAAU,cAAc,OAAO;CACrC,MAAM,EAAE,UAAU,cAAc,kBAAkB,QAAQ,YAAY,MAAM;CAE5E,MAAM,cAAc,UAAU,MAAK,SAAQ,KAAK,SAAS,UAAU,OAAO;CAC1E,MAAM,cAAc,qBAAqB,OAAO;CAChD,MAAM,UAAU,UAAU,MAAK,SAAQ,KAAK,SAAS,UAAU,WAAW;CAI1E,MAAM,WAAW,gBACf,cACI,uBAAuB,WAAW,IAClC,cACE,aAAa,YAAY,KAAK,IAC9B,KAAA,GACN,YAAY,QAAQ,kBAAkB,QAAQ,QAAQ,OACtD,SACA,OACF;CAEA,MAAM,kBAAkB,SAAS,MAC/B,MAAK,EAAE,aAAa,aAAa,QACnC;CACA,MAAM,gBAAgB,SAAS,QAC7B,MAAK,EAAE,aAAa,aAAa,SAAS,EAAE,SAAS,OACvD;CAEA,MAAM,mBAAmB,SAAS,MAChC,MAAK,EAAE,aAAa,aAAa,UACnC;CAEA,IAAI;CACJ,IAAI,oBAAoB,KAAK,SAAS,SAAS,GAC7C,cAAc,KAAK,SAChB,KAAI,UAAS,aAAa,KAAK,CAAC,CAAC,CACjC,KAAK,EAAE,CAAC,CACR,KAAK;CAGV,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAEA,MAAM,gBACJ,KACA,YACmB;CACnB,MAAM,UAAU,KAAK,GAAG;CACxB,MAAM,MAAM,MAAM,SAAS;EACzB,YAAY;EACZ,SAAS,CAAC,OAAO,YAAY;EAC7B,eAAe;CACjB,CAAC;CAED,MAAM,UAA0B,CAAC;CAKjC,MAAM,iCAAiB,IAAI,QAAsC;CAEjE,SAAS,KAAK,EACZ,WAAW,MAAM;EACf,IAAI,eAAe,IAAI,KAAK,IAAI,GAC9B;EAGF,MAAM,EACJ,SACA,UACA,WACA,UACA,iBACA,eACA,gBACE,oBAAoB,KAAK,MAAM,SAAS,OAAO;EAEnD,IAAI,CAAC,WAAW,CAAC,UAAU,QACzB;EAGF,IAAI;EAEJ,IAAI,iBACF,gBAAgB,uBACd,KAAK,MACL,gBACA,MACA,SACA,OACF;EAGF,KAAK,MAAM,gBAAgB,eACzB,kBAAkB,KAAK,MAAM,gBAAgB,aAAa,QAAQ;EAGpE,QAAQ,KAAK;GACX;GACA,YAAY;GACZ,gBAAgB;GAChB,aAAa,YAAY,KAAK,KAAK,QAAQ;GAC3C;GACA,UAAU;GACV;GACA,KAAK,KAAK,KAAK,MACX;IACE,OAAO;KACL,MAAM,KAAK,KAAK,IAAI,MAAM;KAC1B,QAAQ,KAAK,KAAK,IAAI,MAAM;IAC9B;IACA,KAAK;KACH,MAAM,KAAK,KAAK,IAAI,IAAI;KACxB,QAAQ,KAAK,KAAK,IAAI,IAAI;IAC5B;GACF,IACA,KAAA;EACN,CAAC;CACH,EACF,CAAC;CAED,OAAO;AACT;AAKA,SAAgB,QACd,KACA,UAA0B,CAAC,GACX;CAChB,MAAM,QAAQ,SAAS,OAAO;CAE9B,IAAI,MAAM,IAAI,GAAG,GACf,OAAO,MAAM,IAAI,GAAG;CAGtB,MAAM,UAAU,aAAa,KAAK,OAAO;CAEzC,MAAM,IAAI,KAAK,OAAO;CAEtB,OAAO;AACT;AAEA,SAAS,gBACP,MACA,gBACA,QACA,SACgB;CAChB,gBAAgB,IAAI,IAAI;CAExB,MAAM,EACJ,SACA,UACA,WACA,UACA,iBACA,gBACE,oBAAoB,MAAM,QAAQ,OAAO;CAE7C,IAAI;CAEJ,IAAI,iBACF,gBAAgB,uBACd,MACA,gBACA,MACA,QACA,OACF;CAGF,IAAI,CAAC,eACH,gBAAgB,uBACd,MACA,gBACA,OACA,QACA,OACF;CAGF,OAAO,CACL;EACE;EACA,YAAY;EACZ,gBAAgB;EAChB,aAAa,YAAY,KAAK,QAAQ;EACtC;EACA,UAAU;EACV;CACF,CACF;AACF;AAEA,SAAgB,oBAAoB;CAClC,aAAa,MAAM;CACnB,sCAAsB,IAAI,QAAQ;AACpC;AAEA,oBAAoB,iBAAiB;;;ACxlBrC,MAAM,qBAAqB,UACzB,MAAM,KAAI,SAAQ;CAChB,MAAM,MAAM,UAAU,IAAI;CAE1B,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,oBAAoB;CAGtC,OAAO,aAAa,GAAG;AACzB,CAAC;AAEH,MAAa,yBAAyB,UAAoC;CACxE,MAAM,UAAU,kBAAkB,KAAK;CAEvC,OAAO,MAAM,KAAK,MAAM,UACtB,KAAK,UAAU,CAAC,KAAK,UAAU,MAAM,QAAQ,MAAM,CAAC,CACtD;AACF;AAEA,MAAM,mBACJ,SACA,UAEA,MAAM,QAAQ,OAAO,KACrB,IAAI,IAAI,OAAO,CAAC,CAAC,SAAS,QAAQ,UAClC,QAAQ,OACN,UAAS,OAAO,UAAU,KAAK,KAAK,SAAS,KAAK,QAAQ,KAC5D;AAIF,MAAM,cAAc,QAAgB,YAAiC;CACnE,MAAM,OAAO,gBAAgB,QAAQ,EAAE,SAAS,CAAC,OAAO,YAAY,EAAE,CAAC;CACvE,MAAM,QAAsB,CAAC;CAC7B,MAAM,cAAc;EAClB,IAAI,KAAK,OAAO,EAAE;EAElB,OAAO,QAAQ,IAAI,EAAE,GACnB,KAAK,OAAO,EAAE;EAGhB,QAAQ,IAAI,EAAE;EAEd,OAAO;CACT;CAEA,aAAe,OAAM,UAAS;EAC5B,IAAI,CAACe,oBAAsB,KAAK,GAC9B;EAGF,MAAM,MAAM,MAAM,WAAW,QAC1B,SACCC,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC,CACpD;EAEA,IAAI,IAAI,SAAS,GACf,MAAM,IAAI,MAAM,8BAA8B;EAGhD,MAAM,OAAO,IAAI;EAEjB,IACE,QACA,MAAM,WACH,MAAM,MAAM,WAAW,QAAQ,IAAI,IAAI,CAAC,CAAC,CACzC,MAAK,cAAaC,qBAAuB,SAAS,CAAC,GAEtD,MAAM,IAAI,MAAM,0CAA0C;EAG5D,IAAI,MAAM;GACR,MAAM,QAAQ,KAAK;GAEnB,IACE,CAACC,gBAAkB,KAAK,KACxB,MAAM,SAAS,QACf,MAAM,OAAO,MAEb,MAAM,IAAI,MAAM,+BAA+B;GAGjD,MAAM,KAAK;IACT,OAAO,MAAM;IACb,KAAK,MAAM;IACX,SAAS,KAAK,UAAU,MAAM,CAAC;GACjC,CAAC;EACH,OAAO;GACL,MAAM,KAAK,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,OAAO,MAAM,KAAK;GAEtD,IAAI,MAAM,MACR,MAAM,IAAI,MAAM,8BAA8B;GAGhD,MAAM,KAAK;IACT,OAAO;IACP,KAAK;IACL,SAAS,aAAa,MAAM,EAAE;GAChC,CAAC;EACH;CACF,CAAC;CAED,OAAO,WAAW,QAAQ,KAAK;AACjC;AAQA,MAAM,kBACJ,QACA,QACA,MACA,WACe;CACf,MAAM,UAAU,OAAO,eAAgB;CAEvC,IAAI,MAAM,SAAS,QAAQ,KAAK,OAAO,MAAM;EAC3C,MAAM,YAAY,OAAO,YAAY,MAAM,KAAK,QAAQ,CAAC,IAAI;EAC7D,MAAM,SAAS,OAAO,MAAM,WAAW,KAAK,KAAK;EACjD,MAAM,QAAQ,iBAAiB,KAAK,OAAO,MAAM,KAAK,KAAK,OAAO,CAAC;EAEnE,IAAI,SAAS,WAAW,KAAK,MAAM,GACjC,OAAO;GACL,OAAO,KAAK;GACZ,KAAK,KAAK;GACV,SAAS,OAAO,KAAI,SAAQ,GAAG,MAAM,KAAK,SAAS,MAAM,CAAC,CAAC,KAAK,EAAE;EACpE;CAEJ;CAEA,OAAO;EAAE,OAAO;EAAS,KAAK;EAAS,SAAS,OAAO,KAAK,EAAE;CAAE;AAClE;AAKA,MAAa,sBACX,QACA,QACA,OAGA,YACwB;CACxB,IAAI;EACF,IAAI,CAAC,OAAO,kBAAkB,OAAO,SAAS,QAAQ,OAAO,OAAO,MAClE,OAAO;EAGT,MAAM,QAAQ,OAAO,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;EAC9D,MAAM,WAAW,OAAO,SAAS,QAC9B,UACCC,aAAe,KAAK,KAAKC,cAAgB,KAAK,CAClD;EACA,MAAM,MAAM,SAAS,KAAI,UAAS,OAAO,MAAM,MAAM,OAAQ,MAAM,GAAI,CAAC;EACxE,MAAM,SACJ,QAAQ,OAAO,MAAM,OAAO,OAAO,OAAO,GAAG,GAAG,OAAO,CAAC,CAAC,EAAE,EAAE,YAC7D,CAAC;EAIH,IAAI,OAAO,WAAW,SAAS,QAC7B,OAAO;EAGT,MAAM,aAAa,kBAAkB,MAAM;EAC3C,MAAM,gBAAgB,SAAiC;GACrD,MAAM,QAAQ,SAAS,KAAK,OAAO,WAAW;IAC5C,OAAO,MAAM;IACb,KAAK,MAAM;IACX,SAAS,KAAK,UAAU;GAC1B,EAAE;GAEF,IAAI,KAAK,SAAS,SAAS,QACzB,MAAM,KACJ,eACE,QACA,QACA,SAAS,GAAG,EAAE,GACd,KAAK,MAAM,SAAS,MAAM,CAC5B,CACF;GAGF,OAAO;EACT;EAEA,IAAI,MAAM,QAAQ,KAAK,GAAG;GAIxB,MAAM,UAAU,kBAAkB,KAAK;GACvC,MAAM,WAAW,IAAI,OAClB,MAAM,UACL,aACE,gBAAgB,MAAM,EAAE,SAAS,CAAC,OAAO,YAAY,EAAE,CAAC,CAC1D,MAAM,WAAW,MACrB;GACA,MAAM,2BAAW,IAAI,IAAY;GACjC,MAAM,OAAO,QAAQ,KAAK,WAAW,aAAa;IAChD,MAAM,QAAQ,WAAW,WACtB,WAAW,MACV,cAAc,aACd,CAAC,SAAS,IAAI,CAAC,MACd,MAAM,SAAS,CAAC,WAAW,KAAA,KAC1B,MAAM,SAAS,CAAC,WAAW,IAAI,GACrC;IAEA,IAAI,SAAS,GAAG;KACd,SAAS,IAAI,KAAK;KAElB,OAAO,IAAI;IACb;IAEA,IACE,CAAC,YACA,MAAM,SAAS,CAAC,WAAW,KAAA,KAC1B,CAAC,IAAI,SAAS,MAAM,SAAS,CAAC,MAAM,GAEtC,MAAM,IAAI,MACR,0DACF;IAGF,OAAO;GACT,CAAC;GAID,MAAM,YAAY,SAAiB;IACjC,MAAM,yBAAS,IAAI,IAAoB;IACvC,aACE,gBAAgB,MAAM,EAAE,SAAS,CAAC,OAAO,YAAY,EAAE,CAAC,IACxD,SAAQ;KACN,IACEL,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC,KAChDE,gBAAkB,KAAK,KAAK,GAE5B,OAAO,IACL,KAAK,MAAM,QACV,OAAO,IAAI,KAAK,MAAM,KAAK,KAAK,KAAK,CACxC;IAEJ,CACF;IAEA,OAAO;GACT;GACA,MAAM,cAAc,SAAS,MAAM;GAInC,IACE,CAAC,GAHa,SADM,WAAW,QAAQ,aAAa,IAAI,CACrB,CAGzB,CAAC,CAAC,CAAC,MACV,CAAC,IAAI,WAAW,QAAQ,KAAK,SAAS,YAAY,IAAI,EAAE,KAAK,EAChE,GAEA,OAAO;GAGT,OAAO,aAAa,IAAI;EAC1B;EAEA,MAAM,UAAU;EAEhB,IACE,SAAS,SAAS,mBAClB,CAAC,MAAM,QAAQ,QAAQ,QAAQ,KAC/B,QAAQ,SAAS,WAAW,WAAW,UACvC,CAAC,sBAAsB,MAAM,CAAC,CAAC,OAC5B,WAAW,UAAU,cAAc,QAAQ,SAAS,MACvD,KACA,CAAC,QAAQ,QAET,OAAO;EAGT,MAAM,EAAE,WAAW;EACnB,MAAM,0BAAU,IAAI,IAAY;EAEhC,aAAe,SAAQ,SAAQ;GAC7B,IACEH,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC,KAChDE,gBAAkB,KAAK,KAAK,GAE5B,QAAQ,IAAI,KAAK,MAAM,KAAK;EAEhC,CAAC;EAED,QAAQ,OAAO,MAAf;GACE,KAAK,QAAQ;IACX,IACE,CAAC,gBAAgB,CAAC,OAAO,IAAI,GAAG,IAAI,MAAM,KAC1C,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,IAAI,MAAM,GAExC,OAAO;IAGT,MAAM,OAAO,CAAC,GAAG,GAAG;IACpB,MAAM,CAAC,SAAS,KAAK,OAAO,OAAO,MAAM,CAAC;IAC1C,KAAK,OAAO,OAAO,IAAI,GAAG,KAAM;IAEhC,OAAO,aAAa,IAAI;GAC1B;GACA,KAAK;IACH,IACE,CAAC,gBAAgB,OAAO,SAAS,IAAI,MAAM,KAC3C,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,SAAS,OAAO,SAAS,GAEzC,OAAO;IAGT,OAAO,aACL,oBAAoB,KAAK,IAAI,IAAI,OAAO,OAAO,GAAG,OAAO,SAAS,CAAC,CAChE,KACL;GAEF,KAAK;IACH,IAAI,CAAC,gBAAgB,OAAO,SAAS,IAAI,MAAM,GAC7C,OAAO;IAGT,OAAO,OAAO,QAAQ,KAAI,WAAU;KAClC,OAAO,SAAS,MAAM,CAAE;KACxB,KAAK,SAAS,MAAM,CAAE;KACtB,SAAS;IACX,EAAE;GAEJ,KAAK,aAAa;IAChB,IAAI,CAAC,gBAAgB,OAAO,SAAS,IAAI,MAAM,GAC7C,OAAO;IAGT,MAAM,SAAS,CAAC,GAAG,OAAO,OAAO,CAAC,CAC/B,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,CACrB,KAAI,UAAS,WAAW,IAAI,QAAS,OAAO,CAAC;IAEhD,OAAO,CAAC,eAAe,QAAQ,QAAQ,SAAS,GAAG,EAAE,GAAG,MAAM,CAAC;GACjE;GACA,KAAK,UAAU;IACb,MAAM,OAAO,WAAW,IAAI,MAAM,eAAe,OAAO;IAExD,OAAO,CAAC,eAAe,QAAQ,QAAQ,SAAS,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;GACjE;GACA,SACE,OAAO;EACX;CACF,QAAQ;EACN,OAAO;CACT;AACF;;;ACrXA,MAAa,uBACX,MACA,UACwB;CACxB,QAAQ,MAAR;EACE,KAAK,WACH,OAAOG,eAAiB,UAAU,IAAI;EAExC,KAAK,UACH,OAAOC,eAAiB,OAAO,KAAK,CAAC;EAEvC,KAAK,UACH,OAAOC,cAAgB,OAAO,KAAK,CAAC;EAEtC,KAAK,QACH,OAAOC,YAAc;EAEvB,KAAK;EACL,KAAK;EACL,KAAK,WACH,OAAO;EAET,SACE,OAAO;CAEX;AACF;AAMA,MAAa,qBAAqB,UAAwC;CACxE,IAAI,OAAO,UAAU,UACnB,OAAOD,cAAgB,KAAK;CAG9B,IAAI,OAAO,UAAU,UACnB,OAAO,QAAQ,IACXE,gBAAkB,KAAKH,eAAiB,CAAC,KAAK,CAAC,IAC/CA,eAAiB,KAAK;CAG5B,IAAI,OAAO,UAAU,WACnB,OAAOD,eAAiB,KAAK;CAG/B,IAAI,UAAU,MACZ,OAAOG,YAAc;CAGvB,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAOE,gBACL,MAAM,KAAI,SAAQ,kBAAkB,IAAI,KAAKF,YAAc,CAAC,CAC9D;CAGF,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,aAAiC,CAAC;EAExC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,KAAK,GAAG;GAC/C,MAAM,OAAO,kBAAkB,IAAI;GACnC,IAAI,SAAS,MACX;GAEF,WAAW,KAAKG,eAAiBJ,cAAgB,GAAG,GAAG,IAAI,CAAC;EAC9D;EAEA,OAAOK,iBAAmB,UAAU;CACtC;CAEA,OAAO;AACT;;;AC3DA,MAAa,iBACX,YAC0C;CAC1C,MAAM,EAAE,gBAAgB,mBAAmB;CAE3C,IACE,CAAC,kBACD,eAAe,OAAO,QACtB,eAAe,SAAS,MAExB,OAAO;CAGT,OAAO;EAAE,OAAO,eAAe;EAAK,KAAK,eAAe;CAAM;AAChE;AAEA,MAAa,iBACX,SACA,iBAC+B;CAC/B,OAAO,QAAQ,WAAW,MACvB,SACCC,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,IAAI,KAC3B,KAAK,KAAK,SAAS,YACvB;AACF;AAIA,MAAM,wBAAwB,YAAgD;CAG5E,OAFa,QAAQ,WAAW,QAAQ,WAAW,SAAS,EAEjD,EAAE,OAAO,QAAQ,KAAK,OAAO;AAC1C;AAOA,MAAM,iBAAiB,UACrB,MACG,QAAQ,yBAAyB,OAAO,CAAC,CACzC,QAAQ,MAAM,MAAM,CAAC,CACrB,QAAQ,MAAM,MAAM,CAAC,CACrB,QAAQ,OAAO,QAAQ,CAAC,CACxB,QAAQ,OAAO,QAAQ;AAS5B,MAAa,iBACX,QACA,SACA,UACe;CACf,MAAM,QAAQ,cAAc,OAAO;CAEnC,IAAI,CAAC,OACH,OAAO,CAAC;CAGV,MAAM,OAAO,cAAc,KAAK;CAChC,MAAM,CAAC,QAAQ,QAAQ;CAEvB,IACE,QAAQ,SAAS,WAAW,KAC5BC,UAAY,IAAI,KAChB,KAAK,SAAS,QACd,KAAK,OAAO,MACZ;EAIA,MAAM,MAAM,OAAO,MAAM,KAAK,OAAO,KAAK,GAAG;EAE7C,IAAI,IAAI,KAAK,MAAM,IAAI;GACrB,MAAM,eAAe,IAAI,MAAM,GAAG,IAAI,SAAS,IAAI,UAAU,CAAC,CAAC,MAAM;GACrE,MAAM,gBAAgB,IAAI,MAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;GAIpD,MAAM,UAAU,SAAS,KAAK,YAAY,IAAI,aAAa,SAAS;GACpE,MAAM,WAAW,SAAS,KAAK,aAAa,IAAI,cAAc,SAAS;GAEvE,OAAO,CACL;IACE,OAAO,KAAK,QAAQ;IACpB,KAAK,KAAK,MAAM;IAChB,SAAS;GACX,CACF;EACF;CACF;CAEA,MAAM,QAAsB,CAAC;CAE7B,KAAK,MAAM,SAAS,QAAQ,UAC1B,IAAIA,UAAY,KAAK,KAAK,MAAM,SAAS,QAAQ,MAAM,OAAO,MAC5D,MAAM,KAAK;EAAE,OAAO,MAAM;EAAO,KAAK,MAAM;EAAK,SAAS;CAAG,CAAC;CAIlE,MAAM,KAAK;EAAE,OAAO,MAAM;EAAK,KAAK,MAAM;EAAK,SAAS;CAAK,CAAC;CAE9D,OAAO;AACT;AAGA,MAAa,iBACX,SACA,UACe;CACf,MAAM,QAAQ,cAAc,OAAO;CAEnC,IAAI,CAAC,OACH,OAAO,CAAC;CAGV,OAAO,CAAC;EAAE,OAAO,MAAM;EAAO,KAAK,MAAM;EAAK,SAAS;CAAM,CAAC;AAChE;AAEA,MAAa,gBACX,SACA,UACe;CACf,MAAM,QAAsB,CAAC;CAC7B,MAAM,QAAQ,cAAc,OAAO;CAGnC,IAAI,SAAS,MAAM,UAAU,MAAM,KACjC,MAAM,KAAK;EAAE,OAAO,MAAM;EAAO,KAAK,MAAM;EAAK,SAAS;CAAG,CAAC;CAGhE,MAAM,UAAU,QAAQ;CACxB,MAAM,YAAYC,aAChBC,cAAgB,yBAAyB,GACzCC,uBACEC,iBAAmB,CACjBC,eAAiBC,WAAa,QAAQ,GAAGC,cAAgB,KAAK,CAAC,CACjE,CAAC,CACH,CACF;CACA,MAAM,UAAU,aAAa,SAAS;CACtC,MAAM,WAAW,cAAc,SAAS,yBAAyB;CAEjE,IAAI,YAAY,SAAS,SAAS,QAAQ,SAAS,OAAO,MAAM;EAC9D,MAAM,KAAK;GACT,OAAO,SAAS;GAChB,KAAK,SAAS;GACd;GACA,QAAQ;EACV,CAAC;EAED,OAAO;CACT;CAEA,MAAM,WAAW,qBAAqB,OAAO;CAE7C,IAAI,YAAY,MACd,OAAO;CAGT,MAAM,KAAK;EACT,OAAO;EACP,KAAK;EACL,SAAS,IAAI;EACb,QAAQ;CACV,CAAC;CAED,OAAO;AACT;AAIA,MAAa,oBACX,SACA,cACA,UACe;CACf,MAAM,YAAY,cAAc,SAAS,YAAY;CAErD,IAAI,CAAC,WACH,OAAO;CAGT,MAAM,UAAU,IAAI,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE;CAEzC,IAAI,UAAU,OAAO,SAAS,QAAQ,UAAU,MAAM,OAAO,MAC3D,OAAO,CACL;EACE,OAAO,UAAU,MAAM;EACvB,KAAK,UAAU,MAAM;EACrB;CACF,CACF;CAKF,MAAM,WAAW,UAAU,KAAK;CAEhC,IAAI,YAAY,MACd,OAAO;CAGT,OAAO,CAAC;EAAE,OAAO;EAAU,KAAK;EAAU,SAAS,IAAI;CAAU,CAAC;AACpE;AAMA,MAAM,6BAA6B,UACjCC,yBAA2B,KAAK,MAC/BC,kBAAoB,iBAAiB,MAAM,UAAU,CAAC,KACrDC,mBAAqB,iBAAiB,MAAM,UAAU,CAAC;AAK3D,MAAM,oBAAoB,UAAuC;CAC/D,IAAI;EACF,MAAM,aAAa,gBAAgB,MAAM,KAAK,GAAG,EAC/C,SAAS,CAAC,OAAO,YAAY,EAC/B,CAAC;EAED,OAAOD,kBAAoB,iBAAiB,UAAU,CAAC,KACrDC,mBAAqB,iBAAiB,UAAU,CAAC,IAC/C,aACA;CACN,QAAQ;EACN,OAAO;CACT;AACF;AAGA,MAAM,uBAAuB,UAC3B,MAAM,KAAK,KAAK,CAAC,CAAC,MAAK,SAAQ,KAAK,WAAW,CAAC,IAAI,EAAI;AAe1D,MAAM,kBACJ,UAC+C;CAC/C,IAAI,oBAAoB,KAAK,GAC3B,OAAOP,uBAAyBI,cAAgB,KAAK,CAAC;CAGxD,MAAM,QAAQ,MAAM,SAAS,IAAG,KAAK,CAAC,MAAM,SAAS,GAAG,IAAI,MAAM;CAClE,MAAM,OAAO,MAAM,QAAQ,yBAAyB,OAAO;CAC3D,MAAM,UAAU,UAAU,OAAM,KAAK,QAAQ,MAAM,QAAQ,IAAI;CAC/D,MAAM,UAAUA,cAAgB,KAAK;CAErC,QAAQ,QAAQ;EAAE,KAAK,GAAG,QAAQ,UAAU;EAAS,UAAU;CAAM;CAErE,OAAO;AACT;AAMA,MAAM,uBACJ,OACA,MACA,YAC4B;CAG5B,IAAI,SAAS,WAAW,SAAS,UAAU;EACzC,IAAI,OAAO,UAAU,UACnB,IAAI;GACF,OAAOJ,uBACL,gBAAgB,MAAM,KAAK,GAAG,EAAE,SAAS,CAAC,OAAO,YAAY,EAAE,CAAC,CAClE;EACF,QAAQ;GACN,OAAO,eAAe,KAAK;EAC7B;EAGF,MAAM,OAAO,kBAAkB,KAAK;EACpC,OAAO,OAAOA,uBAAyB,IAAI,IAAII,cAAgB,EAAE;CACnE;CAIA,IAAI,OAAO,UAAU,UAAU;EAI7B,IACE,0BAA0B,OAAO,KACjC,EAAE,QAAQ,oBAAoB,IAAI,IAAI,IACtC;GACA,MAAM,aAAa,iBAAiB,KAAK;GAEzC,IAAI,YACF,OAAOJ,uBAAyB,UAAU;EAE9C;EAEA,OAAO,eAAe,KAAK;CAC7B;CAEA,MAAM,OAAO,kBAAkB,KAAK;CACpC,OAAO,OAAOA,uBAAyB,IAAI,IAAI,eAAe,OAAO,KAAK,CAAC;AAC7E;AAEA,MAAa,iBACX,SACA,cACA,OACA,SACe;CACf,MAAM,YAAY,cAAc,SAAS,YAAY;CAErD,IAAI,CAAC,aAAa,UAAU,SAAS,QAAQ,UAAU,OAAO,MAC5D,OAAO;CAKT,IACE,OAAO,UAAU,aAChB,SAAS,WACR,SAAS,YACR,0BAA0B,UAAU,KAAK,KACxC,EAAE,QAAQ,oBAAoB,IAAI,IAAI,KAC1C;EACA,MAAM,aAAa,iBAAiB,KAAK;EAEzC,IAAI,cAAcK,yBAA2B,UAAU,KAAK,GAAG;GAC7D,MAAM,OAAO,MAAM,KAAK;GACxB,MAAM,cAAc,WAAW,kBAAkB,MAC/C,YAAW,QAAQ,SAAS,aAC9B;GAEA,OAAO,CACL;IACE,OAAO,UAAU,MAAM,WAAW;IAClC,KAAK,UAAU,MAAM,WAAW;IAChC,SAAS,GAAG,OAAO,cAAc,OAAO;GAC1C,CACF;EACF;CACF;CAKA,MAAM,UAAU,aACdP,aACE,UAAU,MACV,oBAAoB,OAAO,MAAM,UAAU,KAAK,CAClD,CACF;CAEA,OAAO,CACL;EAAE,OAAO,UAAU;EAAO,KAAK,UAAU;EAAK;EAAS,QAAQ;CAAK,CACtE;AACF;AAIA,MAAM,oBACJ;AAMF,MAAa,mBACX,QACA,cACe;CACf,IAAI,UAAU,SAAS,QAAQ,UAAU,OAAO,MAC9C,OAAO;CAGT,MAAM,YAAY,OAAO,YAAY,MAAM,UAAU,QAAQ,CAAC,IAAI;CAClE,MAAM,OAAO,kBAAkB,KAAK,OAAO,MAAM,UAAU,GAAG,CAAC;CAE/D,IAAI,WAAW,KAAK,OAAO,MAAM,WAAW,UAAU,KAAK,CAAC,KAAK,MAC/D,OAAO,CACL;EAAE,OAAO;EAAW,KAAK,UAAU,MAAM,KAAK,EAAE,CAAC;EAAQ,SAAS;CAAG,CACvE;CAGF,IAAI,QAAQ,UAAU;CAEtB,OAAO,QAAQ,KAAK,KAAK,KAAK,OAAO,QAAQ,EAAG,GAC9C,SAAS;CAGX,OAAO,CAAC;EAAE;EAAO,KAAK,UAAU;EAAK,SAAS;CAAG,CAAC;AACpD;AAMA,MAAa,gBACX,QACA,SACA,cACA,OACA,SACe;CACf,MAAM,WAAW,qBAAqB,OAAO;CAE7C,IAAI,YAAY,MACd,OAAO;CAKT,MAAM,YAAY,QAAQ,WAAW,QAAQ,WAAW,SAAS,EAAE,EAAE;CACrE,MAAM,YACJ,aAAa,OAAO,KAAK,OAAO,YAAY,MAAM,YAAY,CAAC,IAAI;CAiBrE,OAAO,CACL;EACE,OAAO;EACP,KAAK;EACL,SAAS,GAnBX,aAAa,QACb,YAAY,KACZ,QAAQ,KAAK,OAAO,MAAM,WAAW,SAAS,CAAC,IACrB,OAAO,MAGjC,SAAS,QACL,GAAG,aAAa,IAAI,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,KACzC,aACEA,aACEC,cAAgB,YAAY,GAC5B,oBAAoB,OAAO,IAAI,CACjC,CACF;EAOF,QAAQ;CACV,CACF;AACF;AAEA,MAAa,yBACX,WACA,OACA,SACG;CACH,IACE,CAACM,yBAA2B,UAAU,KAAK,KAC3CG,qBAAuB,UAAU,MAAM,UAAU,KACjD,sBAAsB,UAAU,MAAM,UAAU,GAEhD,OAAO;CAKT,OACE,OAAO,UAAU,YACjB,0BAA0B,UAAU,KAAK,KACzC,EAAE,QAAQ,oBAAoB,IAAI,IAAI,MACtC,iBAAiB,KAAK,MAAM;AAEhC;;;ACvaA,MAAM,aAAa,SAA8B,WAC/C,QAAQ,WAAW,MACjB,SACEC,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,IAAI,KAC3B,KAAK,KAAK,SAAS,UAAU,MAC7B,KAAK,SACLC,gBAAkB,KAAK,KAAK,KAC5B,KAAK,MAAM,UAAU,MACzB;AAEF,MAAM,oBAAoB,SAA8B,SACtD,QAAQ,WAAW,MAChB,SACCF,eAAiB,IAAI,KACrBC,gBAAkB,KAAK,IAAI,KAC3B,KAAK,KAAK,SAAS,IACvB;AAMF,MAAM,eACJ,SACA,EAAE,QAAQ,OAAO,UAAU,cAC+B;CAC1D,MAAM,cAAc,iBAAiB,SAAS,UAAU,OAAO;CAG/D,IAAI,eAAe,CAAC,YAAY,OAC9B,OAAO,EAAE,SAAS;EAAE,QAAQ;EAAc;CAAO,EAAE;CAGrD,IAAI;CAEJ,IAAI,aAAa,OAAO;EACtB,IAAI,eAAe;EAEnB,IAAIC,gBAAkB,YAAY,KAAK,GACrC,eAAe,YAAY,MAAM;OAC5B,IAAIC,yBAA2B,YAAY,KAAK,GACrD,IAAI;GACF,eAAe,aAAa,YAAY,MAAM,UAAU;EAC1D,SAAS,OAAO;GACd,OAAO,EAAE,SAAS;IAAE,QAAQ;IAAe;GAAM,EAAE;EACrD;EAGF,MAAM,aAAa,YAAY;CACjC;CAEA,MAAM,UAAU,iBAAiB,SAAS,UAAU,WAAW;CAC/D,MAAM,WAAW,gBACf,KACA,YACG,QAAQ,SAASD,gBAAkB,QAAQ,KAAK,IAC7C,QAAQ,MAAM,QACd,OACN,cAAc,OAAO,GACrB,OACF;CAEA,IAAI,CAAC,OAAO,SAAS,WAAW,GAC9B,OAAO,EAAE,SAAS;EAAE,QAAQ;EAAc;CAAO,EAAE;CAGrD,MAAM,UAAU,SAAS,QAAO,YAC9B,aAAa,KAAA,IACT,QAAQ,aAAa,WACrB,QAAQ,UAAU,KACxB;CAEA,IAAI,QAAQ,WAAW,GACrB,OAAO,EACL,SAAS;EAAE,QAAQ;EAAwB;EAAQ;EAAO;CAAS,EACrE;CAGF,IAAI,QAAQ,SAAS,GACnB,OAAO,EACL,SAAS;EACP,QAAQ;EACR;EACA;EACA;EACA,OAAO,QAAQ;CACjB,EACF;CAGF,OAAO,EAAE,SAAS,QAAQ,GAAI;AAChC;AAIA,MAAM,aACJ,SACA,EAAE,QAAQ,YACoB;CAC9B,MAAM,WAAW,QAAQ;CAEzB,IAAI,4BAA4B,SAAS,QAAQ,GAC/C,OAAO;EAAE,QAAQ;EAAqB;EAAQ;CAAS;CAGzD,IAAI,UAAU,KAAA,KAAa,QAAQ,UACjC,OAAO;EAAE,QAAQ;EAAqB;EAAQ;CAAS;AAI3D;AAGA,MAAM,iBACJ,QACA,WACiB,SAAS,EAAE,OAAO,OAAO,IAAI,EAAE,SAAS,OAAO,EAAE;AAIpE,MAAM,gBACJ,QACA,SACA,SACA,EAAE,QAAQ,OAAO,cACD;CAChB,MAAM,UAAU,QAAQ;CACxB,MAAM,OAAO,QAAQ;CACrB,MAAM,QAAQ,UAAU,KAAA;CACxB,MAAM,wBAAuC;EAC3C,QAAQ;EACR,uBAAO,IAAI,MAAM,qBAAqB,KAAK,EAAE;CAC/C;CAIA,MAAM,qBACJ,CAAC,SAAS,OAAO,KAAK,MAAM,MAAM,CAAC,cAAc,OAAO;CAE1D,QAAQ,MAAR;EACE,KAAK,aAAa;GAChB,IAAI,oBACF,OAAO,EAAE,SAAS;IAAE,QAAQ;IAAgB;IAAQ,UAAU;GAAK,EAAE;GAGvE,OAAO,cACL,cAAc,QAAQ,SAAS,QAAQ,KAAK,OAAO,KAAK,CAAC,GACzD,cACF;EAGF,KAAK,aAAa;GAEhB,IAAI,sBAAsB,QAAQ,SAAS,YACzC,OAAO,EAAE,SAAS;IAAE,QAAQ;IAAgB;IAAQ,UAAU;GAAK,EAAE;GAGvE,OAAO,cACL,QAAQ,SAAS,aACb,aAAa,SAAS,QAAQ,KAAK,OAAO,KAAK,CAAC,IAChD,cAAc,SAAS,QAAQ,KAAK,OAAO,KAAK,CAAC,GACrD,cACF;EAGF,KAAK,aAAa;GAGhB,IAAI,OACF,OAAO,EACL,SAAS;IAAE,QAAQ;IAAsB;IAAQ,UAAU;GAAK,EAClE;GAGF,OAAO,cACL,mBAAmB,QAAQ,SAAS,OAAO,OAAO,UAC3C;IACL,QAAQ;IACR,uBAAO,IAAI,MACT,0DACF;GACF,EACF;EAGF,SAAS;GACP,MAAM,YAAY,cAAc,SAAS,IAAI;GAE7C,IAAI,OAEF,OAAO,cACL,YAAY,gBAAgB,QAAQ,SAAS,IAAI,CAAC,UAC3C;IACL,QAAQ;IACR,uBAAO,IAAI,MAAM,qBAAqB,KAAK,EAAE;GAC/C,EACF;GAMF,IAAI,CAAC,WACH,OAAO,cACL,UAAU,KACN,CAAC,IACD,aAAa,QAAQ,SAAS,MAAM,OAAO,QAAQ,IAAI,UACpD;IAAE,QAAQ;IAAuB;IAAQ,UAAU;GAAK,EACjE;GAGF,IACE,QAAQ,SAAS,SACjB,CAAC,sBAAsB,WAAW,OAAO,QAAQ,IAAI,GAErD,OAAO,EACL,SAAS;IAAE,QAAQ;IAAsB;IAAQ,UAAU;GAAK,EAClE;GAGF,OAAO,cACL,QAAQ,SAAS,QACb,iBAAiB,SAAS,MAAM,KAAK,IACrC,cAAc,SAAS,MAAM,OAAO,QAAQ,IAAI,UAC7C;IAAE,QAAQ;IAAuB;IAAQ,UAAU;GAAK,EACjE;EACF;CACF;AACF;AAGA,MAAM,eACJ,QACA,SACA,YACgB;CAChB,MAAM,QAAQ,YAAY,QAAQ,gBAAgB,OAAO;CAEzD,IAAI,aAAa,OACf,OAAO;CAGT,MAAM,UAAU,UAAU,MAAM,SAAS,OAAO;CAEhD,IAAI,SACF,OAAO,EAAE,SAAS,QAAQ;CAG5B,OAAO,aAAa,QAAQ,SAAS,MAAM,SAAS,OAAO;AAC7D;AASA,MAAa,UACX,MACA,QACA,OACA,OACA,UACA,UAA0B,CAAC,MACV;CACjB,MAAM,UAAyB;EAAE;EAAQ;EAAO;EAAO;EAAU;CAAQ;CAEzE,IAAI;EACF,MAAM,UAAU,KAAK,IAAI;EACzB,MAAM,MAAM,MAAM,SAAS;GACzB,YAAY;GACZ,SAAS,CAAC,OAAO,YAAY;EAC/B,CAAC;EAED,IAAI,UAAU;EACd,IAAI;EACJ,MAAM,QAAsB,CAAC;EAI7B,SAAS,KAAK,EACZ,WAAW,MAAM;GACf,IAAI,CAAC,UAAU,KAAK,KAAK,gBAAgB,MAAM,GAC7C;GAGF,MAAM,SAAS,YAAY,SAAS,KAAK,MAAM,OAAO;GAEtD,IAAI,aAAa,QAAQ;IACvB,UAAU,OAAO;IAEjB;GACF;GAEA,MAAM,KAAK,GAAG,OAAO,KAAK;GAC1B,UAAU;EACZ,EACF,CAAC;EAED,IAAI,CAAC,SACH,OAAO;GACL;GACA,SAAS;GAGT,SAAS,WAAW;IAAE,QAAQ;IAAqB;GAAO;EAC5D;EAKF,OAAO;GAAE,MAAM,OAAO,WAAW,SAAS,KAAK,CAAC;GAAG,SAAS;EAAK;CACnE,SAAS,OAAO;EACd,QAAQ,MAAM,wBAAwB,KAAK;EAC3C,OAAO;GAAE;GAAM,SAAS;GAAO,SAAS;IAAE,QAAQ;IAAe;GAAM;EAAE;CAC3E;AACF;AAwBA,MAAa,aACX,KACA,SACA,UAA0B,CAAC,MACP;CACpB,IAAI,UAAU;CAEd,KAAK,MAAM,CAAC,OAAO,UAAU,QAAQ,QAAQ,GAAG;EAC9C,MAAM,SAAS,OACb,SACA,MAAM,QACN,MAAM,OACN,MAAM,OACN,MAAM,UACN,OACF;EAEA,IAAI,CAAC,OAAO,SACV,OAAO;GACL,SAAS;GACT,MAAM;GACN,SAAS,OAAO,WAAW;IACzB,QAAQ;IACR,QAAQ,MAAM;GAChB;GACA;EACF;EAGF,UAAU,OAAO;CACnB;CAEA,OAAO;EAAE,SAAS;EAAM,MAAM;CAAQ;AACxC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-dynamic-tailwind-0nuRN57N.js","names":[],"sources":["../src/components/frame/auto-height/measure.ts","../src/components/frame/auto-height/animations.ts","../src/components/frame/viewport-units.ts","../src/components/frame/auto-height/auto-height.ts","../src/components/frame/auto-height/use-auto-height.ts","../src/components/frame/iframe/inject-assets.ts","../src/components/frame/style-sync.ts","../src/components/frame/iframe/use-host-style-sync.ts","../src/components/frame/iframe/use-iframe-document.ts","../src/components/frame/iframe/iframe.tsx","../src/components/frame/shadow.tsx","../src/components/frame/frame.tsx","../src/components/preview/stable-component.ts","../src/components/preview/defaults.ts","../src/components/preview/use-compiled-module.ts","../src/components/preview/use-dynamic-tailwind.ts"],"sourcesContent":["// The calculations behind `autoHeight`, kept free of the DOM so they can be\n// unit-tested. The DOM reads stay in `auto-height.ts`, which needs a real\n// 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","import { isAnimationActive } from './measure';\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.\nexport const isCssAnimation = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSAnimation === 'function' &&\n animation instanceof win.CSSAnimation;\n\nexport const 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.\nexport const 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.\nexport const neverFinishes = (animation: Animation): boolean => {\n const timing = animation.effect?.getComputedTiming();\n\n return timing?.iterations === Infinity || timing?.duration === Infinity;\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 { rewriteInlineViewportUnits } from '../viewport-units';\nimport { hasActiveAnimation } from './animations';\nimport {\n FALLBACK_PROBE_HEIGHT,\n computeProbeHeight,\n isVisuallyHidden,\n positionedElementBottom,\n verticalInsets,\n} from './measure';\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.\nexport const CONTAINER_STYLE_ID = 'autoheight-container';\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\nexport const 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\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.\nexport 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).\nconst 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// The height the preview's `cq*` units resolve against, read from the\n// iframe's scroll container. `null` while the layout isn't ready.\nexport const getProbeHeight = (\n iframe: HTMLIFrameElement,\n win: Window,\n): number | null => {\n const scrollParent = iframe.closest<HTMLElement>('[data-frame-container]');\n\n if (!scrollParent) {\n // No scroll container (`Frame` used without `Live.Dnd`): use a fixed\n // default. See `FALLBACK_PROBE_HEIGHT`.\n return FALLBACK_PROBE_HEIGHT;\n }\n\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 return computeProbeHeight(scrollParent.clientHeight, wrapperInsets);\n};\n\n// The height of the preview's content with the iframe sized to\n// `probeHeight`: the mount node's `scrollHeight`, or the bottom edge of a\n// fixed or absolute element if that reaches further. Runs inside the\n// measurement overrides, and writes the container style and the rewritten\n// viewport units into the document.\nexport const measureContentHeight = (\n mountNode: HTMLElement,\n doc: Document,\n win: Window,\n probeHeight: number,\n freezeTransitions: boolean,\n): number => {\n let contentHeight = 0;\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 return contentHeight;\n};\n","import { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { RefObject } from 'react';\n\nimport {\n useEventListener,\n useMutationObserver,\n useResizeObserver,\n} from '@jbpark/use-hooks';\n\nimport { isCssAnimation, isCssTransition, neverFinishes } from './animations';\nimport {\n CONTAINER_STYLE_ID,\n HIDE_SCROLLBAR_STYLE_ID,\n SCROLLBAR_OVERRIDE_RULES,\n getProbeHeight,\n measureContentHeight,\n} from './auto-height';\nimport { isAnimationActive } from './measure';\n\n// Sizes the iframe to its content while `shouldAutoHeight` is on, and\n// re-measures when anything that can change the height does. Also owns the\n// document styles that only `autoHeight` needs. Call it after the hooks that\n// set up the document: the effects below rely on running after them.\nexport const useAutoHeight = (\n iframeRef: RefObject<HTMLIFrameElement | null>,\n mountNode: HTMLElement | null,\n shouldAutoHeight: boolean,\n) => {\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 // 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 void 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 probeHeight = getProbeHeight(iframe, win);\n\n if (probeHeight === null) {\n // Layout isn't ready yet: skip this pass. The observers call this again\n // once it settles.\n return;\n }\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 const contentHeight = measureContentHeight(\n mountNode,\n doc,\n win,\n probeHeight,\n freezeTransitions,\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 }, [iframeRef, 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 }, [iframeRef, 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 }, [iframeRef, 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 = SCROLLBAR_OVERRIDE_RULES.join('\\n');\n doc.head.appendChild(styleEl);\n }, [iframeRef, 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 // Runs on each size the resize observer reports. `updateHeight` stays out\n // of the deps: the effect above already runs it whenever it changes.\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","import { convertViewportUnits } from '../viewport-units';\n\n// How many `<style>` and `<link>` elements the last sync left in the\n// document, so a shorter list can remove the extras.\nexport interface InjectedCounts {\n styles: number;\n stylesheets: number;\n}\n\n// Gives each value its own element in the head, found again by\n// `${idPrefix}${index}`, and removes the elements a shorter list leaves\n// behind.\nconst syncInjectedElements = <T extends HTMLElement>(\n doc: Document,\n idPrefix: string,\n values: string[],\n previousCount: number,\n create: () => T,\n update: (el: T, value: string) => void,\n) => {\n values.forEach((value, index) => {\n const id = `${idPrefix}${index}`;\n let el = doc.getElementById(id) as T | null;\n\n if (!el) {\n el = create();\n el.id = id;\n doc.head.appendChild(el);\n }\n\n update(el, value);\n });\n\n for (let index = values.length; index < previousCount; index++) {\n doc.getElementById(`${idPrefix}${index}`)?.remove();\n }\n};\n\n// Writes `styles` (CSS text) and `stylesheets` (URLs) into the document's\n// head and returns the counts for the next call. Writes only what differs.\nexport const syncInjectedAssets = (\n doc: Document,\n styles: string[],\n stylesheets: string[],\n previous: InjectedCounts,\n): InjectedCounts => {\n syncInjectedElements(\n doc,\n 'injected-style-',\n styles,\n previous.styles,\n () => doc.createElement('style'),\n (styleEl, css) => {\n // The main source of `vh` units in a preview: compiled component CSS,\n // such as Tailwind's `h-screen`. See `ensureContainerStyle` in\n // `auto-height.ts` for why they're converted.\n const convertedCss = convertViewportUnits(css);\n\n if (styleEl.textContent !== convertedCss) {\n styleEl.textContent = convertedCss;\n }\n },\n );\n\n syncInjectedElements(\n doc,\n 'injected-stylesheet-',\n stylesheets,\n previous.stylesheets,\n () => {\n const linkEl = doc.createElement('link');\n\n linkEl.rel = 'stylesheet';\n\n return linkEl;\n },\n (linkEl, href) => {\n if (linkEl.href !== href) {\n linkEl.href = href;\n }\n },\n );\n\n return { styles: styles.length, stylesheets: stylesheets.length };\n};\n","const SYNCED_STYLE_ATTR = 'data-live-editor-synced-style';\n\ntype SourceStyle = HTMLLinkElement | HTMLStyleElement;\ntype SyncedStyle = HTMLLinkElement | HTMLStyleElement;\n\ninterface 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.\ninterface 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","import { useCallback, useRef } from 'react';\nimport type { RefObject } from 'react';\n\nimport { useDebouncedCallback, useMutationObserver } from '@jbpark/use-hooks';\n\nimport { CONTAINER_STYLE_ID } from '../auto-height/auto-height';\nimport {\n createRootAttributeSync,\n createStyleSyncManager,\n reconcileRootAttributes,\n reconcileStyles,\n} from '../style-sync';\nimport { convertViewportUnits } from '../viewport-units';\n\n// Copies the host page's styles and root attributes into the iframe while\n// `syncStyle` is on, and again whenever the host changes them. Returns\n// `applyStyle`, which the document setup calls once the iframe's document\n// exists.\nexport const useHostStyleSync = (\n iframeRef: RefObject<HTMLIFrameElement | null>,\n syncStyle: boolean,\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 }, [iframeRef, syncStyle]);\n\n // Debounced, since a stylesheet swap fires several head mutations in a\n // row.\n const debouncedApplyStyle = useDebouncedCallback(applyStyle, {\n delay: 50,\n autoInvoke: false,\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 return applyStyle;\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { RefObject } from 'react';\n\nimport { withScriptBlobs } from '~/utils/scripts';\n\n// Adds each script to the document's head as a `<script>` that loads from a\n// blob URL. Not awaited: a script that fails to load becomes an unhandled\n// rejection on the host page.\nconst injectScripts = (doc: Document, srcs: string[]) => {\n void withScriptBlobs(srcs, 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\ninterface Options {\n scripts: string[];\n onLoaded?: () => void;\n applyStyle: () => void;\n}\n\n// Prepares the iframe's document each time it loads: creates the mount node,\n// applies the host styles, injects the scripts not yet in it and calls\n// `onLoaded`. Returns the mount node, `null` until the first load.\nexport const useIframeDocument = (\n iframeRef: RefObject<HTMLIFrameElement | null>,\n { scripts, onLoaded, applyStyle }: Options,\n) => {\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\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 injectScripts(doc, pendingScripts);\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 }, [iframeRef, scripts, onLoaded, applyStyle]);\n\n return mountNode;\n};\n","import { useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useAutoHeight } from '../auto-height/use-auto-height';\nimport { type InjectedCounts, syncInjectedAssets } from './inject-assets';\nimport { useHostStyleSync } from './use-host-style-sync';\nimport { useIframeDocument } from './use-iframe-document';\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\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 shouldAutoHeight = autoHeight && style.height == null;\n\n const applyStyle = useHostStyleSync(iframeRef, syncStyle);\n const mountNode = useIframeDocument(iframeRef, {\n scripts,\n onLoaded,\n applyStyle,\n });\n const injectedCountsRef = useRef<InjectedCounts>({\n styles: 0,\n stylesheets: 0,\n });\n\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n injectedCountsRef.current = syncInjectedAssets(\n doc,\n styles,\n stylesheets,\n injectedCountsRef.current,\n );\n }, [styles, stylesheets]);\n\n useAutoHeight(iframeRef, mountNode, shouldAutoHeight);\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 { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useDebouncedCallback, 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 // Debounced, since a stylesheet swap fires several head mutations in a\n // row, as in `iframe.tsx`.\n const debouncedApplyStyle = useDebouncedCallback(applyStyle, {\n delay: 50,\n autoInvoke: false,\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/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 { createElement } from 'react';\n\ntype Props = Record<string, unknown>;\ntype Component = React.ComponentType<Props>;\n\n// Every hook call in `code`, in source order: `useState(`, `React.useMemo(`,\n// `use(`. Two compiles of a component with the same list call the same\n// hooks in the same order, which is what React needs to keep its state.\nconst HOOK_CALL = /\\buse(?:[A-Z0-9_]\\w*)?\\s*\\(/g;\n\nexport const hookSignature = (code: string): string =>\n (code.match(HOOK_CALL) ?? [])\n .map(call => call.replace(/\\s*\\($/, ''))\n .join(',');\n\n// A plain function component, which can be called with its props. Class\n// components and the objects `memo`, `forwardRef` and `lazy` return can't.\nconst isFunctionComponent = (\n component: Component,\n): component is React.FunctionComponent<Props> =>\n typeof component === 'function' &&\n !(component.prototype as { isReactComponent?: unknown } | undefined)\n ?.isReactComponent;\n\ninterface StableProps {\n render: React.FunctionComponent<Props>;\n props: Props;\n}\n\n// One component type for every compile, which calls the compiled function\n// itself, so the function's output belongs to this type.\nconst StableComponent = ({ render, props }: StableProps) => render(props);\n\n// Renders `Component`, compiled from `code`, under a component type that\n// survives a recompile. Each compile returns a new function, and React\n// remounts a subtree whose component type changes, so rendering it directly\n// rebuilds a section's whole DOM on every edit. While the hook calls in\n// `code` stay the same, the type and key here stay the same too, and React\n// updates only what the new output changes. When they change, the key\n// changes and the subtree remounts, so React never sees a different hook\n// order. A class, `memo` or `forwardRef` component renders as itself.\nexport const renderStableComponent = (\n Component: Component,\n code: string,\n props: Props,\n): React.ReactElement =>\n isFunctionComponent(Component)\n ? createElement(StableComponent, {\n key: hookSignature(code),\n render: Component,\n props,\n })\n : createElement(Component, props);\n","// 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","import { useMemo } from 'react';\n\nimport { useStableValue } from '@jbpark/use-hooks';\n\nimport { useLiveMessages } from '~/components/context/messages';\nimport type { Module } from '~/types';\nimport { compile } from '~/utils/compile';\n\nimport { NO_MODULES } from './defaults';\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 = useStableValue(_modules);\n const { unknown } = useLiveMessages().errors;\n\n return useMemo(() => {\n if (!code) {\n return null;\n }\n\n try {\n return compile(code, modules ?? NO_MODULES);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : unknown,\n };\n }\n }, [code, modules, unknown]);\n};\n","import { useCallback, useEffect, useState } from 'react';\n\nimport { useAsync } from '@jbpark/use-hooks';\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).\n//\n// `css` keeps the last compiled result while the next one runs, while it's\n// off, and after a failure. A failure is logged and returned as `error`.\nexport const useDynamicTailwind = (code: string, enabled: boolean) => {\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const ref = useCallback((node: HTMLDivElement | null) => {\n setElement(node);\n }, []);\n\n const { value: css = '', error } = useAsync(\n async () => {\n const { generateTailwindCSSFromDOM } = await import('~/utils/tailwind');\n\n return generateTailwindCSSFromDOM(element!);\n },\n [code, element],\n { enabled: enabled && !!code && !!element },\n );\n\n useEffect(() => {\n if (error) {\n console.error('Generating the preview Tailwind CSS failed', error);\n }\n }, [error]);\n\n return { ref, css, error };\n};\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["t.isArrayExpression","t.isSpreadElement","t.isObjectExpression","t.isObjectProperty","t.isIdentifier","t.isStringLiteral","t.isNumericLiteral","t.isBooleanLiteral","t.isUnaryExpression","t.isTemplateLiteral","t.isJSXElement","t.isJSXFragment"],"sources":["../../../src/utils/ast/editable-value.ts"],"sourcesContent":["import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\n\nimport { parseValue, unwrapExpression } from './value';\n\n// The editable leaves of an object or array value: listing them with their\n// paths, and replacing one while keeping the rest of the source as written.\n\nexport type EditablePathSegment = string | number;\n\nexport type EditablePrimitive = string | number | boolean;\n\nexport interface EditableValueEntry {\n path: EditablePathSegment[];\n value: EditablePrimitive;\n}\n\nconst MAX_FLATTEN_DEPTH = 20;\n\nconst isEditablePrimitive = (value: unknown): value is EditablePrimitive =>\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean';\n\n// Lists the editable leaves of an object or array value, with their paths.\n// It follows the value's own shape, so it works without a `render` map\n// (#225), as for `style` or an `items` array of `{ key, children }`. Strings,\n// numbers and booleans are leaves, whatever a string contains. Deeply nested\n// values stop at a fixed depth, and anything deeper is left out.\nexport const flattenEditableValue = (\n value: string,\n): EditableValueEntry[] | null => {\n const parsed = parseValue(value);\n\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n Object.keys(parsed).length === 0\n ) {\n return null;\n }\n\n const entries: EditableValueEntry[] = [];\n\n const walk = (node: unknown, path: EditablePathSegment[], depth: number) => {\n if (depth > MAX_FLATTEN_DEPTH) {\n return;\n }\n\n if (isEditablePrimitive(node)) {\n entries.push({ path, value: node });\n return;\n }\n\n if (Array.isArray(node)) {\n node.forEach((item, index) => walk(item, [...path, index], depth + 1));\n return;\n }\n\n if (typeof node === 'object' && node !== null) {\n Object.entries(node).forEach(([key, item]) =>\n walk(item, [...path, key], depth + 1),\n );\n }\n\n // `null`, `undefined`, functions and symbols have no editable form and\n // are left out.\n };\n\n walk(parsed, [], 0);\n\n return entries.length ? entries : null;\n};\n\n// Finds the node `flattenEditableValue` reported at `path`, walking the\n// same literal structure `evaluateLiteral` reads. Returns null for anything\n// it can't point at with certainty: a missing key or index, a step through\n// something that isn't an object or array, or a spread that could replace\n// the entry at runtime.\nconst findEditableLeaf = (\n root: t.Node,\n path: EditablePathSegment[],\n): t.Node | null => {\n let node = unwrapExpression(root);\n\n for (const segment of path) {\n if (t.isArrayExpression(node)) {\n if (typeof segment !== 'number') {\n return null;\n }\n\n const elements = node.elements.slice(0, segment + 1);\n const element = node.elements[segment];\n\n if (!element || elements.some(item => t.isSpreadElement(item))) {\n return null;\n }\n\n node = unwrapExpression(element);\n continue;\n }\n\n if (t.isObjectExpression(node)) {\n const key = String(segment);\n const matches = (property: t.ObjectExpression['properties'][number]) =>\n t.isObjectProperty(property) &&\n !property.computed &&\n ((t.isIdentifier(property.key) && property.key.name === key) ||\n (t.isStringLiteral(property.key) && property.key.value === key) ||\n (t.isNumericLiteral(property.key) &&\n String(property.key.value) === key));\n // The last match is the one a duplicate key leaves in effect, and the\n // one `evaluateLiteral` reports.\n let index = node.properties.length - 1;\n\n while (index >= 0 && !matches(node.properties[index]!)) {\n index--;\n }\n\n const property = node.properties[index];\n\n if (\n !property ||\n !t.isObjectProperty(property) ||\n node.properties.slice(index + 1).some(item => t.isSpreadElement(item))\n ) {\n return null;\n }\n\n node = unwrapExpression(property.value);\n continue;\n }\n\n return null;\n }\n\n return node;\n};\n\nconst isEditableLeaf = (node: t.Node): boolean =>\n t.isStringLiteral(node) ||\n t.isNumericLiteral(node) ||\n t.isBooleanLiteral(node) ||\n (t.isUnaryExpression(node) &&\n node.operator === '-' &&\n t.isNumericLiteral(node.argument)) ||\n (t.isTemplateLiteral(node) && node.expressions.length === 0) ||\n t.isJSXElement(node) ||\n t.isJSXFragment(node);\n\nconst quoteString = (text: string, quote: string): string => {\n if (quote === '`') {\n return `\\`${text.replace(/[\\\\`]|\\$\\{/g, match => `\\\\${match}`)}\\``;\n }\n\n const escaped = JSON.stringify(text).slice(1, -1);\n\n return quote === '\"'\n ? `\"${escaped}\"`\n : `'${escaped.replace(/\\\\\"/g, '\"').replace(/'/g, \"\\\\'\")}'`;\n};\n\nconst isJSXSource = (text: string): boolean => {\n try {\n const expression = parseExpression(text, { plugins: ['jsx'] });\n\n return t.isJSXElement(expression) || t.isJSXFragment(expression);\n } catch {\n return false;\n }\n};\n\n// Source text for `next` in place of `leaf`, keeping the leaf's own form\n// where it has one: a string keeps its quotes, and a JSX leaf, which\n// `flattenEditableValue` reports as its source text, stays JSX when the\n// edited text still is.\nconst leafSource = (\n value: string,\n leaf: t.Node,\n next: EditablePrimitive,\n): string => {\n if (typeof next !== 'string') {\n return String(next);\n }\n\n if ((t.isJSXElement(leaf) || t.isJSXFragment(leaf)) && isJSXSource(next)) {\n return next.trim();\n }\n\n const quote =\n t.isStringLiteral(leaf) || t.isTemplateLiteral(leaf)\n ? value[leaf.start!]!\n : \"'\";\n\n return quoteString(next, quote);\n};\n\n// Replaces the leaf at `path` (as `flattenEditableValue` reports it) and\n// returns `value` with only that leaf's source changed, so formatting,\n// comments, JSX, functions and references stay (#427). The result is a\n// string for `PanelBinding.onChange`. A path it can't find, or a `value`\n// that doesn't parse, returns `value` unchanged. It never adds a key or\n// grows an array.\nexport const setEditableValue = (\n value: string,\n path: EditablePathSegment[],\n next: EditablePrimitive,\n): string => {\n if (!path.length) {\n return value;\n }\n\n let leaf: t.Node | null;\n\n try {\n leaf = findEditableLeaf(\n parseExpression(value, { plugins: ['jsx', 'typescript'] }),\n path,\n );\n } catch {\n return value;\n }\n\n if (\n !leaf ||\n !isEditableLeaf(leaf) ||\n leaf.start == null ||\n leaf.end == null\n ) {\n return value;\n }\n\n return `${value.slice(0, leaf.start)}${leafSource(value, leaf, next)}${value.slice(leaf.end)}`;\n};\n"],"mappings":"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"}