@jbpark/live-editor 4.0.1 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dnd/index.js +1 -1
- package/dist/{dnd-_0jfnnVB.js → dnd-D_rG92-R.js} +22 -4
- package/dist/{dnd-_0jfnnVB.js.map → dnd-D_rG92-R.js.map} +1 -1
- package/dist/index.js +2 -2
- package/dist/preview/index.js +2 -2
- package/dist/{preview-DKyKKcu7.js → preview-CS6Rsppd.js} +8 -4
- package/dist/preview-CS6Rsppd.js.map +1 -0
- package/dist/style.css +550 -688
- package/dist/{use-dynamic-tailwind-BF8TQ3Yy.js → use-dynamic-tailwind-SOgrb2qc.js} +2 -3
- package/dist/{use-dynamic-tailwind-BF8TQ3Yy.js.map → use-dynamic-tailwind-SOgrb2qc.js.map} +1 -1
- package/dist/utils/tailwind/index.js +27 -1
- package/dist/{tailwind-CbjdLyVX.js.map → utils/tailwind/index.js.map} +1 -1
- package/package.json +2 -2
- package/dist/preview-DKyKKcu7.js.map +0 -1
- package/dist/tailwind-CbjdLyVX.js +0 -28
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { a as compile, u as getCachedScriptBlob } from "./utils-BQ7WL7Jh.js";
|
|
2
|
-
import { t as generateTailwindCSSFromDOM } from "./tailwind-CbjdLyVX.js";
|
|
3
2
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
4
3
|
import { jsx } from "react/jsx-runtime";
|
|
5
4
|
import * as ui from "@jbpark/ui-kit";
|
|
@@ -485,7 +484,7 @@ const useDynamicTailwind = (code, enabled) => {
|
|
|
485
484
|
useEffect(() => {
|
|
486
485
|
if (!code || !enabled || !element) return;
|
|
487
486
|
let cancelled = false;
|
|
488
|
-
generateTailwindCSSFromDOM(element).then((next) => {
|
|
487
|
+
import("./utils/tailwind/index.js").then(({ generateTailwindCSSFromDOM }) => generateTailwindCSSFromDOM(element)).then((next) => {
|
|
489
488
|
if (!cancelled) setCss(next);
|
|
490
489
|
});
|
|
491
490
|
return () => {
|
|
@@ -504,4 +503,4 @@ const useDynamicTailwind = (code, enabled) => {
|
|
|
504
503
|
//#endregion
|
|
505
504
|
export { Frame as i, useCompiledModule as n, baseModules as r, useDynamicTailwind as t };
|
|
506
505
|
|
|
507
|
-
//# sourceMappingURL=use-dynamic-tailwind-
|
|
506
|
+
//# sourceMappingURL=use-dynamic-tailwind-SOgrb2qc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-dynamic-tailwind-BF8TQ3Yy.js","names":[],"sources":["../src/components/frame/measure.ts","../src/components/frame/style-sync.ts","../src/components/frame/viewport-units.ts","../src/components/frame/iframe.tsx","../src/components/frame/shadow.tsx","../src/components/frame/frame.tsx","../src/components/preview/base-modules.ts","../src/components/preview/use-compiled-module.ts","../src/components/preview/use-dynamic-tailwind.ts"],"sourcesContent":["// Pure helpers behind iframe.tsx's autoHeight measurement (#132 stages\n// 2-3) — kept DOM-free so they're testable under this repo's node-\n// environment vitest setup; the DOM walking itself (getComputedStyle,\n// querySelectorAll, offsetHeight reads) has no real layout engine to run\n// against outside a real browser and stays in iframe.tsx, verified\n// separately with a real Chromium instance instead of a unit test.\n\n// A fallback used only when there's no `[data-frame-container]` scroll\n// container to measure against at all — e.g. `Frame` used directly by a\n// library consumer, without `Dnd`. There's no better reference height to\n// wait for in that case (unlike the \"container exists but hasn't laid out\n// yet\" case below, which defers instead), so this just needs to be *some*\n// reasonable default. Matches the source fork's own constant — a common\n// mobile viewport height, chosen there for the same reason.\nexport const FALLBACK_PROBE_HEIGHT = 812;\n\n// The reference height for the preview's CSS containment context (see\n// ensureContainerStyle in iframe.tsx) — everything sized in `vh`-family\n// units (converted to `cqh` by convertViewportUnits) resolves against\n// this instead of the iframe's own height, which is what breaks the old\n// approach's fold-to-0px-then-measure circularity (#132 problem 1).\n//\n// `clientHeight` already excludes the scroll container's own border, but\n// not any padding/border on wrapper elements *between* the iframe and\n// that container (this codebase's own Sortable/Renderer/Frame don't add\n// any today, but a consumer's own `provider` or custom-panel wrapper\n// could) — `wrapperInsets` is the sum of those, added up by the caller\n// while walking from the iframe to the scroll container.\n//\n// Returns `null` (not a guessed fallback) when the container hasn't been\n// laid out yet (`clientHeight` still 0, e.g. mid-transition) — the\n// caller should skip this measurement pass rather than settle on a\n// number that has nothing to do with the actual available space and\n// that no future event would ever correct (see the issue's own\n// reasoning for why a `window.innerHeight` fallback here was wrong).\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// `visibility:hidden` and `opacity:0` elements keep a non-zero\n// offsetHeight/scrollHeight (unlike `display:none`, which zeroes them\n// out on its own) — without this check, a closed bottom sheet or a\n// not-yet-faded-in overlay sitting in the DOM inflates the measured\n// height by however tall it would be if shown.\n//\n// `opacity:0` on its own can't separate that closed overlay from the\n// *first frames of a fade-in*, which is on its way to being visible and\n// belongs in the height (#374). `isAnimating` is how the caller resolves\n// it: an element part-way through a keyframe animation is measured even\n// while fully transparent. It deliberately doesn't rescue\n// `visibility:hidden` — an element animating some unrelated property\n// while hidden is still hidden.\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// Which `Animation.playState`s mean \"this element's appearance is still\n// in flight, don't trust the current frame as its resting state\".\n//\n// `playState !== 'idle'` would be the tempting shorthand and is wrong:\n// a *finished* fade-out with `animation-fill-mode: forwards` sits in\n// `finished` while holding `opacity: 0`, and that element really is\n// hidden for good — counting it as animating would put the full height\n// of a dismissed overlay back into the estimate. `paused` counts because\n// a paused fade-in is stopped part-way through, not dismissed.\nexport const isAnimationActive = (playState: string): boolean =>\n playState === 'running' || playState === 'paused';\n\n// `translate(Xpx, Ypx)` / `translateY(Ypx)` / `matrix(a,b,c,d,tx,ty)`'s Y\n// component — a positioned popup/overlay is commonly offset this way\n// (Radix/floating-ui do), so its *effective* bottom edge is `offsetY +\n// offsetHeight` from its positioned ancestor, not just `offsetHeight`\n// alone. Returns 0 for anything else (no transform, or an X-only/\n// unrecognized one) rather than throwing — an unparsed offset is safer\n// treated as \"no extra offset\" than as a measurement failure.\n//\n// iframe.tsx's only caller passes `getComputedStyle(el).transform`, which\n// every real browser normalizes to `matrix(...)` regardless of what\n// syntax (translate/translateY/none of the above) the original CSS used\n// — confirmed against a real Chromium instance, not assumed. The\n// translate()/translateY() branches mainly document intent and cover any\n// future caller that passes an *inline* style's transform instead (which\n// does preserve the author's original syntax).\nexport const parseTranslateY = (transform: string): number => {\n if (!transform || transform === 'none') {\n return 0;\n }\n\n // translateY(y) is single-argument — tried first and separately from\n // translate(x, y), since a naive \"match the arg after a comma\" pattern\n // has no comma to find here at all and would silently fall through to 0.\n const translateYMatch = transform.match(/translateY\\(\\s*([+-]?\\d*\\.?\\d+)/);\n\n if (translateYMatch?.[1]) {\n return parseFloat(translateYMatch[1]);\n }\n\n const translateMatch = transform.match(\n /translate\\([^,]+,\\s*([+-]?\\d*\\.?\\d+)/,\n );\n\n if (translateMatch?.[1]) {\n return parseFloat(translateMatch[1]);\n }\n\n const matrixMatch = transform.match(\n /matrix\\(\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*([+-]?\\d*\\.?\\d+)/,\n );\n\n return matrixMatch?.[1] ? parseFloat(matrixMatch[1]) : 0;\n};\n\n// A `position:fixed`/`absolute` element is placed relative to the\n// viewport (or the nearest positioned ancestor, which for this preview\n// content is effectively the same scale) — `offsetY + offsetHeight` can\n// legitimately exceed the probe height (e.g. an element deliberately\n// positioned to bleed off-screen), but letting an unbounded value drive\n// the *whole document's* measured height would make one runaway overlay\n// balloon everything below it. Capping at `probeHeight` treats \"this\n// element's bottom edge is somewhere past the viewport\" the same as \"at\n// the viewport edge\" for sizing purposes, without needing to know how far\n// past.\nexport const estimatePositionedElementHeight = (\n offsetHeight: number,\n transform: string,\n probeHeight: number,\n): number => {\n const offsetY = parseTranslateY(transform);\n\n return Math.min(offsetY + offsetHeight, probeHeight);\n};\n","const SYNCED_STYLE_ATTR = 'data-live-editor-synced-style';\n\ntype SourceStyle = HTMLLinkElement | HTMLStyleElement;\ntype SyncedStyle = HTMLLinkElement | HTMLStyleElement;\n\nexport interface StyleSyncManager {\n clones: Map<SourceStyle, SyncedStyle>;\n}\n\nexport const createStyleSyncManager = (): StyleSyncManager => ({\n clones: new Map(),\n});\n\nconst isDocument = (target: Document | ShadowRoot): target is Document =>\n target.nodeType === Node.DOCUMENT_NODE;\n\nconst sourceStyles = (document: Document): SourceStyle[] =>\n Array.from(\n document.head.querySelectorAll<HTMLLinkElement | HTMLStyleElement>(\n 'link[rel=\"stylesheet\"], style',\n ),\n );\n\nconst copyAttributes = (\n source: SourceStyle,\n clone: SyncedStyle,\n transformStyle: (content: string) => string,\n) => {\n Array.from(clone.attributes).forEach(attribute => {\n if (\n attribute.name !== SYNCED_STYLE_ATTR &&\n !source.hasAttribute(attribute.name)\n ) {\n clone.removeAttribute(attribute.name);\n }\n });\n\n Array.from(source.attributes).forEach(attribute => {\n clone.setAttribute(attribute.name, attribute.value);\n });\n\n if (source.tagName === 'LINK' && clone.tagName === 'LINK') {\n (clone as HTMLLinkElement).disabled = (source as HTMLLinkElement).disabled;\n }\n\n clone.textContent =\n source.tagName === 'STYLE'\n ? transformStyle(source.textContent || '')\n : source.textContent;\n};\n\nconst createClone = (\n source: SourceStyle,\n target: Document | ShadowRoot,\n transformStyle: (content: string) => string,\n): SyncedStyle => {\n const ownerDocument = isDocument(target) ? target : target.ownerDocument;\n const clone = ownerDocument.createElement(\n source.tagName.toLowerCase(),\n ) as SyncedStyle;\n\n clone.setAttribute(SYNCED_STYLE_ATTR, '');\n copyAttributes(source, clone, transformStyle);\n\n return clone;\n};\n\nconst targetContainer = (target: Document | ShadowRoot) =>\n isDocument(target) ? target.head : target;\n\nconst isSyncedStyle = (node: Node): node is SyncedStyle => {\n const element = node as Element;\n\n return (\n (element.tagName === 'LINK' || element.tagName === 'STYLE') &&\n element.hasAttribute(SYNCED_STYLE_ATTR)\n );\n};\n\nconst removeClone = (clone: SyncedStyle) => {\n clone.remove();\n};\n\nexport const reconcileStyles = (\n sourceDocument: Document,\n target: Document | ShadowRoot,\n manager: StyleSyncManager,\n enabled: boolean,\n transformStyle: (content: string) => string = content => content,\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) ?? null);\n\n if (clone !== nextSibling) {\n container.insertBefore(clone, nextSibling);\n }\n\n previous = clone;\n });\n};\n","// Part of #132 stage 1 — porting the internal GitLab fork's autoHeight\n// height-measurement redesign into this repo, one verifiable stage at a\n// time (see the issue for the full plan and why the current `updateHeight`\n// implementation needs replacing: folding the iframe to 0px before\n// measuring permanently collapses `vh`-sized content to 0, since `vh`\n// units resolve against the iframe's own height).\n//\n// The fork's fix replaces the iframe height as `vh`'s reference point with\n// a fixed-size CSS containment context (`html { container-type: size;\n// height: <probe>px }`) — see stage 2. That only works if the document's\n// own `vh`/`svh`/`lvh`/`dvh`/`vmin`/`vmax` usages are first rewritten to\n// the matching container-query unit (`cqh`/`cqmin`/`cqmax`), since a size\n// container doesn't retroactively change what `vh` itself resolves\n// against. `vw`/`vi` are deliberately left alone: they resolve against\n// width, which this measurement never touches, so rewriting them would\n// only add risk with no corresponding bug to fix.\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// Requires the matched number not to be immediately preceded by a letter,\n// digit, underscore, `.`, or `-` — this is what keeps `url(a5vh.png)`,\n// `.a5vh{}`, and `.hero-100vh{}` untouched (in all three, the digits\n// before `vh` are part of a larger filename/class-name token, not a\n// standalone CSS number) without needing any special-casing for\n// `url(...)`/selectors specifically. `-` has to be excluded too, not just\n// `\\w`/`.`, since a kebab-case identifier like `hero-100vh` uses it as a\n// word separator the same way `a5vh` uses no separator at all — otherwise\n// the number pattern's own optional leading `-?` would happily treat that\n// hyphen as a negative sign instead. This doesn't break real negative\n// values (`margin-top: -10vh`): there the character *before* the `-` is\n// whatever precedes the whole declaration (a space, in practice), so the\n// lookbehind still passes and the leading `-` is captured as part of the\n// number, same as before.\n//\n// Separately, `--my-vh: 10px` was never a candidate to begin with: there's\n// no digit immediately before `vh` there at all (the `y` in `-vh` is a\n// letter, not a number), so the pattern doesn't even try to match it.\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/vmax to their cqh/cqmin/cqmax equivalent\n// wherever they appear as an actual CSS dimension — including nested\n// inside calc()/var() fallbacks, since this is a plain text substitution\n// rather than a CSS-aware parse. `vw` is left as-is (see UNIT_MAP above).\n//\n// Known limitation, inherited from the source fork and not fixed here:\n// this can't distinguish a real dimension from the same text sitting\n// inside a CSS string literal, e.g. `content: \"100vh\"` — the regex has no\n// concept of quoting, so that string's contents get rewritten too. In\n// practice this is rare (a `content` value that's coincidentally shaped\n// like a viewport dimension) and doesn't affect layout, since `content`\n// strings aren't parsed as CSS values.\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// `convertViewportUnits` only ever runs over CSS *text* that this component\n// controls the injection of — the parent-document `<style>` copies (syncStyle)\n// and the `styles` prop (see iframe.tsx). Two paths carry a viewport unit into\n// the preview document without passing through either, so the container-context\n// fix (#132) never reaches them and their `vh` still resolves against the\n// iframe's own height — re-creating the exact circularity #132 removed:\n//\n// 1. inline `style` attributes — the visual editor's panel edits produce\n// these, so they're a common path here, not an edge case; and\n// 2. author `<style>` elements rendered *inside* the previewed component by\n// React, which never pass through `applyStyle`/`styles`.\n//\n// This rewrites both in place, walking only nodes that could carry a match so\n// the pass stays cheap. It's meant to be called from `updateHeight` right after\n// the container style is (re)applied and before any height is read.\n//\n// Idempotent, and specifically non-perturbing once converted: a rewritten value\n// contains `cqh`/`cqmin`/`cqmax`, none of which match the `vh`/`vmin`/`vmax`\n// attribute selectors, so a second pass re-selects nothing; and each node is\n// written back only when its text actually changed, so an already-converted\n// document isn't mutated — which matters because the write itself would\n// otherwise re-trip the MutationObserver in iframe.tsx and loop.\nexport const rewriteInlineViewportUnits = (root: HTMLElement): void => {\n // `vh` as a substring already covers `svh`/`lvh`/`dvh`; `vmin`/`vmax` need\n // their own terms. Case-insensitive so `100VH` inline is caught too.\n const inlineTargets = root.querySelectorAll<HTMLElement>(\n '[style*=\"vh\" i], [style*=\"vmin\" i], [style*=\"vmax\" i]',\n );\n\n inlineTargets.forEach(el => {\n const current = el.getAttribute('style');\n\n if (current == null) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n el.setAttribute('style', converted);\n }\n });\n\n root.querySelectorAll<HTMLStyleElement>('style').forEach(styleEl => {\n const current = styleEl.textContent;\n\n if (!current) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n styleEl.textContent = converted;\n }\n });\n};\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n useEventListener,\n useMutationObserver,\n useResizeObserver,\n} from '@jbpark/use-hooks';\n\nimport { getCachedScriptBlob } from '~/utils';\n\nimport {\n FALLBACK_PROBE_HEIGHT,\n computeProbeHeight,\n estimatePositionedElementHeight,\n isAnimationActive,\n isVisuallyHidden,\n} from './measure';\nimport { createStyleSyncManager, reconcileStyles } from './style-sync';\nimport {\n convertViewportUnits,\n rewriteInlineViewportUnits,\n} from './viewport-units';\n\nexport interface Props {\n title?: string;\n /** Forwarded to the iframe's `sandbox` attribute for DOM/CSS isolation only — not a security boundary, since preview code executes in the host window's realm (see `compileModule` in `~/utils`). */\n sandbox?: string;\n style?: React.CSSProperties;\n scripts?: string[];\n styles?: string[];\n stylesheets?: string[];\n autoHeight?: boolean;\n syncStyle?: boolean;\n children: (container: HTMLElement) => ReactNode;\n onLoaded?: () => void;\n}\n\nconst EMPTY_STRING_ARRAY: string[] = [];\n\n// `getAnimations()` returns three kinds of animation mixed together:\n// CSSAnimation (a @keyframes rule), CSSTransition (a `transition`) and\n// plain Animation (`element.animate()`). They need telling apart below\n// because only the first two announce their own completion through a\n// bubbling DOM event. Both constructors are feature-detected rather than\n// assumed: jsdom exposes neither.\nconst isCssAnimation = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSAnimation === 'function' &&\n animation instanceof win.CSSAnimation;\n\nconst isCssTransition = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSTransition === 'function' &&\n animation instanceof win.CSSTransition;\n\n// Whether this element's look is still in flight, which is what tells a\n// transient `opacity: 0` (the first frames of a fade-in — measure it)\n// from a permanent one (a closed overlay — skip it).\n//\n// Transitions count here, unlike keyframe animations they are not\n// distinguished: now that a measurement pass only freezes transitions when\n// it moves the probe height (see withMeasurementOverrides), an element at\n// the very start of a fade-*in* transition genuinely reads `opacity: 0`\n// with a running transition and has to be measured. An element fading\n// *out* needs no special case — part-way through it reads a fractional\n// opacity, so it is measured for as long as it is still visible, and once\n// the transition is over it reads `0` with nothing running and drops out.\n//\n// getAnimations() is feature-detected: jsdom and pre-2020 browsers don't\n// implement it, and without it this returns false, which is the safe\n// direction (under-measuring a fading-in overlay rather than inflating a\n// section by the height of a dismissed one).\nconst hasActiveAnimation = (el: HTMLElement): boolean =>\n typeof el.getAnimations === 'function' &&\n el.getAnimations().some(animation => isAnimationActive(animation.playState));\n\n// `finished` never resolves for an animation that repeats forever, so a\n// handler attached to one would only pin its closure for as long as the\n// element lives. No signal is lost by skipping it: such an element is\n// perpetually \"animating\", so hasActiveAnimation keeps it in the estimate\n// on every pass anyway.\nconst neverFinishes = (animation: Animation): boolean => {\n const timing = animation.effect?.getComputedTiming();\n\n return timing?.iterations === Infinity || timing?.duration === Infinity;\n};\n\n// A second, separate style — inert (`media=\"not all\"`) except for the\n// brief window updateHeight actually measures in, toggled on right\n// before and off right after (#132 stage 4). Two things it guards\n// against:\n//\n// - transitions: if any rule in the preview (or a browser default)\n// gives `html`/an ancestor a `transition` on a property this\n// measurement touches, changing ensureContainerStyle's `height` would\n// animate instead of applying instantly, and a read taken right after\n// would catch a mid-transition value instead of the settled one. Only\n// applied on a pass that actually changes the probe height — see\n// `freezeTransitions`.\n// - scrollbar chrome: applying a new probe height can make a scrollbar\n// appear/disappear for exactly this measurement pass; on platforms\n// where it takes up layout width (Windows, unlike macOS's overlay\n// scrollbars), that narrows content and skews the height reading.\n// `scrollbar-width: none`/`::-webkit-scrollbar { display: none }`\n// only hides the *chrome* — unlike `overflow: hidden`, scrolling\n// itself still works, so content that ends up taller than its probe\n// height is still reachable rather than silently clipped.\n//\n// A single style element (not two, and never added/removed) so\n// toggling it can't itself trip the MutationObserver watching for\n// *content* changes.\nconst MEASUREMENT_OVERRIDE_STYLE_ID = 'autoheight-measurement-overrides';\n\nconst SCROLLBAR_OVERRIDE_RULES = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n];\n\nconst FREEZE_TRANSITIONS_RULE =\n '*, *::before, *::after { transition: none !important; }';\n\n// `freezeTransitions` is deliberately not always on. `transition: none`\n// does not pause a transition for the duration of the measurement — it\n// *cancels* it, and lifting the override afterwards does not resume it.\n// Measured in Chromium: 0.5s into a 4s fade the element read `0.974`\n// with one running animation; inside the override window it read `0`\n// with none, and it was still `0` with none 0.8s after the override came\n// back off. The element had snapped to its end state for good.\n//\n// Freezing on every pass therefore killed every transition in the\n// preview that happened to overlap a measurement — and because a DOM\n// mutation is what both triggers a measurement and typically starts a\n// transition (a class toggle opening an overlay), that was most of them.\n//\n// The guard is only needed for what the measurement *itself* changes:\n// the probe height, and with it any `cq*`-unit descendant sized against\n// it. When the probe height is unchanged from the last pass, the pass\n// changes nothing, so there is nothing to freeze and the preview's own\n// transitions are left alone.\nconst withMeasurementOverrides = (\n doc: Document,\n freezeTransitions: boolean,\n measure: () => void,\n) => {\n let styleEl = doc.getElementById(\n MEASUREMENT_OVERRIDE_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = MEASUREMENT_OVERRIDE_STYLE_ID;\n styleEl.media = 'not all';\n doc.head?.appendChild(styleEl);\n }\n\n const text = (\n freezeTransitions\n ? [FREEZE_TRANSITIONS_RULE, ...SCROLLBAR_OVERRIDE_RULES]\n : SCROLLBAR_OVERRIDE_RULES\n ).join('\\n');\n\n if (styleEl.textContent !== text) {\n styleEl.textContent = text;\n }\n\n styleEl.media = 'all';\n measure();\n styleEl.media = 'not all';\n};\n\nconst IFrame = ({\n title = 'Live Preview',\n sandbox,\n style = {},\n scripts = EMPTY_STRING_ARRAY,\n styles = EMPTY_STRING_ARRAY,\n stylesheets = EMPTY_STRING_ARRAY,\n autoHeight = false,\n syncStyle = false,\n children,\n onLoaded,\n ...props\n}: Props) => {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const [mountNode, setMountNode] = useState<HTMLElement | null>(null);\n // Tracks which script srcs have already been injected into this iframe's\n // document, keyed by src rather than a single loaded/not-loaded boolean —\n // a boolean latched to `true` forever meant a later change to `scripts`\n // (new entries) never got loaded once the first batch had.\n const loadedScriptsRef = useRef<Set<string>>(new Set());\n const prevStyleCountRef = useRef(0);\n const prevStylesheetCountRef = useRef(0);\n // Animations already given a \"re-measure once you settle\" handler, so a\n // long-running one still in flight across many measurement passes only\n // ever gets one (see trackScriptAnimations). Weak so it never keeps a\n // finished animation — or the element owning it — alive.\n const trackedAnimationsRef = useRef(new WeakSet<Animation>());\n // Lets those handlers call back into the *current* updateHeight without\n // updateHeight having to list itself as its own dependency.\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 about the document, which is what\n // lets that pass measure without freezing the preview's transitions.\n const lastProbeHeightRef = useRef<number | undefined>(undefined);\n const shouldAutoHeight = autoHeight && style.height == null;\n\n const styleManagerRef = useRef(createStyleSyncManager());\n\n const applyStyle = useCallback(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc) {\n return;\n }\n\n reconcileStyles(\n document,\n doc,\n styleManagerRef.current,\n syncStyle,\n convertViewportUnits,\n );\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced so a burst of head mutations (a stylesheet swap can fire\n // several in quick succession) only re-runs applyStyle once, matching the\n // original raw-MutationObserver setup's 50ms debounce.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n 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 doc.body.style.overflowX = 'hidden';\n doc.body.style.margin = '0';\n\n let node = doc.getElementById('iframe-root');\n\n if (!node) {\n node = doc.createElement('div');\n node.id = 'iframe-root';\n doc.body.appendChild(node);\n }\n\n setMountNode(node);\n\n applyStyle();\n\n const pendingScripts = scripts.filter(\n src => !loadedScriptsRef.current.has(src),\n );\n\n if (pendingScripts.length) {\n pendingScripts.forEach(src => loadedScriptsRef.current.add(src));\n\n Promise.all(pendingScripts.map(getCachedScriptBlob)).then(blobUrls => {\n if (!doc.head) {\n return;\n }\n\n const fragment = doc.createDocumentFragment();\n blobUrls.forEach(blobUrl => {\n const script = doc.createElement('script');\n script.src = blobUrl;\n fragment.appendChild(script);\n });\n doc.head.appendChild(fragment);\n });\n }\n\n onLoaded?.();\n };\n\n $iframe.addEventListener('load', onLoad);\n\n if ($iframe.contentDocument?.readyState === 'complete') {\n onLoad();\n }\n\n return () => {\n $iframe.removeEventListener('load', onLoad);\n };\n }, [scripts, onLoaded, applyStyle]);\n\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n styles.forEach((css, index) => {\n const styleId = `injected-style-${index}`;\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = styleId;\n doc.head.appendChild(styleEl);\n }\n\n // The primary source of vh/svh/etc in a real preview — compiled\n // component CSS (e.g. Tailwind's `h-screen` -> `height: 100vh`).\n // See ensureContainerStyle below for why this needs converting.\n const convertedCss = convertViewportUnits(css);\n\n if (styleEl.textContent !== convertedCss) {\n styleEl.textContent = convertedCss;\n }\n });\n\n // Indices beyond the current array's length are stale from a previous,\n // longer `styles`/`stylesheets` — the loops above only add/update up to\n // the current length, so anything past it (from before an item was\n // removed, or the array shrank) would otherwise stay injected forever.\n for (\n let index = styles.length;\n index < prevStyleCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-style-${index}`)?.remove();\n }\n prevStyleCountRef.current = styles.length;\n\n stylesheets.forEach((href, index) => {\n const linkId = `injected-stylesheet-${index}`;\n let linkEl = doc.getElementById(linkId) as HTMLLinkElement | null;\n\n if (!linkEl) {\n linkEl = doc.createElement('link');\n linkEl.id = linkId;\n linkEl.rel = 'stylesheet';\n doc.head.appendChild(linkEl);\n }\n\n if (linkEl.href !== href) {\n linkEl.href = href;\n }\n });\n\n for (\n let index = stylesheets.length;\n index < prevStylesheetCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-stylesheet-${index}`)?.remove();\n }\n prevStylesheetCountRef.current = stylesheets.length;\n }, [styles, stylesheets]);\n\n // The <html> element's own container-context style — id'd so it can be\n // found/updated/removed across calls without holding a ref to it. Scoped\n // to `html` (not `:root`, which is equivalent but the fork's own\n // convention) so this only ever affects cq*-unit resolution and nothing\n // else about the document.\n const CONTAINER_STYLE_ID = 'autoheight-container';\n\n // Permanently hides the iframe document's own scrollbar chrome while\n // autoHeight is sizing the iframe to its content. autoHeight sets the\n // iframe's height to `Math.ceil(contentHeight)`, so sub-pixel content or\n // a rounding remainder can leave the inner document a fraction taller\n // than its viewport — enough for the browser to draw a vertical\n // scrollbar inside every section's iframe (visual noise once several Dnd\n // sections stack). Unlike the measurement-only override above (toggled\n // off after each read), this one stays on: `scrollbar-width`/\n // `::-webkit-scrollbar` hide only the *chrome*, not scrolling itself, so\n // content that ever genuinely exceeds the measured height is still\n // reachable by wheel/keyboard rather than clipped.\n const HIDE_SCROLLBAR_STYLE_ID = 'autoheight-hide-scrollbar';\n\n // Ties `cqh`/`cqmin`/`cqmax` (what convertViewportUnits rewrote every\n // vh/svh/lvh/dvh/vmin/vmax to) to a *fixed* reference height instead of\n // the iframe's own height — this is what breaks the old approach's\n // circularity (#132 problem 1): folding the iframe to 0px before\n // measuring made vh-sized content resolve to 0 and stay there forever,\n // while measuring without folding never converges (vh content sized\n // against the iframe's own just-grown height keeps growing it further).\n // `container-type: size` requires an explicit height to size against,\n // which `probeHeight` (the *scroll container's* available height, not\n // the iframe's) provides — genuinely independent of whatever height this\n // function goes on to set on the iframe itself.\n const ensureContainerStyle = (doc: Document, probeHeight: number) => {\n let styleEl = doc.getElementById(\n CONTAINER_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = CONTAINER_STYLE_ID;\n doc.head?.appendChild(styleEl);\n }\n\n const text = `html { container-type: size !important; height: ${probeHeight}px !important; }`;\n\n // Only written when it actually differs. Re-assigning identical\n // textContent would tear down and rebuild the same CSSOM rule on every\n // pass, and the whole point of the probe height being stable is that a\n // pass changes nothing about the document (see freezeTransitions).\n if (styleEl.textContent !== text) {\n styleEl.textContent = text;\n }\n };\n\n // Script-driven animations are the blind spot the animationend listeners\n // below can't cover: the Web Animations API fires no DOM event when one\n // ends, so nothing would re-run a measurement taken mid-fade. Their\n // `finished` promise is the equivalent signal, so each gets exactly one\n // re-measure scheduled for when it settles.\n //\n // CSS animations and transitions are both skipped: their\n // `animationend`/`transitionend` already bubble to the mount node, so\n // tracking them here too would only measure twice.\n //\n // A cancelled animation rejects `finished` with an AbortError and snaps\n // the element back to its un-animated style, which is as much a reason to\n // re-measure as a clean finish — hence one handler on both settle paths.\n const trackScriptAnimations = useCallback(\n (doc: Document, win: Window & typeof globalThis) => {\n if (typeof doc.getAnimations !== 'function') {\n return;\n }\n\n doc.getAnimations().forEach(animation => {\n if (\n trackedAnimationsRef.current.has(animation) ||\n !isAnimationActive(animation.playState) ||\n isCssAnimation(win, animation) ||\n isCssTransition(win, animation) ||\n neverFinishes(animation)\n ) {\n return;\n }\n\n trackedAnimationsRef.current.add(animation);\n\n animation.finished\n .catch(() => undefined)\n .then(() => updateHeightRef.current?.());\n });\n },\n [],\n );\n\n // Not ported from #132 stage 4: a \"settled scrollHeight + settled probe\n // height both unchanged -> skip\" guard, meant to avoid redundant re-runs\n // from updateHeight's own `iframe.style.height` write looping back\n // through the ResizeObserver below (a real path — the iframe's own box\n // size determines its *internal* viewport size, so this can genuinely\n // fire again). Left out deliberately: `scrollHeight` only reflects\n // normal document flow, but a position:fixed/absolute overlay opening or\n // closing (its whole reason for needing the full-subtree walk above)\n // often doesn't touch `scrollHeight` at all. A guard keyed on it would\n // silently skip exactly the kind of update stage 3 exists to catch —\n // reintroducing a narrower version of the bug this file just fixed\n // would be a worse trade than the redundant-recompute cost it'd save.\n const updateHeight = useCallback(() => {\n if (!shouldAutoHeight || !mountNode || !iframeRef.current) {\n return;\n }\n\n const iframe = iframeRef.current;\n const doc = iframe.contentDocument;\n const win = doc?.defaultView;\n\n if (!doc || !win) {\n return;\n }\n\n const scrollParent = iframe.closest<HTMLElement>('[data-frame-container]');\n\n let probeHeight: number;\n\n if (!scrollParent) {\n // No scroll container anywhere in the tree (Frame used directly,\n // without Dnd) — fall back to a fixed default; see\n // FALLBACK_PROBE_HEIGHT's own comment for why this differs from\n // the \"container exists but isn't laid out yet\" case below.\n probeHeight = FALLBACK_PROBE_HEIGHT;\n } else {\n let wrapperInsets = 0;\n let node = iframe.parentElement;\n\n while (node && node !== scrollParent) {\n const style = win.getComputedStyle(node);\n\n wrapperInsets +=\n parseFloat(style.borderTopWidth) +\n parseFloat(style.borderBottomWidth) +\n parseFloat(style.paddingTop) +\n parseFloat(style.paddingBottom);\n\n node = node.parentElement;\n }\n\n const computed = computeProbeHeight(\n scrollParent.clientHeight,\n wrapperInsets,\n );\n\n if (computed === null) {\n // Layout not ready yet (mid-transition, just mounted, etc) —\n // skip this pass instead of guessing; the ResizeObserver/\n // MutationObserver below will call this again once something\n // actually changes, including the layout settling.\n return;\n }\n\n probeHeight = computed;\n }\n\n let contentHeight = 0;\n\n // First pass (`undefined`) and any pass that moves the probe height are\n // the only ones that change the container context, so they are the only\n // ones that need the preview's transitions out of the way.\n const freezeTransitions = probeHeight !== lastProbeHeightRef.current;\n\n lastProbeHeightRef.current = probeHeight;\n\n withMeasurementOverrides(doc, freezeTransitions, () => {\n ensureContainerStyle(doc, probeHeight);\n\n // Rewrite vh-family units the container context can't otherwise reach —\n // inline `style` attributes and in-preview `<style>` tags — so they too\n // resolve against the fixed probe height rather than the iframe's own\n // (see rewriteInlineViewportUnits). Must run after ensureContainerStyle\n // and before the reads below; it's idempotent, so the extra observer\n // pass its first-render rewrites trigger converges immediately.\n rewriteInlineViewportUnits(mountNode);\n\n // No 0px fold before measuring (that was the source of problem 1)\n // — with cq*-unit content now sized against the fixed probe height\n // instead of the iframe's own, a direct read is already stable.\n contentHeight = mountNode.scrollHeight;\n\n // Full subtree, not just direct children (a popup/overlay nested a\n // few components deep was previously invisible to this walk\n // entirely — problem 2's \"중첩된 오버레이는 아예 누락됩니다\").\n const descendants = mountNode.querySelectorAll<HTMLElement>('*');\n\n descendants.forEach(el => {\n const style = win.getComputedStyle(el);\n\n // visibility:hidden/opacity:0 elements (a closed bottom sheet,\n // a not-yet-faded-in overlay) keep a non-zero offsetHeight —\n // display:none doesn't need checking here since the browser\n // already zeroes *its* offsetHeight on its own.\n //\n // The animation lookup is confined to the one verdict it can\n // change — whether a fully transparent element is fading in\n // (measure it) or simply not shown (skip it) — so every other\n // element still costs nothing but the computed-style read.\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 estimatedHeight = estimatePositionedElementHeight(\n el.offsetHeight,\n style.transform,\n probeHeight,\n );\n\n contentHeight = Math.max(contentHeight, estimatedHeight);\n }\n });\n });\n\n if (contentHeight > 0) {\n iframe.style.height = `${Math.ceil(contentHeight)}px`;\n }\n\n // Outside the measurement window on purpose: the overrides above cancel\n // running transitions, and this read should see the document's real\n // animation set rather than one the act of measuring just altered.\n trackScriptAnimations(doc, win);\n }, [shouldAutoHeight, mountNode, trackScriptAnimations]);\n\n useEffect(() => {\n updateHeightRef.current = updateHeight;\n }, [updateHeight]);\n\n // updateHeight only ever adds/refreshes the container-context style —\n // if autoHeight is toggled off (or an explicit style.height is passed)\n // at runtime, nothing else would ever remove or update it again,\n // leaving cq*-unit content sized against a stale probe height instead\n // of correctly falling back to real viewport-relative sizing (which\n // cqh does on its own once nothing establishes a size container — see\n // ensureContainerStyle's own comment).\n useEffect(() => {\n if (shouldAutoHeight) {\n return;\n }\n\n iframeRef.current?.contentDocument\n ?.getElementById(CONTAINER_STYLE_ID)\n ?.remove();\n }, [shouldAutoHeight]);\n\n // Keyed on mountNode (not just shouldAutoHeight) so it re-runs once the\n // iframe's document exists — before load there's no head to inject into.\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n const existing = doc.getElementById(HIDE_SCROLLBAR_STYLE_ID);\n\n if (!shouldAutoHeight) {\n existing?.remove();\n return;\n }\n\n if (existing) {\n return;\n }\n\n const styleEl = doc.createElement('style');\n styleEl.id = HIDE_SCROLLBAR_STYLE_ID;\n styleEl.textContent = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n ].join('\\n');\n doc.head.appendChild(styleEl);\n }, [shouldAutoHeight, mountNode]);\n\n useEffect(() => {\n updateHeight();\n }, [updateHeight]);\n\n const [resizeRef, resizeSize] = useResizeObserver<HTMLElement>();\n\n // useResizeObserver's ref callback isn't wired through this component's\n // own JSX (mountNode is the portal's imperatively-created container, not\n // something rendered here), so it's attached/detached imperatively\n // instead. Its reported size is intentionally unused - updateHeight's own\n // walk (every descendant, position:fixed/absolute ones capped and offset\n // by their transform) computes a more accurate height than mountNode's\n // own content-box size would, so a change in `resizeSize` is only used\n // as a trigger to recompute.\n useEffect(() => {\n if (!shouldAutoHeight || !mountNode) {\n return;\n }\n\n resizeRef(mountNode);\n return () => resizeRef(null);\n }, [shouldAutoHeight, mountNode, resizeRef]);\n\n useEffect(() => {\n updateHeight();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resizeSize]);\n\n useMutationObserver(mountNode, updateHeight, {\n enabled: shouldAutoHeight,\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n });\n\n // An animation or transition finishing is neither a DOM mutation nor a\n // resize of the mount node, so neither observer above re-runs the\n // measurement — a fixed/absolute element read mid-fade would keep its\n // stale height on the iframe until something unrelated happened to the DOM\n // (#374). All four events bubble, so a single listener each on the mount\n // node covers every descendant.\n //\n // The `cancel` events count as much as the `end` ones: a cancelled\n // animation or transition snaps the element back to its un-animated style,\n // changing the height just the same.\n //\n // `transitionend`/`transitioncancel` used to be unnecessary, because every\n // measurement pass cancelled every transition outright. Now that a pass\n // only freezes transitions when it moves the probe height, a transition\n // can genuinely still be running when a pass reads it, so its completion\n // needs the same re-measure a keyframe animation's does.\n //\n // useEventListener resolves an element target through a ref, so mountNode\n // (portal-owned state, not something this component renders) is wrapped in\n // one that changes identity only when the node itself does. `enabled`\n // keeps it from polling for a node that isn't there yet.\n const mountNodeRef = useMemo(() => ({ current: mountNode }), [mountNode]);\n const settleListenerEnabled = shouldAutoHeight && mountNode !== null;\n\n useEventListener('animationend', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('animationcancel', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('transitionend', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('transitioncancel', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n const content = mountNode\n ? createPortal(children(mountNode), mountNode)\n : null;\n\n return (\n <iframe\n ref={iframeRef}\n style={{\n width: '100%',\n height: '100%',\n border: 'none',\n ...style,\n }}\n title={title}\n sandbox={sandbox}\n {...props}\n >\n {content}\n </iframe>\n );\n};\n\nexport default IFrame;\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useMutationObserver } from '@jbpark/use-hooks';\n\nimport { createStyleSyncManager, reconcileStyles } from './style-sync';\n\ninterface Props {\n // Clones the host document's <link rel=\"stylesheet\">/<style> tags into the\n // shadow root, mirroring `iframe.tsx`'s option of the same name. Unlike\n // `dynamicTailwind` (which recompiles only the classes it can find in the\n // rendered DOM, and only knows Tailwind's own default theme), this gets\n // the host's *actual* compiled CSS — including a consuming app's own\n // custom utilities/theme tokens — at the cost of only covering classes\n // that were already known at the host's own build time. The two are\n // complementary: this handles anything already in the host's stylesheets,\n // dynamicTailwind covers whatever's left (e.g. a class typed at runtime\n // that no build ever saw).\n syncStyle?: boolean;\n children: (hostContainer: HTMLElement | null) => ReactNode;\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 const [hostContainer, setHostContainer] = useState<HTMLElement | null>(null);\n\n // Appended as siblings of the portal target (below), not inside it — that\n // subtree is React-owned via createPortal, and anything appended there\n // directly would get wiped on the next reconcile.\n const styleManagerRef = useRef(createStyleSyncManager());\n\n const applyStyle = useCallback(() => {\n const shadowRoot = shadowRootRef.current;\n\n if (!shadowRoot) {\n return;\n }\n\n reconcileStyles(document, shadowRoot, styleManagerRef.current, syncStyle);\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced so a burst of head mutations (a stylesheet swap can fire\n // several in quick succession) only re-runs applyStyle once — same\n // rationale as iframe.tsx's identical setup.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n useLayoutEffect(() => {\n if (!hostRef.current) {\n return;\n }\n\n const container = hostRef.current.closest(\n '[data-frame-container]',\n ) as HTMLElement | null;\n\n setHostContainer(container);\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 target = document.createElement('div');\n shadowRoot.appendChild(target);\n renderTargetRef.current = target;\n setRenderTarget(target);\n }\n\n applyStyle();\n // click/pointerdown/pointerup are `composed: true` by spec, so they\n // already retarget across the shadow boundary and reach listeners\n // outside it (document, this host's ancestors, React's own root\n // listener) on their own - manually redispatching them here used to\n // make every one of those listeners see the interaction twice. Anyone\n // needing the real element inside the shadow tree (not the retargeted\n // host) can still read it via event.composedPath()[0], unaffected by\n // this removal. See #92.\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 && createPortal(children(hostContainer), renderTarget)}\n </div>\n );\n};\n\nexport default Shadow;\n","import { type ReactNode } from 'react';\n\nimport IFrame, { type Props as IframeProps } from './iframe';\nimport Shadow from './shadow';\n\nexport interface FrameProps extends Omit<IframeProps, 'children'> {\n mode?: 'iframe' | 'shadow';\n}\n\ninterface Props extends FrameProps {\n children: (container: HTMLElement) => ReactNode;\n}\n\nconst Frame = ({ mode, children, ...restProps }: Props) => {\n if (!mode) {\n return children(document.body);\n }\n\n if (mode === 'shadow') {\n return (\n <Shadow syncStyle={restProps.syncStyle}>\n {container => children(container || document.body)}\n </Shadow>\n );\n }\n\n return <IFrame {...restProps}>{children}</IFrame>;\n};\n\nexport default Frame;\n","import * as ui from '@jbpark/ui-kit';\nimport * as utils from '@jbpark/ui-kit/utils';\n\n// The specifiers every compiled sample can import without the host supplying\n// them (`import * as ui from 'ui-kit'`). Lives with the preview, its only\n// consumer, rather than in `~/utils`: evaluating ui-kit's namespace reaches\n// its stylesheet imports, so keeping it there made `@jbpark/live-editor/utils`\n// (and every entry built on it) unimportable outside a bundler — Node, SSR,\n// scripts. See #372.\nexport const baseModules = {\n 'ui-kit': ui,\n 'ui-kit/utils': utils,\n};\n","import { useMemo } from 'react';\n\nimport type { Module } from '~/types';\nimport { compile } from '~/utils';\n\nimport { baseModules } from './base-modules';\n\n// Shared by `preview/client.tsx` and `dnd/renderer.tsx`, which both turn a\n// code string into a renderable component in exactly the same way. They used\n// to implement this separately, which is how the two paths drifted apart on\n// error handling (see #246).\n//\n// Returns `null` for empty code so a caller can tell \"nothing to render\"\n// apart from \"compiled, but failed\" — the latter is a Module carrying\n// `error`, which callers should surface rather than render as blank.\nexport const useCompiledModule = (\n code: string,\n modules?: Record<string, unknown>,\n): Module | null => {\n const mergedModules = useMemo(\n () => ({ ...baseModules, ...modules }),\n [modules],\n );\n\n return useMemo(() => {\n if (!code) {\n return null;\n }\n\n try {\n return compile(code, mergedModules);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\n }, [code, mergedModules]);\n};\n","import { useCallback, useEffect, useState } from 'react';\n\nimport { generateTailwindCSSFromDOM } from '~/utils/tailwind';\n\n// Compiles the Tailwind classes found in rendered output and returns them as\n// a CSS string for the caller to inject as a `<style>` tag. Shared by\n// `preview/client.tsx` and `dnd/renderer.tsx`, which previously carried\n// byte-identical copies of this logic and of the comments below (see #246).\n//\n// Scans the live DOM (whatever the returned `ref` is attached to) rather than\n// the source text it was rendered from, so classes contributed by an imported\n// component (e.g. ui-kit's `Button`) are picked up too — those never appear as\n// literal text in the previewed source, only in that component's own compiled\n// output.\n//\n// The scanned element is tracked as state via a callback ref rather than a\n// plain `useRef`, because in shadow mode it isn't mounted on the caller's\n// first commit at all — `Shadow` creates its portal target in its own effect\n// and only re-renders with it afterwards, one commit later. A plain ref read\n// in a `[code, enabled]`-keyed effect would see `null` on that first pass and\n// never retry; making the element itself a dependency re-runs the scan once\n// it actually exists.\nexport const useDynamicTailwind = (code: string, enabled: boolean) => {\n const [css, setCss] = useState('');\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const ref = useCallback((node: HTMLDivElement | null) => {\n setElement(node);\n }, []);\n\n useEffect(() => {\n if (!code || !enabled || !element) {\n return;\n }\n\n let cancelled = false;\n\n generateTailwindCSSFromDOM(element).then(next => {\n if (!cancelled) {\n setCss(next);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [code, enabled, element]);\n\n return { ref, css };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-dynamic-tailwind-SOgrb2qc.js","names":[],"sources":["../src/components/frame/measure.ts","../src/components/frame/style-sync.ts","../src/components/frame/viewport-units.ts","../src/components/frame/iframe.tsx","../src/components/frame/shadow.tsx","../src/components/frame/frame.tsx","../src/components/preview/base-modules.ts","../src/components/preview/use-compiled-module.ts","../src/components/preview/use-dynamic-tailwind.ts"],"sourcesContent":["// Pure helpers behind iframe.tsx's autoHeight measurement (#132 stages\n// 2-3) — kept DOM-free so they're testable under this repo's node-\n// environment vitest setup; the DOM walking itself (getComputedStyle,\n// querySelectorAll, offsetHeight reads) has no real layout engine to run\n// against outside a real browser and stays in iframe.tsx, verified\n// separately with a real Chromium instance instead of a unit test.\n\n// A fallback used only when there's no `[data-frame-container]` scroll\n// container to measure against at all — e.g. `Frame` used directly by a\n// library consumer, without `Dnd`. There's no better reference height to\n// wait for in that case (unlike the \"container exists but hasn't laid out\n// yet\" case below, which defers instead), so this just needs to be *some*\n// reasonable default. Matches the source fork's own constant — a common\n// mobile viewport height, chosen there for the same reason.\nexport const FALLBACK_PROBE_HEIGHT = 812;\n\n// The reference height for the preview's CSS containment context (see\n// ensureContainerStyle in iframe.tsx) — everything sized in `vh`-family\n// units (converted to `cqh` by convertViewportUnits) resolves against\n// this instead of the iframe's own height, which is what breaks the old\n// approach's fold-to-0px-then-measure circularity (#132 problem 1).\n//\n// `clientHeight` already excludes the scroll container's own border, but\n// not any padding/border on wrapper elements *between* the iframe and\n// that container (this codebase's own Sortable/Renderer/Frame don't add\n// any today, but a consumer's own `provider` or custom-panel wrapper\n// could) — `wrapperInsets` is the sum of those, added up by the caller\n// while walking from the iframe to the scroll container.\n//\n// Returns `null` (not a guessed fallback) when the container hasn't been\n// laid out yet (`clientHeight` still 0, e.g. mid-transition) — the\n// caller should skip this measurement pass rather than settle on a\n// number that has nothing to do with the actual available space and\n// that no future event would ever correct (see the issue's own\n// reasoning for why a `window.innerHeight` fallback here was wrong).\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// `visibility:hidden` and `opacity:0` elements keep a non-zero\n// offsetHeight/scrollHeight (unlike `display:none`, which zeroes them\n// out on its own) — without this check, a closed bottom sheet or a\n// not-yet-faded-in overlay sitting in the DOM inflates the measured\n// height by however tall it would be if shown.\n//\n// `opacity:0` on its own can't separate that closed overlay from the\n// *first frames of a fade-in*, which is on its way to being visible and\n// belongs in the height (#374). `isAnimating` is how the caller resolves\n// it: an element part-way through a keyframe animation is measured even\n// while fully transparent. It deliberately doesn't rescue\n// `visibility:hidden` — an element animating some unrelated property\n// while hidden is still hidden.\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// Which `Animation.playState`s mean \"this element's appearance is still\n// in flight, don't trust the current frame as its resting state\".\n//\n// `playState !== 'idle'` would be the tempting shorthand and is wrong:\n// a *finished* fade-out with `animation-fill-mode: forwards` sits in\n// `finished` while holding `opacity: 0`, and that element really is\n// hidden for good — counting it as animating would put the full height\n// of a dismissed overlay back into the estimate. `paused` counts because\n// a paused fade-in is stopped part-way through, not dismissed.\nexport const isAnimationActive = (playState: string): boolean =>\n playState === 'running' || playState === 'paused';\n\n// `translate(Xpx, Ypx)` / `translateY(Ypx)` / `matrix(a,b,c,d,tx,ty)`'s Y\n// component — a positioned popup/overlay is commonly offset this way\n// (Radix/floating-ui do), so its *effective* bottom edge is `offsetY +\n// offsetHeight` from its positioned ancestor, not just `offsetHeight`\n// alone. Returns 0 for anything else (no transform, or an X-only/\n// unrecognized one) rather than throwing — an unparsed offset is safer\n// treated as \"no extra offset\" than as a measurement failure.\n//\n// iframe.tsx's only caller passes `getComputedStyle(el).transform`, which\n// every real browser normalizes to `matrix(...)` regardless of what\n// syntax (translate/translateY/none of the above) the original CSS used\n// — confirmed against a real Chromium instance, not assumed. The\n// translate()/translateY() branches mainly document intent and cover any\n// future caller that passes an *inline* style's transform instead (which\n// does preserve the author's original syntax).\nexport const parseTranslateY = (transform: string): number => {\n if (!transform || transform === 'none') {\n return 0;\n }\n\n // translateY(y) is single-argument — tried first and separately from\n // translate(x, y), since a naive \"match the arg after a comma\" pattern\n // has no comma to find here at all and would silently fall through to 0.\n const translateYMatch = transform.match(/translateY\\(\\s*([+-]?\\d*\\.?\\d+)/);\n\n if (translateYMatch?.[1]) {\n return parseFloat(translateYMatch[1]);\n }\n\n const translateMatch = transform.match(\n /translate\\([^,]+,\\s*([+-]?\\d*\\.?\\d+)/,\n );\n\n if (translateMatch?.[1]) {\n return parseFloat(translateMatch[1]);\n }\n\n const matrixMatch = transform.match(\n /matrix\\(\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*([+-]?\\d*\\.?\\d+)/,\n );\n\n return matrixMatch?.[1] ? parseFloat(matrixMatch[1]) : 0;\n};\n\n// A `position:fixed`/`absolute` element is placed relative to the\n// viewport (or the nearest positioned ancestor, which for this preview\n// content is effectively the same scale) — `offsetY + offsetHeight` can\n// legitimately exceed the probe height (e.g. an element deliberately\n// positioned to bleed off-screen), but letting an unbounded value drive\n// the *whole document's* measured height would make one runaway overlay\n// balloon everything below it. Capping at `probeHeight` treats \"this\n// element's bottom edge is somewhere past the viewport\" the same as \"at\n// the viewport edge\" for sizing purposes, without needing to know how far\n// past.\nexport const estimatePositionedElementHeight = (\n offsetHeight: number,\n transform: string,\n probeHeight: number,\n): number => {\n const offsetY = parseTranslateY(transform);\n\n return Math.min(offsetY + offsetHeight, probeHeight);\n};\n","const SYNCED_STYLE_ATTR = 'data-live-editor-synced-style';\n\ntype SourceStyle = HTMLLinkElement | HTMLStyleElement;\ntype SyncedStyle = HTMLLinkElement | HTMLStyleElement;\n\nexport interface StyleSyncManager {\n clones: Map<SourceStyle, SyncedStyle>;\n}\n\nexport const createStyleSyncManager = (): StyleSyncManager => ({\n clones: new Map(),\n});\n\nconst isDocument = (target: Document | ShadowRoot): target is Document =>\n target.nodeType === Node.DOCUMENT_NODE;\n\nconst sourceStyles = (document: Document): SourceStyle[] =>\n Array.from(\n document.head.querySelectorAll<HTMLLinkElement | HTMLStyleElement>(\n 'link[rel=\"stylesheet\"], style',\n ),\n );\n\nconst copyAttributes = (\n source: SourceStyle,\n clone: SyncedStyle,\n transformStyle: (content: string) => string,\n) => {\n Array.from(clone.attributes).forEach(attribute => {\n if (\n attribute.name !== SYNCED_STYLE_ATTR &&\n !source.hasAttribute(attribute.name)\n ) {\n clone.removeAttribute(attribute.name);\n }\n });\n\n Array.from(source.attributes).forEach(attribute => {\n clone.setAttribute(attribute.name, attribute.value);\n });\n\n if (source.tagName === 'LINK' && clone.tagName === 'LINK') {\n (clone as HTMLLinkElement).disabled = (source as HTMLLinkElement).disabled;\n }\n\n clone.textContent =\n source.tagName === 'STYLE'\n ? transformStyle(source.textContent || '')\n : source.textContent;\n};\n\nconst createClone = (\n source: SourceStyle,\n target: Document | ShadowRoot,\n transformStyle: (content: string) => string,\n): SyncedStyle => {\n const ownerDocument = isDocument(target) ? target : target.ownerDocument;\n const clone = ownerDocument.createElement(\n source.tagName.toLowerCase(),\n ) as SyncedStyle;\n\n clone.setAttribute(SYNCED_STYLE_ATTR, '');\n copyAttributes(source, clone, transformStyle);\n\n return clone;\n};\n\nconst targetContainer = (target: Document | ShadowRoot) =>\n isDocument(target) ? target.head : target;\n\nconst isSyncedStyle = (node: Node): node is SyncedStyle => {\n const element = node as Element;\n\n return (\n (element.tagName === 'LINK' || element.tagName === 'STYLE') &&\n element.hasAttribute(SYNCED_STYLE_ATTR)\n );\n};\n\nconst removeClone = (clone: SyncedStyle) => {\n clone.remove();\n};\n\nexport const reconcileStyles = (\n sourceDocument: Document,\n target: Document | ShadowRoot,\n manager: StyleSyncManager,\n enabled: boolean,\n transformStyle: (content: string) => string = content => content,\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) ?? null);\n\n if (clone !== nextSibling) {\n container.insertBefore(clone, nextSibling);\n }\n\n previous = clone;\n });\n};\n","// Part of #132 stage 1 — porting the internal GitLab fork's autoHeight\n// height-measurement redesign into this repo, one verifiable stage at a\n// time (see the issue for the full plan and why the current `updateHeight`\n// implementation needs replacing: folding the iframe to 0px before\n// measuring permanently collapses `vh`-sized content to 0, since `vh`\n// units resolve against the iframe's own height).\n//\n// The fork's fix replaces the iframe height as `vh`'s reference point with\n// a fixed-size CSS containment context (`html { container-type: size;\n// height: <probe>px }`) — see stage 2. That only works if the document's\n// own `vh`/`svh`/`lvh`/`dvh`/`vmin`/`vmax` usages are first rewritten to\n// the matching container-query unit (`cqh`/`cqmin`/`cqmax`), since a size\n// container doesn't retroactively change what `vh` itself resolves\n// against. `vw`/`vi` are deliberately left alone: they resolve against\n// width, which this measurement never touches, so rewriting them would\n// only add risk with no corresponding bug to fix.\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// Requires the matched number not to be immediately preceded by a letter,\n// digit, underscore, `.`, or `-` — this is what keeps `url(a5vh.png)`,\n// `.a5vh{}`, and `.hero-100vh{}` untouched (in all three, the digits\n// before `vh` are part of a larger filename/class-name token, not a\n// standalone CSS number) without needing any special-casing for\n// `url(...)`/selectors specifically. `-` has to be excluded too, not just\n// `\\w`/`.`, since a kebab-case identifier like `hero-100vh` uses it as a\n// word separator the same way `a5vh` uses no separator at all — otherwise\n// the number pattern's own optional leading `-?` would happily treat that\n// hyphen as a negative sign instead. This doesn't break real negative\n// values (`margin-top: -10vh`): there the character *before* the `-` is\n// whatever precedes the whole declaration (a space, in practice), so the\n// lookbehind still passes and the leading `-` is captured as part of the\n// number, same as before.\n//\n// Separately, `--my-vh: 10px` was never a candidate to begin with: there's\n// no digit immediately before `vh` there at all (the `y` in `-vh` is a\n// letter, not a number), so the pattern doesn't even try to match it.\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/vmax to their cqh/cqmin/cqmax equivalent\n// wherever they appear as an actual CSS dimension — including nested\n// inside calc()/var() fallbacks, since this is a plain text substitution\n// rather than a CSS-aware parse. `vw` is left as-is (see UNIT_MAP above).\n//\n// Known limitation, inherited from the source fork and not fixed here:\n// this can't distinguish a real dimension from the same text sitting\n// inside a CSS string literal, e.g. `content: \"100vh\"` — the regex has no\n// concept of quoting, so that string's contents get rewritten too. In\n// practice this is rare (a `content` value that's coincidentally shaped\n// like a viewport dimension) and doesn't affect layout, since `content`\n// strings aren't parsed as CSS values.\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// `convertViewportUnits` only ever runs over CSS *text* that this component\n// controls the injection of — the parent-document `<style>` copies (syncStyle)\n// and the `styles` prop (see iframe.tsx). Two paths carry a viewport unit into\n// the preview document without passing through either, so the container-context\n// fix (#132) never reaches them and their `vh` still resolves against the\n// iframe's own height — re-creating the exact circularity #132 removed:\n//\n// 1. inline `style` attributes — the visual editor's panel edits produce\n// these, so they're a common path here, not an edge case; and\n// 2. author `<style>` elements rendered *inside* the previewed component by\n// React, which never pass through `applyStyle`/`styles`.\n//\n// This rewrites both in place, walking only nodes that could carry a match so\n// the pass stays cheap. It's meant to be called from `updateHeight` right after\n// the container style is (re)applied and before any height is read.\n//\n// Idempotent, and specifically non-perturbing once converted: a rewritten value\n// contains `cqh`/`cqmin`/`cqmax`, none of which match the `vh`/`vmin`/`vmax`\n// attribute selectors, so a second pass re-selects nothing; and each node is\n// written back only when its text actually changed, so an already-converted\n// document isn't mutated — which matters because the write itself would\n// otherwise re-trip the MutationObserver in iframe.tsx and loop.\nexport const rewriteInlineViewportUnits = (root: HTMLElement): void => {\n // `vh` as a substring already covers `svh`/`lvh`/`dvh`; `vmin`/`vmax` need\n // their own terms. Case-insensitive so `100VH` inline is caught too.\n const inlineTargets = root.querySelectorAll<HTMLElement>(\n '[style*=\"vh\" i], [style*=\"vmin\" i], [style*=\"vmax\" i]',\n );\n\n inlineTargets.forEach(el => {\n const current = el.getAttribute('style');\n\n if (current == null) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n el.setAttribute('style', converted);\n }\n });\n\n root.querySelectorAll<HTMLStyleElement>('style').forEach(styleEl => {\n const current = styleEl.textContent;\n\n if (!current) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n styleEl.textContent = converted;\n }\n });\n};\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport {\n useEventListener,\n useMutationObserver,\n useResizeObserver,\n} from '@jbpark/use-hooks';\n\nimport { getCachedScriptBlob } from '~/utils';\n\nimport {\n FALLBACK_PROBE_HEIGHT,\n computeProbeHeight,\n estimatePositionedElementHeight,\n isAnimationActive,\n isVisuallyHidden,\n} from './measure';\nimport { createStyleSyncManager, reconcileStyles } from './style-sync';\nimport {\n convertViewportUnits,\n rewriteInlineViewportUnits,\n} from './viewport-units';\n\nexport interface Props {\n title?: string;\n /** Forwarded to the iframe's `sandbox` attribute for DOM/CSS isolation only — not a security boundary, since preview code executes in the host window's realm (see `compileModule` in `~/utils`). */\n sandbox?: string;\n style?: React.CSSProperties;\n scripts?: string[];\n styles?: string[];\n stylesheets?: string[];\n autoHeight?: boolean;\n syncStyle?: boolean;\n children: (container: HTMLElement) => ReactNode;\n onLoaded?: () => void;\n}\n\nconst EMPTY_STRING_ARRAY: string[] = [];\n\n// `getAnimations()` returns three kinds of animation mixed together:\n// CSSAnimation (a @keyframes rule), CSSTransition (a `transition`) and\n// plain Animation (`element.animate()`). They need telling apart below\n// because only the first two announce their own completion through a\n// bubbling DOM event. Both constructors are feature-detected rather than\n// assumed: jsdom exposes neither.\nconst isCssAnimation = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSAnimation === 'function' &&\n animation instanceof win.CSSAnimation;\n\nconst isCssTransition = (\n win: Window & typeof globalThis,\n animation: Animation,\n): boolean =>\n typeof win.CSSTransition === 'function' &&\n animation instanceof win.CSSTransition;\n\n// Whether this element's look is still in flight, which is what tells a\n// transient `opacity: 0` (the first frames of a fade-in — measure it)\n// from a permanent one (a closed overlay — skip it).\n//\n// Transitions count here, unlike keyframe animations they are not\n// distinguished: now that a measurement pass only freezes transitions when\n// it moves the probe height (see withMeasurementOverrides), an element at\n// the very start of a fade-*in* transition genuinely reads `opacity: 0`\n// with a running transition and has to be measured. An element fading\n// *out* needs no special case — part-way through it reads a fractional\n// opacity, so it is measured for as long as it is still visible, and once\n// the transition is over it reads `0` with nothing running and drops out.\n//\n// getAnimations() is feature-detected: jsdom and pre-2020 browsers don't\n// implement it, and without it this returns false, which is the safe\n// direction (under-measuring a fading-in overlay rather than inflating a\n// section by the height of a dismissed one).\nconst hasActiveAnimation = (el: HTMLElement): boolean =>\n typeof el.getAnimations === 'function' &&\n el.getAnimations().some(animation => isAnimationActive(animation.playState));\n\n// `finished` never resolves for an animation that repeats forever, so a\n// handler attached to one would only pin its closure for as long as the\n// element lives. No signal is lost by skipping it: such an element is\n// perpetually \"animating\", so hasActiveAnimation keeps it in the estimate\n// on every pass anyway.\nconst neverFinishes = (animation: Animation): boolean => {\n const timing = animation.effect?.getComputedTiming();\n\n return timing?.iterations === Infinity || timing?.duration === Infinity;\n};\n\n// A second, separate style — inert (`media=\"not all\"`) except for the\n// brief window updateHeight actually measures in, toggled on right\n// before and off right after (#132 stage 4). Two things it guards\n// against:\n//\n// - transitions: if any rule in the preview (or a browser default)\n// gives `html`/an ancestor a `transition` on a property this\n// measurement touches, changing ensureContainerStyle's `height` would\n// animate instead of applying instantly, and a read taken right after\n// would catch a mid-transition value instead of the settled one. Only\n// applied on a pass that actually changes the probe height — see\n// `freezeTransitions`.\n// - scrollbar chrome: applying a new probe height can make a scrollbar\n// appear/disappear for exactly this measurement pass; on platforms\n// where it takes up layout width (Windows, unlike macOS's overlay\n// scrollbars), that narrows content and skews the height reading.\n// `scrollbar-width: none`/`::-webkit-scrollbar { display: none }`\n// only hides the *chrome* — unlike `overflow: hidden`, scrolling\n// itself still works, so content that ends up taller than its probe\n// height is still reachable rather than silently clipped.\n//\n// A single style element (not two, and never added/removed) so\n// toggling it can't itself trip the MutationObserver watching for\n// *content* changes.\nconst MEASUREMENT_OVERRIDE_STYLE_ID = 'autoheight-measurement-overrides';\n\nconst SCROLLBAR_OVERRIDE_RULES = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n];\n\nconst FREEZE_TRANSITIONS_RULE =\n '*, *::before, *::after { transition: none !important; }';\n\n// `freezeTransitions` is deliberately not always on. `transition: none`\n// does not pause a transition for the duration of the measurement — it\n// *cancels* it, and lifting the override afterwards does not resume it.\n// Measured in Chromium: 0.5s into a 4s fade the element read `0.974`\n// with one running animation; inside the override window it read `0`\n// with none, and it was still `0` with none 0.8s after the override came\n// back off. The element had snapped to its end state for good.\n//\n// Freezing on every pass therefore killed every transition in the\n// preview that happened to overlap a measurement — and because a DOM\n// mutation is what both triggers a measurement and typically starts a\n// transition (a class toggle opening an overlay), that was most of them.\n//\n// The guard is only needed for what the measurement *itself* changes:\n// the probe height, and with it any `cq*`-unit descendant sized against\n// it. When the probe height is unchanged from the last pass, the pass\n// changes nothing, so there is nothing to freeze and the preview's own\n// transitions are left alone.\nconst withMeasurementOverrides = (\n doc: Document,\n freezeTransitions: boolean,\n measure: () => void,\n) => {\n let styleEl = doc.getElementById(\n MEASUREMENT_OVERRIDE_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = MEASUREMENT_OVERRIDE_STYLE_ID;\n styleEl.media = 'not all';\n doc.head?.appendChild(styleEl);\n }\n\n const text = (\n freezeTransitions\n ? [FREEZE_TRANSITIONS_RULE, ...SCROLLBAR_OVERRIDE_RULES]\n : SCROLLBAR_OVERRIDE_RULES\n ).join('\\n');\n\n if (styleEl.textContent !== text) {\n styleEl.textContent = text;\n }\n\n styleEl.media = 'all';\n measure();\n styleEl.media = 'not all';\n};\n\nconst IFrame = ({\n title = 'Live Preview',\n sandbox,\n style = {},\n scripts = EMPTY_STRING_ARRAY,\n styles = EMPTY_STRING_ARRAY,\n stylesheets = EMPTY_STRING_ARRAY,\n autoHeight = false,\n syncStyle = false,\n children,\n onLoaded,\n ...props\n}: Props) => {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const [mountNode, setMountNode] = useState<HTMLElement | null>(null);\n // Tracks which script srcs have already been injected into this iframe's\n // document, keyed by src rather than a single loaded/not-loaded boolean —\n // a boolean latched to `true` forever meant a later change to `scripts`\n // (new entries) never got loaded once the first batch had.\n const loadedScriptsRef = useRef<Set<string>>(new Set());\n const prevStyleCountRef = useRef(0);\n const prevStylesheetCountRef = useRef(0);\n // Animations already given a \"re-measure once you settle\" handler, so a\n // long-running one still in flight across many measurement passes only\n // ever gets one (see trackScriptAnimations). Weak so it never keeps a\n // finished animation — or the element owning it — alive.\n const trackedAnimationsRef = useRef(new WeakSet<Animation>());\n // Lets those handlers call back into the *current* updateHeight without\n // updateHeight having to list itself as its own dependency.\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 about the document, which is what\n // lets that pass measure without freezing the preview's transitions.\n const lastProbeHeightRef = useRef<number | undefined>(undefined);\n const shouldAutoHeight = autoHeight && style.height == null;\n\n const styleManagerRef = useRef(createStyleSyncManager());\n\n const applyStyle = useCallback(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc) {\n return;\n }\n\n reconcileStyles(\n document,\n doc,\n styleManagerRef.current,\n syncStyle,\n convertViewportUnits,\n );\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced so a burst of head mutations (a stylesheet swap can fire\n // several in quick succession) only re-runs applyStyle once, matching the\n // original raw-MutationObserver setup's 50ms debounce.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n 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 doc.body.style.overflowX = 'hidden';\n doc.body.style.margin = '0';\n\n let node = doc.getElementById('iframe-root');\n\n if (!node) {\n node = doc.createElement('div');\n node.id = 'iframe-root';\n doc.body.appendChild(node);\n }\n\n setMountNode(node);\n\n applyStyle();\n\n const pendingScripts = scripts.filter(\n src => !loadedScriptsRef.current.has(src),\n );\n\n if (pendingScripts.length) {\n pendingScripts.forEach(src => loadedScriptsRef.current.add(src));\n\n Promise.all(pendingScripts.map(getCachedScriptBlob)).then(blobUrls => {\n if (!doc.head) {\n return;\n }\n\n const fragment = doc.createDocumentFragment();\n blobUrls.forEach(blobUrl => {\n const script = doc.createElement('script');\n script.src = blobUrl;\n fragment.appendChild(script);\n });\n doc.head.appendChild(fragment);\n });\n }\n\n onLoaded?.();\n };\n\n $iframe.addEventListener('load', onLoad);\n\n if ($iframe.contentDocument?.readyState === 'complete') {\n onLoad();\n }\n\n return () => {\n $iframe.removeEventListener('load', onLoad);\n };\n }, [scripts, onLoaded, applyStyle]);\n\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n styles.forEach((css, index) => {\n const styleId = `injected-style-${index}`;\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = styleId;\n doc.head.appendChild(styleEl);\n }\n\n // The primary source of vh/svh/etc in a real preview — compiled\n // component CSS (e.g. Tailwind's `h-screen` -> `height: 100vh`).\n // See ensureContainerStyle below for why this needs converting.\n const convertedCss = convertViewportUnits(css);\n\n if (styleEl.textContent !== convertedCss) {\n styleEl.textContent = convertedCss;\n }\n });\n\n // Indices beyond the current array's length are stale from a previous,\n // longer `styles`/`stylesheets` — the loops above only add/update up to\n // the current length, so anything past it (from before an item was\n // removed, or the array shrank) would otherwise stay injected forever.\n for (\n let index = styles.length;\n index < prevStyleCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-style-${index}`)?.remove();\n }\n prevStyleCountRef.current = styles.length;\n\n stylesheets.forEach((href, index) => {\n const linkId = `injected-stylesheet-${index}`;\n let linkEl = doc.getElementById(linkId) as HTMLLinkElement | null;\n\n if (!linkEl) {\n linkEl = doc.createElement('link');\n linkEl.id = linkId;\n linkEl.rel = 'stylesheet';\n doc.head.appendChild(linkEl);\n }\n\n if (linkEl.href !== href) {\n linkEl.href = href;\n }\n });\n\n for (\n let index = stylesheets.length;\n index < prevStylesheetCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-stylesheet-${index}`)?.remove();\n }\n prevStylesheetCountRef.current = stylesheets.length;\n }, [styles, stylesheets]);\n\n // The <html> element's own container-context style — id'd so it can be\n // found/updated/removed across calls without holding a ref to it. Scoped\n // to `html` (not `:root`, which is equivalent but the fork's own\n // convention) so this only ever affects cq*-unit resolution and nothing\n // else about the document.\n const CONTAINER_STYLE_ID = 'autoheight-container';\n\n // Permanently hides the iframe document's own scrollbar chrome while\n // autoHeight is sizing the iframe to its content. autoHeight sets the\n // iframe's height to `Math.ceil(contentHeight)`, so sub-pixel content or\n // a rounding remainder can leave the inner document a fraction taller\n // than its viewport — enough for the browser to draw a vertical\n // scrollbar inside every section's iframe (visual noise once several Dnd\n // sections stack). Unlike the measurement-only override above (toggled\n // off after each read), this one stays on: `scrollbar-width`/\n // `::-webkit-scrollbar` hide only the *chrome*, not scrolling itself, so\n // content that ever genuinely exceeds the measured height is still\n // reachable by wheel/keyboard rather than clipped.\n const HIDE_SCROLLBAR_STYLE_ID = 'autoheight-hide-scrollbar';\n\n // Ties `cqh`/`cqmin`/`cqmax` (what convertViewportUnits rewrote every\n // vh/svh/lvh/dvh/vmin/vmax to) to a *fixed* reference height instead of\n // the iframe's own height — this is what breaks the old approach's\n // circularity (#132 problem 1): folding the iframe to 0px before\n // measuring made vh-sized content resolve to 0 and stay there forever,\n // while measuring without folding never converges (vh content sized\n // against the iframe's own just-grown height keeps growing it further).\n // `container-type: size` requires an explicit height to size against,\n // which `probeHeight` (the *scroll container's* available height, not\n // the iframe's) provides — genuinely independent of whatever height this\n // function goes on to set on the iframe itself.\n const ensureContainerStyle = (doc: Document, probeHeight: number) => {\n let styleEl = doc.getElementById(\n CONTAINER_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = CONTAINER_STYLE_ID;\n doc.head?.appendChild(styleEl);\n }\n\n const text = `html { container-type: size !important; height: ${probeHeight}px !important; }`;\n\n // Only written when it actually differs. Re-assigning identical\n // textContent would tear down and rebuild the same CSSOM rule on every\n // pass, and the whole point of the probe height being stable is that a\n // pass changes nothing about the document (see freezeTransitions).\n if (styleEl.textContent !== text) {\n styleEl.textContent = text;\n }\n };\n\n // Script-driven animations are the blind spot the animationend listeners\n // below can't cover: the Web Animations API fires no DOM event when one\n // ends, so nothing would re-run a measurement taken mid-fade. Their\n // `finished` promise is the equivalent signal, so each gets exactly one\n // re-measure scheduled for when it settles.\n //\n // CSS animations and transitions are both skipped: their\n // `animationend`/`transitionend` already bubble to the mount node, so\n // tracking them here too would only measure twice.\n //\n // A cancelled animation rejects `finished` with an AbortError and snaps\n // the element back to its un-animated style, which is as much a reason to\n // re-measure as a clean finish — hence one handler on both settle paths.\n const trackScriptAnimations = useCallback(\n (doc: Document, win: Window & typeof globalThis) => {\n if (typeof doc.getAnimations !== 'function') {\n return;\n }\n\n doc.getAnimations().forEach(animation => {\n if (\n trackedAnimationsRef.current.has(animation) ||\n !isAnimationActive(animation.playState) ||\n isCssAnimation(win, animation) ||\n isCssTransition(win, animation) ||\n neverFinishes(animation)\n ) {\n return;\n }\n\n trackedAnimationsRef.current.add(animation);\n\n animation.finished\n .catch(() => undefined)\n .then(() => updateHeightRef.current?.());\n });\n },\n [],\n );\n\n // Not ported from #132 stage 4: a \"settled scrollHeight + settled probe\n // height both unchanged -> skip\" guard, meant to avoid redundant re-runs\n // from updateHeight's own `iframe.style.height` write looping back\n // through the ResizeObserver below (a real path — the iframe's own box\n // size determines its *internal* viewport size, so this can genuinely\n // fire again). Left out deliberately: `scrollHeight` only reflects\n // normal document flow, but a position:fixed/absolute overlay opening or\n // closing (its whole reason for needing the full-subtree walk above)\n // often doesn't touch `scrollHeight` at all. A guard keyed on it would\n // silently skip exactly the kind of update stage 3 exists to catch —\n // reintroducing a narrower version of the bug this file just fixed\n // would be a worse trade than the redundant-recompute cost it'd save.\n const updateHeight = useCallback(() => {\n if (!shouldAutoHeight || !mountNode || !iframeRef.current) {\n return;\n }\n\n const iframe = iframeRef.current;\n const doc = iframe.contentDocument;\n const win = doc?.defaultView;\n\n if (!doc || !win) {\n return;\n }\n\n const scrollParent = iframe.closest<HTMLElement>('[data-frame-container]');\n\n let probeHeight: number;\n\n if (!scrollParent) {\n // No scroll container anywhere in the tree (Frame used directly,\n // without Dnd) — fall back to a fixed default; see\n // FALLBACK_PROBE_HEIGHT's own comment for why this differs from\n // the \"container exists but isn't laid out yet\" case below.\n probeHeight = FALLBACK_PROBE_HEIGHT;\n } else {\n let wrapperInsets = 0;\n let node = iframe.parentElement;\n\n while (node && node !== scrollParent) {\n const style = win.getComputedStyle(node);\n\n wrapperInsets +=\n parseFloat(style.borderTopWidth) +\n parseFloat(style.borderBottomWidth) +\n parseFloat(style.paddingTop) +\n parseFloat(style.paddingBottom);\n\n node = node.parentElement;\n }\n\n const computed = computeProbeHeight(\n scrollParent.clientHeight,\n wrapperInsets,\n );\n\n if (computed === null) {\n // Layout not ready yet (mid-transition, just mounted, etc) —\n // skip this pass instead of guessing; the ResizeObserver/\n // MutationObserver below will call this again once something\n // actually changes, including the layout settling.\n return;\n }\n\n probeHeight = computed;\n }\n\n let contentHeight = 0;\n\n // First pass (`undefined`) and any pass that moves the probe height are\n // the only ones that change the container context, so they are the only\n // ones that need the preview's transitions out of the way.\n const freezeTransitions = probeHeight !== lastProbeHeightRef.current;\n\n lastProbeHeightRef.current = probeHeight;\n\n withMeasurementOverrides(doc, freezeTransitions, () => {\n ensureContainerStyle(doc, probeHeight);\n\n // Rewrite vh-family units the container context can't otherwise reach —\n // inline `style` attributes and in-preview `<style>` tags — so they too\n // resolve against the fixed probe height rather than the iframe's own\n // (see rewriteInlineViewportUnits). Must run after ensureContainerStyle\n // and before the reads below; it's idempotent, so the extra observer\n // pass its first-render rewrites trigger converges immediately.\n rewriteInlineViewportUnits(mountNode);\n\n // No 0px fold before measuring (that was the source of problem 1)\n // — with cq*-unit content now sized against the fixed probe height\n // instead of the iframe's own, a direct read is already stable.\n contentHeight = mountNode.scrollHeight;\n\n // Full subtree, not just direct children (a popup/overlay nested a\n // few components deep was previously invisible to this walk\n // entirely — problem 2's \"중첩된 오버레이는 아예 누락됩니다\").\n const descendants = mountNode.querySelectorAll<HTMLElement>('*');\n\n descendants.forEach(el => {\n const style = win.getComputedStyle(el);\n\n // visibility:hidden/opacity:0 elements (a closed bottom sheet,\n // a not-yet-faded-in overlay) keep a non-zero offsetHeight —\n // display:none doesn't need checking here since the browser\n // already zeroes *its* offsetHeight on its own.\n //\n // The animation lookup is confined to the one verdict it can\n // change — whether a fully transparent element is fading in\n // (measure it) or simply not shown (skip it) — so every other\n // element still costs nothing but the computed-style read.\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 estimatedHeight = estimatePositionedElementHeight(\n el.offsetHeight,\n style.transform,\n probeHeight,\n );\n\n contentHeight = Math.max(contentHeight, estimatedHeight);\n }\n });\n });\n\n if (contentHeight > 0) {\n iframe.style.height = `${Math.ceil(contentHeight)}px`;\n }\n\n // Outside the measurement window on purpose: the overrides above cancel\n // running transitions, and this read should see the document's real\n // animation set rather than one the act of measuring just altered.\n trackScriptAnimations(doc, win);\n }, [shouldAutoHeight, mountNode, trackScriptAnimations]);\n\n useEffect(() => {\n updateHeightRef.current = updateHeight;\n }, [updateHeight]);\n\n // updateHeight only ever adds/refreshes the container-context style —\n // if autoHeight is toggled off (or an explicit style.height is passed)\n // at runtime, nothing else would ever remove or update it again,\n // leaving cq*-unit content sized against a stale probe height instead\n // of correctly falling back to real viewport-relative sizing (which\n // cqh does on its own once nothing establishes a size container — see\n // ensureContainerStyle's own comment).\n useEffect(() => {\n if (shouldAutoHeight) {\n return;\n }\n\n iframeRef.current?.contentDocument\n ?.getElementById(CONTAINER_STYLE_ID)\n ?.remove();\n }, [shouldAutoHeight]);\n\n // Keyed on mountNode (not just shouldAutoHeight) so it re-runs once the\n // iframe's document exists — before load there's no head to inject into.\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n const existing = doc.getElementById(HIDE_SCROLLBAR_STYLE_ID);\n\n if (!shouldAutoHeight) {\n existing?.remove();\n return;\n }\n\n if (existing) {\n return;\n }\n\n const styleEl = doc.createElement('style');\n styleEl.id = HIDE_SCROLLBAR_STYLE_ID;\n styleEl.textContent = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n ].join('\\n');\n doc.head.appendChild(styleEl);\n }, [shouldAutoHeight, mountNode]);\n\n useEffect(() => {\n updateHeight();\n }, [updateHeight]);\n\n const [resizeRef, resizeSize] = useResizeObserver<HTMLElement>();\n\n // useResizeObserver's ref callback isn't wired through this component's\n // own JSX (mountNode is the portal's imperatively-created container, not\n // something rendered here), so it's attached/detached imperatively\n // instead. Its reported size is intentionally unused - updateHeight's own\n // walk (every descendant, position:fixed/absolute ones capped and offset\n // by their transform) computes a more accurate height than mountNode's\n // own content-box size would, so a change in `resizeSize` is only used\n // as a trigger to recompute.\n useEffect(() => {\n if (!shouldAutoHeight || !mountNode) {\n return;\n }\n\n resizeRef(mountNode);\n return () => resizeRef(null);\n }, [shouldAutoHeight, mountNode, resizeRef]);\n\n useEffect(() => {\n updateHeight();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resizeSize]);\n\n useMutationObserver(mountNode, updateHeight, {\n enabled: shouldAutoHeight,\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n });\n\n // An animation or transition finishing is neither a DOM mutation nor a\n // resize of the mount node, so neither observer above re-runs the\n // measurement — a fixed/absolute element read mid-fade would keep its\n // stale height on the iframe until something unrelated happened to the DOM\n // (#374). All four events bubble, so a single listener each on the mount\n // node covers every descendant.\n //\n // The `cancel` events count as much as the `end` ones: a cancelled\n // animation or transition snaps the element back to its un-animated style,\n // changing the height just the same.\n //\n // `transitionend`/`transitioncancel` used to be unnecessary, because every\n // measurement pass cancelled every transition outright. Now that a pass\n // only freezes transitions when it moves the probe height, a transition\n // can genuinely still be running when a pass reads it, so its completion\n // needs the same re-measure a keyframe animation's does.\n //\n // useEventListener resolves an element target through a ref, so mountNode\n // (portal-owned state, not something this component renders) is wrapped in\n // one that changes identity only when the node itself does. `enabled`\n // keeps it from polling for a node that isn't there yet.\n const mountNodeRef = useMemo(() => ({ current: mountNode }), [mountNode]);\n const settleListenerEnabled = shouldAutoHeight && mountNode !== null;\n\n useEventListener('animationend', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('animationcancel', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('transitionend', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n useEventListener('transitioncancel', updateHeight, {\n target: mountNodeRef,\n enabled: settleListenerEnabled,\n });\n\n const content = mountNode\n ? createPortal(children(mountNode), mountNode)\n : null;\n\n return (\n <iframe\n ref={iframeRef}\n style={{\n width: '100%',\n height: '100%',\n border: 'none',\n ...style,\n }}\n title={title}\n sandbox={sandbox}\n {...props}\n >\n {content}\n </iframe>\n );\n};\n\nexport default IFrame;\n","import {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useMutationObserver } from '@jbpark/use-hooks';\n\nimport { createStyleSyncManager, reconcileStyles } from './style-sync';\n\ninterface Props {\n // Clones the host document's <link rel=\"stylesheet\">/<style> tags into the\n // shadow root, mirroring `iframe.tsx`'s option of the same name. Unlike\n // `dynamicTailwind` (which recompiles only the classes it can find in the\n // rendered DOM, and only knows Tailwind's own default theme), this gets\n // the host's *actual* compiled CSS — including a consuming app's own\n // custom utilities/theme tokens — at the cost of only covering classes\n // that were already known at the host's own build time. The two are\n // complementary: this handles anything already in the host's stylesheets,\n // dynamicTailwind covers whatever's left (e.g. a class typed at runtime\n // that no build ever saw).\n syncStyle?: boolean;\n children: (hostContainer: HTMLElement | null) => ReactNode;\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 const [hostContainer, setHostContainer] = useState<HTMLElement | null>(null);\n\n // Appended as siblings of the portal target (below), not inside it — that\n // subtree is React-owned via createPortal, and anything appended there\n // directly would get wiped on the next reconcile.\n const styleManagerRef = useRef(createStyleSyncManager());\n\n const applyStyle = useCallback(() => {\n const shadowRoot = shadowRootRef.current;\n\n if (!shadowRoot) {\n return;\n }\n\n reconcileStyles(document, shadowRoot, styleManagerRef.current, syncStyle);\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced so a burst of head mutations (a stylesheet swap can fire\n // several in quick succession) only re-runs applyStyle once — same\n // rationale as iframe.tsx's identical setup.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n });\n\n useLayoutEffect(() => {\n if (!hostRef.current) {\n return;\n }\n\n const container = hostRef.current.closest(\n '[data-frame-container]',\n ) as HTMLElement | null;\n\n setHostContainer(container);\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 target = document.createElement('div');\n shadowRoot.appendChild(target);\n renderTargetRef.current = target;\n setRenderTarget(target);\n }\n\n applyStyle();\n // click/pointerdown/pointerup are `composed: true` by spec, so they\n // already retarget across the shadow boundary and reach listeners\n // outside it (document, this host's ancestors, React's own root\n // listener) on their own - manually redispatching them here used to\n // make every one of those listeners see the interaction twice. Anyone\n // needing the real element inside the shadow tree (not the retargeted\n // host) can still read it via event.composedPath()[0], unaffected by\n // this removal. See #92.\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 && createPortal(children(hostContainer), renderTarget)}\n </div>\n );\n};\n\nexport default Shadow;\n","import { type ReactNode } from 'react';\n\nimport IFrame, { type Props as IframeProps } from './iframe';\nimport Shadow from './shadow';\n\nexport interface FrameProps extends Omit<IframeProps, 'children'> {\n mode?: 'iframe' | 'shadow';\n}\n\ninterface Props extends FrameProps {\n children: (container: HTMLElement) => ReactNode;\n}\n\nconst Frame = ({ mode, children, ...restProps }: Props) => {\n if (!mode) {\n return children(document.body);\n }\n\n if (mode === 'shadow') {\n return (\n <Shadow syncStyle={restProps.syncStyle}>\n {container => children(container || document.body)}\n </Shadow>\n );\n }\n\n return <IFrame {...restProps}>{children}</IFrame>;\n};\n\nexport default Frame;\n","import * as ui from '@jbpark/ui-kit';\nimport * as utils from '@jbpark/ui-kit/utils';\n\n// The specifiers every compiled sample can import without the host supplying\n// them (`import * as ui from 'ui-kit'`). Lives with the preview, its only\n// consumer, rather than in `~/utils`: evaluating ui-kit's namespace reaches\n// its stylesheet imports, so keeping it there made `@jbpark/live-editor/utils`\n// (and every entry built on it) unimportable outside a bundler — Node, SSR,\n// scripts. See #372.\nexport const baseModules = {\n 'ui-kit': ui,\n 'ui-kit/utils': utils,\n};\n","import { useMemo } from 'react';\n\nimport type { Module } from '~/types';\nimport { compile } from '~/utils';\n\nimport { baseModules } from './base-modules';\n\n// Shared by `preview/client.tsx` and `dnd/renderer.tsx`, which both turn a\n// code string into a renderable component in exactly the same way. They used\n// to implement this separately, which is how the two paths drifted apart on\n// error handling (see #246).\n//\n// Returns `null` for empty code so a caller can tell \"nothing to render\"\n// apart from \"compiled, but failed\" — the latter is a Module carrying\n// `error`, which callers should surface rather than render as blank.\nexport const useCompiledModule = (\n code: string,\n modules?: Record<string, unknown>,\n): Module | null => {\n const mergedModules = useMemo(\n () => ({ ...baseModules, ...modules }),\n [modules],\n );\n\n return useMemo(() => {\n if (!code) {\n return null;\n }\n\n try {\n return compile(code, mergedModules);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\n }, [code, mergedModules]);\n};\n","import { useCallback, useEffect, useState } from 'react';\n\n// Compiles the Tailwind classes found in rendered output and returns them as\n// a CSS string for the caller to inject as a `<style>` tag. Shared by\n// `preview/client.tsx` and `dnd/renderer.tsx`, which previously carried\n// byte-identical copies of this logic and of the comments below (see #246).\n//\n// Scans the live DOM (whatever the returned `ref` is attached to) rather than\n// the source text it was rendered from, so classes contributed by an imported\n// component (e.g. ui-kit's `Button`) are picked up too — those never appear as\n// literal text in the previewed source, only in that component's own compiled\n// output.\n//\n// The scanned element is tracked as state via a callback ref rather than a\n// plain `useRef`, because in shadow mode it isn't mounted on the caller's\n// first commit at all — `Shadow` creates its portal target in its own effect\n// and only re-renders with it afterwards, one commit later. A plain ref read\n// in a `[code, enabled]`-keyed effect would see `null` on that first pass and\n// never retry; making the element itself a dependency re-runs the scan once\n// it actually exists.\n//\n// The Tailwind compiler and its theme are imported on first use rather than\n// with this module: they only matter with `dynamicTailwind` on, and were\n// otherwise ~300 kB of every consumer's initial bundle (#332).\nexport const useDynamicTailwind = (code: string, enabled: boolean) => {\n const [css, setCss] = useState('');\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const ref = useCallback((node: HTMLDivElement | null) => {\n setElement(node);\n }, []);\n\n useEffect(() => {\n if (!code || !enabled || !element) {\n return;\n }\n\n let cancelled = false;\n\n import('~/utils/tailwind')\n .then(({ generateTailwindCSSFromDOM }) =>\n generateTailwindCSSFromDOM(element),\n )\n .then(next => {\n if (!cancelled) {\n setCss(next);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [code, enabled, element]);\n\n return { ref, css };\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { compile } from "tailwindcss";
|
|
2
|
+
//#region src/utils/tailwind/theme-css.ts
|
|
3
|
+
var theme_css_default = "@theme default {\n --font-sans:\n -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial,\n sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;\n --font-mono:\n ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',\n monospace;\n\n --color-red-50: oklch(97.1% 0.013 17.38);\n --color-red-100: oklch(93.6% 0.032 17.717);\n --color-red-200: oklch(88.5% 0.062 18.334);\n --color-red-300: oklch(80.8% 0.114 19.571);\n --color-red-400: oklch(70.4% 0.191 22.216);\n --color-red-500: oklch(63.7% 0.237 25.331);\n --color-red-600: oklch(57.7% 0.245 27.325);\n --color-red-700: oklch(50.5% 0.213 27.518);\n --color-red-800: oklch(44.4% 0.177 26.899);\n --color-red-900: oklch(39.6% 0.141 25.723);\n --color-red-950: oklch(25.8% 0.092 26.042);\n\n --color-orange-50: oklch(98% 0.016 73.684);\n --color-orange-100: oklch(95.4% 0.038 75.164);\n --color-orange-200: oklch(90.1% 0.076 70.697);\n --color-orange-300: oklch(83.7% 0.128 66.29);\n --color-orange-400: oklch(75% 0.183 55.934);\n --color-orange-500: oklch(70.5% 0.213 47.604);\n --color-orange-600: oklch(64.6% 0.222 41.116);\n --color-orange-700: oklch(55.3% 0.195 38.402);\n --color-orange-800: oklch(47% 0.157 37.304);\n --color-orange-900: oklch(40.8% 0.123 38.172);\n --color-orange-950: oklch(26.6% 0.079 36.259);\n\n --color-amber-50: oklch(98.7% 0.022 95.277);\n --color-amber-100: oklch(96.2% 0.059 95.617);\n --color-amber-200: oklch(92.4% 0.12 95.746);\n --color-amber-300: oklch(87.9% 0.169 91.605);\n --color-amber-400: oklch(82.8% 0.189 84.429);\n --color-amber-500: oklch(76.9% 0.188 70.08);\n --color-amber-600: oklch(66.6% 0.179 58.318);\n --color-amber-700: oklch(55.5% 0.163 48.998);\n --color-amber-800: oklch(47.3% 0.137 46.201);\n --color-amber-900: oklch(41.4% 0.112 45.904);\n --color-amber-950: oklch(27.9% 0.077 45.635);\n\n --color-yellow-50: oklch(98.7% 0.026 102.212);\n --color-yellow-100: oklch(97.3% 0.071 103.193);\n --color-yellow-200: oklch(94.5% 0.129 101.54);\n --color-yellow-300: oklch(90.5% 0.182 98.111);\n --color-yellow-400: oklch(85.2% 0.199 91.936);\n --color-yellow-500: oklch(79.5% 0.184 86.047);\n --color-yellow-600: oklch(68.1% 0.162 75.834);\n --color-yellow-700: oklch(55.4% 0.135 66.442);\n --color-yellow-800: oklch(47.6% 0.114 61.907);\n --color-yellow-900: oklch(42.1% 0.095 57.708);\n --color-yellow-950: oklch(28.6% 0.066 53.813);\n\n --color-lime-50: oklch(98.6% 0.031 120.757);\n --color-lime-100: oklch(96.7% 0.067 122.328);\n --color-lime-200: oklch(93.8% 0.127 124.321);\n --color-lime-300: oklch(89.7% 0.196 126.665);\n --color-lime-400: oklch(84.1% 0.238 128.85);\n --color-lime-500: oklch(76.8% 0.233 130.85);\n --color-lime-600: oklch(64.8% 0.2 131.684);\n --color-lime-700: oklch(53.2% 0.157 131.589);\n --color-lime-800: oklch(45.3% 0.124 130.933);\n --color-lime-900: oklch(40.5% 0.101 131.063);\n --color-lime-950: oklch(27.4% 0.072 132.109);\n\n --color-green-50: oklch(98.2% 0.018 155.826);\n --color-green-100: oklch(96.2% 0.044 156.743);\n --color-green-200: oklch(92.5% 0.084 155.995);\n --color-green-300: oklch(87.1% 0.15 154.449);\n --color-green-400: oklch(79.2% 0.209 151.711);\n --color-green-500: oklch(72.3% 0.219 149.579);\n --color-green-600: oklch(62.7% 0.194 149.214);\n --color-green-700: oklch(52.7% 0.154 150.069);\n --color-green-800: oklch(44.8% 0.119 151.328);\n --color-green-900: oklch(39.3% 0.095 152.535);\n --color-green-950: oklch(26.6% 0.065 152.934);\n\n --color-emerald-50: oklch(97.9% 0.021 166.113);\n --color-emerald-100: oklch(95% 0.052 163.051);\n --color-emerald-200: oklch(90.5% 0.093 164.15);\n --color-emerald-300: oklch(84.5% 0.143 164.978);\n --color-emerald-400: oklch(76.5% 0.177 163.223);\n --color-emerald-500: oklch(69.6% 0.17 162.48);\n --color-emerald-600: oklch(59.6% 0.145 163.225);\n --color-emerald-700: oklch(50.8% 0.118 165.612);\n --color-emerald-800: oklch(43.2% 0.095 166.913);\n --color-emerald-900: oklch(37.8% 0.077 168.94);\n --color-emerald-950: oklch(26.2% 0.051 172.552);\n\n --color-teal-50: oklch(98.4% 0.014 180.72);\n --color-teal-100: oklch(95.3% 0.051 180.801);\n --color-teal-200: oklch(91% 0.096 180.426);\n --color-teal-300: oklch(85.5% 0.138 181.071);\n --color-teal-400: oklch(77.7% 0.152 181.912);\n --color-teal-500: oklch(70.4% 0.14 182.503);\n --color-teal-600: oklch(60% 0.118 184.704);\n --color-teal-700: oklch(51.1% 0.096 186.391);\n --color-teal-800: oklch(43.7% 0.078 188.216);\n --color-teal-900: oklch(38.6% 0.063 188.416);\n --color-teal-950: oklch(27.7% 0.046 192.524);\n\n --color-cyan-50: oklch(98.4% 0.019 200.873);\n --color-cyan-100: oklch(95.6% 0.045 203.388);\n --color-cyan-200: oklch(91.7% 0.08 205.041);\n --color-cyan-300: oklch(86.5% 0.127 207.078);\n --color-cyan-400: oklch(78.9% 0.154 211.53);\n --color-cyan-500: oklch(71.5% 0.143 215.221);\n --color-cyan-600: oklch(60.9% 0.126 221.723);\n --color-cyan-700: oklch(52% 0.105 223.128);\n --color-cyan-800: oklch(45% 0.085 224.283);\n --color-cyan-900: oklch(39.8% 0.07 227.392);\n --color-cyan-950: oklch(30.2% 0.056 229.695);\n\n --color-sky-50: oklch(97.7% 0.013 236.62);\n --color-sky-100: oklch(95.1% 0.026 236.824);\n --color-sky-200: oklch(90.1% 0.058 230.902);\n --color-sky-300: oklch(82.8% 0.111 230.318);\n --color-sky-400: oklch(74.6% 0.16 232.661);\n --color-sky-500: oklch(68.5% 0.169 237.323);\n --color-sky-600: oklch(58.8% 0.158 241.966);\n --color-sky-700: oklch(50% 0.134 242.749);\n --color-sky-800: oklch(44.3% 0.11 240.79);\n --color-sky-900: oklch(39.1% 0.09 240.876);\n --color-sky-950: oklch(29.3% 0.066 243.157);\n\n --color-blue-50: oklch(97% 0.014 254.604);\n --color-blue-100: oklch(93.2% 0.032 255.585);\n --color-blue-200: oklch(88.2% 0.059 254.128);\n --color-blue-300: oklch(80.9% 0.105 251.813);\n --color-blue-400: oklch(70.7% 0.165 254.624);\n --color-blue-500: oklch(62.3% 0.214 259.815);\n --color-blue-600: oklch(54.6% 0.245 262.881);\n --color-blue-700: oklch(48.8% 0.243 264.376);\n --color-blue-800: oklch(42.4% 0.199 265.638);\n --color-blue-900: oklch(37.9% 0.146 265.522);\n --color-blue-950: oklch(28.2% 0.091 267.935);\n\n --color-indigo-50: oklch(96.2% 0.018 272.314);\n --color-indigo-100: oklch(93% 0.034 272.788);\n --color-indigo-200: oklch(87% 0.065 274.039);\n --color-indigo-300: oklch(78.5% 0.115 274.713);\n --color-indigo-400: oklch(67.3% 0.182 276.935);\n --color-indigo-500: oklch(58.5% 0.233 277.117);\n --color-indigo-600: oklch(51.1% 0.262 276.966);\n --color-indigo-700: oklch(45.7% 0.24 277.023);\n --color-indigo-800: oklch(39.8% 0.195 277.366);\n --color-indigo-900: oklch(35.9% 0.144 278.697);\n --color-indigo-950: oklch(25.7% 0.09 281.288);\n\n --color-violet-50: oklch(96.9% 0.016 293.756);\n --color-violet-100: oklch(94.3% 0.029 294.588);\n --color-violet-200: oklch(89.4% 0.057 293.283);\n --color-violet-300: oklch(81.1% 0.111 293.571);\n --color-violet-400: oklch(70.2% 0.183 293.541);\n --color-violet-500: oklch(60.6% 0.25 292.717);\n --color-violet-600: oklch(54.1% 0.281 293.009);\n --color-violet-700: oklch(49.1% 0.27 292.581);\n --color-violet-800: oklch(43.2% 0.232 292.759);\n --color-violet-900: oklch(38% 0.189 293.745);\n --color-violet-950: oklch(28.3% 0.141 291.089);\n\n --color-purple-50: oklch(97.7% 0.014 308.299);\n --color-purple-100: oklch(94.6% 0.033 307.174);\n --color-purple-200: oklch(90.2% 0.063 306.703);\n --color-purple-300: oklch(82.7% 0.119 306.383);\n --color-purple-400: oklch(71.4% 0.203 305.504);\n --color-purple-500: oklch(62.7% 0.265 303.9);\n --color-purple-600: oklch(55.8% 0.288 302.321);\n --color-purple-700: oklch(49.6% 0.265 301.924);\n --color-purple-800: oklch(43.8% 0.218 303.724);\n --color-purple-900: oklch(38.1% 0.176 304.987);\n --color-purple-950: oklch(29.1% 0.149 302.717);\n\n --color-fuchsia-50: oklch(97.7% 0.017 320.058);\n --color-fuchsia-100: oklch(95.2% 0.037 318.852);\n --color-fuchsia-200: oklch(90.3% 0.076 319.62);\n --color-fuchsia-300: oklch(83.3% 0.145 321.434);\n --color-fuchsia-400: oklch(74% 0.238 322.16);\n --color-fuchsia-500: oklch(66.7% 0.295 322.15);\n --color-fuchsia-600: oklch(59.1% 0.293 322.896);\n --color-fuchsia-700: oklch(51.8% 0.253 323.949);\n --color-fuchsia-800: oklch(45.2% 0.211 324.591);\n --color-fuchsia-900: oklch(40.1% 0.17 325.612);\n --color-fuchsia-950: oklch(29.3% 0.136 325.661);\n\n --color-pink-50: oklch(97.1% 0.014 343.198);\n --color-pink-100: oklch(94.8% 0.028 342.258);\n --color-pink-200: oklch(89.9% 0.061 343.231);\n --color-pink-300: oklch(82.3% 0.12 346.018);\n --color-pink-400: oklch(71.8% 0.202 349.761);\n --color-pink-500: oklch(65.6% 0.241 354.308);\n --color-pink-600: oklch(59.2% 0.249 0.584);\n --color-pink-700: oklch(52.5% 0.223 3.958);\n --color-pink-800: oklch(45.9% 0.187 3.815);\n --color-pink-900: oklch(40.8% 0.153 2.432);\n --color-pink-950: oklch(28.4% 0.109 3.907);\n\n --color-rose-50: oklch(96.9% 0.015 12.422);\n --color-rose-100: oklch(94.1% 0.03 12.58);\n --color-rose-200: oklch(89.2% 0.058 10.001);\n --color-rose-300: oklch(81% 0.117 11.638);\n --color-rose-400: oklch(71.2% 0.194 13.428);\n --color-rose-500: oklch(64.5% 0.246 16.439);\n --color-rose-600: oklch(58.6% 0.253 17.585);\n --color-rose-700: oklch(51.4% 0.222 16.935);\n --color-rose-800: oklch(45.5% 0.188 13.697);\n --color-rose-900: oklch(41% 0.159 10.272);\n --color-rose-950: oklch(27.1% 0.105 12.094);\n\n --color-slate-50: oklch(98.4% 0.003 247.858);\n --color-slate-100: oklch(96.8% 0.007 247.896);\n --color-slate-200: oklch(92.9% 0.013 255.508);\n --color-slate-300: oklch(86.9% 0.022 252.894);\n --color-slate-400: oklch(70.4% 0.04 256.788);\n --color-slate-500: oklch(55.4% 0.046 257.417);\n --color-slate-600: oklch(44.6% 0.043 257.281);\n --color-slate-700: oklch(37.2% 0.044 257.287);\n --color-slate-800: oklch(27.9% 0.041 260.031);\n --color-slate-900: oklch(20.8% 0.042 265.755);\n --color-slate-950: oklch(12.9% 0.042 264.695);\n\n --color-gray-50: oklch(98.5% 0.002 247.839);\n --color-gray-100: oklch(96.7% 0.003 264.542);\n --color-gray-200: oklch(92.8% 0.006 264.531);\n --color-gray-300: oklch(87.2% 0.01 258.338);\n --color-gray-400: oklch(70.7% 0.022 261.325);\n --color-gray-500: oklch(55.1% 0.027 264.364);\n --color-gray-600: oklch(44.6% 0.03 256.802);\n --color-gray-700: oklch(37.3% 0.034 259.733);\n --color-gray-800: oklch(27.8% 0.033 256.848);\n --color-gray-900: oklch(21% 0.034 264.665);\n --color-gray-950: oklch(13% 0.028 261.692);\n\n --color-zinc-50: oklch(98.5% 0 none);\n --color-zinc-100: oklch(96.7% 0.001 286.375);\n --color-zinc-200: oklch(92% 0.004 286.32);\n --color-zinc-300: oklch(87.1% 0.006 286.286);\n --color-zinc-400: oklch(70.5% 0.015 286.067);\n --color-zinc-500: oklch(55.2% 0.016 285.938);\n --color-zinc-600: oklch(44.2% 0.017 285.786);\n --color-zinc-700: oklch(37% 0.013 285.805);\n --color-zinc-800: oklch(27.4% 0.006 286.033);\n --color-zinc-900: oklch(21% 0.006 285.885);\n --color-zinc-950: oklch(14.1% 0.005 285.823);\n\n --color-neutral-50: oklch(98.5% 0 none);\n --color-neutral-100: oklch(97% 0 none);\n --color-neutral-200: oklch(92.2% 0 none);\n --color-neutral-300: oklch(87% 0 none);\n --color-neutral-400: oklch(70.8% 0 none);\n --color-neutral-500: oklch(55.6% 0 none);\n --color-neutral-600: oklch(43.9% 0 none);\n --color-neutral-700: oklch(37.1% 0 none);\n --color-neutral-800: oklch(26.9% 0 none);\n --color-neutral-900: oklch(20.5% 0 none);\n --color-neutral-950: oklch(14.5% 0 none);\n\n --color-stone-50: oklch(98.5% 0.001 106.423);\n --color-stone-100: oklch(97% 0.001 106.424);\n --color-stone-200: oklch(92.3% 0.003 48.717);\n --color-stone-300: oklch(86.9% 0.005 56.366);\n --color-stone-400: oklch(70.9% 0.01 56.259);\n --color-stone-500: oklch(55.3% 0.013 58.071);\n --color-stone-600: oklch(44.4% 0.011 73.639);\n --color-stone-700: oklch(37.4% 0.01 67.558);\n --color-stone-800: oklch(26.8% 0.007 34.298);\n --color-stone-900: oklch(21.6% 0.006 56.043);\n --color-stone-950: oklch(14.7% 0.004 49.25);\n\n --color-mauve-50: oklch(98.5% 0 none);\n --color-mauve-100: oklch(96% 0.003 325.6);\n --color-mauve-200: oklch(92.2% 0.005 325.62);\n --color-mauve-300: oklch(86.5% 0.012 325.68);\n --color-mauve-400: oklch(71.1% 0.019 323.02);\n --color-mauve-500: oklch(54.2% 0.034 322.5);\n --color-mauve-600: oklch(43.5% 0.029 321.78);\n --color-mauve-700: oklch(36.4% 0.029 323.89);\n --color-mauve-800: oklch(26.3% 0.024 320.12);\n --color-mauve-900: oklch(21.2% 0.019 322.12);\n --color-mauve-950: oklch(14.5% 0.008 326);\n\n --color-olive-50: oklch(98.8% 0.003 106.5);\n --color-olive-100: oklch(96.6% 0.005 106.5);\n --color-olive-200: oklch(93% 0.007 106.5);\n --color-olive-300: oklch(88% 0.011 106.6);\n --color-olive-400: oklch(73.7% 0.021 106.9);\n --color-olive-500: oklch(58% 0.031 107.3);\n --color-olive-600: oklch(46.6% 0.025 107.3);\n --color-olive-700: oklch(39.4% 0.023 107.4);\n --color-olive-800: oklch(28.6% 0.016 107.4);\n --color-olive-900: oklch(22.8% 0.013 107.4);\n --color-olive-950: oklch(15.3% 0.006 107.1);\n\n --color-mist-50: oklch(98.7% 0.002 197.1);\n --color-mist-100: oklch(96.3% 0.002 197.1);\n --color-mist-200: oklch(92.5% 0.005 214.3);\n --color-mist-300: oklch(87.2% 0.007 219.6);\n --color-mist-400: oklch(72.3% 0.014 214.4);\n --color-mist-500: oklch(56% 0.021 213.5);\n --color-mist-600: oklch(45% 0.017 213.2);\n --color-mist-700: oklch(37.8% 0.015 216);\n --color-mist-800: oklch(27.5% 0.011 216.9);\n --color-mist-900: oklch(21.8% 0.008 223.9);\n --color-mist-950: oklch(14.8% 0.004 228.8);\n\n --color-taupe-50: oklch(98.6% 0.002 67.8);\n --color-taupe-100: oklch(96% 0.002 17.2);\n --color-taupe-200: oklch(92.2% 0.005 34.3);\n --color-taupe-300: oklch(86.8% 0.007 39.5);\n --color-taupe-400: oklch(71.4% 0.014 41.2);\n --color-taupe-500: oklch(54.7% 0.021 43.1);\n --color-taupe-600: oklch(43.8% 0.017 39.3);\n --color-taupe-700: oklch(36.7% 0.016 35.7);\n --color-taupe-800: oklch(26.8% 0.011 36.5);\n --color-taupe-900: oklch(21.4% 0.009 43.1);\n --color-taupe-950: oklch(14.7% 0.004 49.3);\n\n --color-black: #000;\n --color-white: #fff;\n\n --spacing: 0.25rem;\n\n --breakpoint-sm: 40rem;\n --breakpoint-md: 48rem;\n --breakpoint-lg: 64rem;\n --breakpoint-xl: 80rem;\n --breakpoint-2xl: 96rem;\n\n --container-3xs: 16rem;\n --container-2xs: 18rem;\n --container-xs: 20rem;\n --container-sm: 24rem;\n --container-md: 28rem;\n --container-lg: 32rem;\n --container-xl: 36rem;\n --container-2xl: 42rem;\n --container-3xl: 48rem;\n --container-4xl: 56rem;\n --container-5xl: 64rem;\n --container-6xl: 72rem;\n --container-7xl: 80rem;\n\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-base: 1rem;\n --text-base--line-height: calc(1.5 / 1);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-2xl: 1.5rem;\n --text-2xl--line-height: calc(2 / 1.5);\n --text-3xl: 1.875rem;\n --text-3xl--line-height: calc(2.25 / 1.875);\n --text-4xl: 2.25rem;\n --text-4xl--line-height: calc(2.5 / 2.25);\n --text-5xl: 3rem;\n --text-5xl--line-height: 1;\n --text-6xl: 3.75rem;\n --text-6xl--line-height: 1;\n --text-7xl: 4.5rem;\n --text-7xl--line-height: 1;\n --text-8xl: 6rem;\n --text-8xl--line-height: 1;\n --text-9xl: 8rem;\n --text-9xl--line-height: 1;\n\n --font-weight-thin: 100;\n --font-weight-extralight: 200;\n --font-weight-light: 300;\n --font-weight-normal: 400;\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --font-weight-extrabold: 800;\n --font-weight-black: 900;\n\n --tracking-tighter: -0.05em;\n --tracking-tight: -0.025em;\n --tracking-normal: 0em;\n --tracking-wide: 0.025em;\n --tracking-wider: 0.05em;\n --tracking-widest: 0.1em;\n\n --leading-tight: 1.25;\n --leading-snug: 1.375;\n --leading-normal: 1.5;\n --leading-relaxed: 1.625;\n --leading-loose: 2;\n\n --radius-xs: 0.125rem;\n --radius-sm: 0.25rem;\n --radius-md: 0.375rem;\n --radius-lg: 0.5rem;\n --radius-xl: 0.75rem;\n --radius-2xl: 1rem;\n --radius-3xl: 1.5rem;\n --radius-4xl: 2rem;\n\n --shadow-2xs: 0 1px rgb(0 0 0 / 0.05);\n --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\n --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n\n --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);\n --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);\n --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);\n\n --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);\n --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);\n --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);\n --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);\n --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);\n --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);\n\n --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);\n --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);\n --text-shadow-sm:\n 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075);\n --text-shadow-md:\n 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1);\n --text-shadow-lg:\n 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1);\n\n --ease-in: cubic-bezier(0.4, 0, 1, 1);\n --ease-out: cubic-bezier(0, 0, 0.2, 1);\n --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);\n\n --animate-spin: spin 1s linear infinite;\n --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\n --animate-bounce: bounce 1s infinite;\n\n @keyframes spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n @keyframes ping {\n 75%,\n 100% {\n transform: scale(2);\n opacity: 0;\n }\n }\n\n @keyframes pulse {\n 50% {\n opacity: 0.5;\n }\n }\n\n @keyframes bounce {\n 0%,\n 100% {\n transform: translateY(-25%);\n animation-timing-function: cubic-bezier(0.8, 0, 1, 1);\n }\n\n 50% {\n transform: none;\n animation-timing-function: cubic-bezier(0, 0, 0.2, 1);\n }\n }\n\n --blur-xs: 4px;\n --blur-sm: 8px;\n --blur-md: 12px;\n --blur-lg: 16px;\n --blur-xl: 24px;\n --blur-2xl: 40px;\n --blur-3xl: 64px;\n\n --perspective-dramatic: 100px;\n --perspective-near: 300px;\n --perspective-normal: 500px;\n --perspective-midrange: 800px;\n --perspective-distant: 1200px;\n\n --aspect-video: 16 / 9;\n\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: --theme(--font-sans, initial);\n --default-font-feature-settings: --theme(--font-sans--font-feature-settings, initial);\n --default-font-variation-settings: --theme(--font-sans--font-variation-settings, initial);\n --default-mono-font-family: --theme(--font-mono, initial);\n --default-mono-font-feature-settings: --theme(--font-mono--font-feature-settings, initial);\n --default-mono-font-variation-settings: --theme(--font-mono--font-variation-settings, initial);\n}\n\n/* Deprecated */\n@theme default inline reference {\n --blur: 8px;\n --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);\n --drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06);\n --radius: 0.25rem;\n --max-width-prose: 65ch;\n}\n";
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/utils/tailwind/index.ts
|
|
6
|
+
const compileClasses = async (classes) => {
|
|
7
|
+
if (classes.length === 0) return "";
|
|
8
|
+
return (await compile(`@import "tailwindcss/theme.css" theme(reference); @tailwind utilities;`, { loadStylesheet: async () => ({
|
|
9
|
+
content: theme_css_default,
|
|
10
|
+
base: "",
|
|
11
|
+
path: "tailwindcss/theme.css"
|
|
12
|
+
}) })).build(classes);
|
|
13
|
+
};
|
|
14
|
+
const generateTailwindCSSFromDOM = async (root) => {
|
|
15
|
+
const classes = /* @__PURE__ */ new Set();
|
|
16
|
+
const collect = (el) => {
|
|
17
|
+
el.getAttribute("class")?.split(/\s+/).forEach((cls) => {
|
|
18
|
+
if (cls.trim()) classes.add(cls.trim());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
collect(root);
|
|
22
|
+
root.querySelectorAll("[class]").forEach(collect);
|
|
23
|
+
return compileClasses(Array.from(classes));
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
2
26
|
export { generateTailwindCSSFromDOM };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tailwind-CbjdLyVX.js","names":["themeCSS"],"sources":["../src/utils/tailwind/theme-css.ts","../src/utils/tailwind/index.ts"],"sourcesContent":["// Generated from `tailwindcss/theme.css` (v4.3.3) — do NOT hand-edit.\n//\n// generateTailwindCSS() below compiles arbitrary utility classes typed at\n// runtime (see ~/utils/tailwind), and needs Tailwind's default theme tokens\n// (colors, spacing, font sizes, ...) in scope to resolve anything beyond\n// keyword-only utilities like `text-center`. Importing `tailwindcss/theme.css`\n// directly would need a `?raw`-style loader, which is a Vite convention that\n// tsdown's bundler (used for the published package) doesn't understand —\n// baking the text in as a plain string works with any consumer bundler.\n// Regenerate by re-running the snippet in the commit that added this file\n// after bumping the `tailwindcss` version.\n\nexport default \"@theme default {\\n --font-sans:\\n -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial,\\n sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\\n --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;\\n --font-mono:\\n ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',\\n monospace;\\n\\n --color-red-50: oklch(97.1% 0.013 17.38);\\n --color-red-100: oklch(93.6% 0.032 17.717);\\n --color-red-200: oklch(88.5% 0.062 18.334);\\n --color-red-300: oklch(80.8% 0.114 19.571);\\n --color-red-400: oklch(70.4% 0.191 22.216);\\n --color-red-500: oklch(63.7% 0.237 25.331);\\n --color-red-600: oklch(57.7% 0.245 27.325);\\n --color-red-700: oklch(50.5% 0.213 27.518);\\n --color-red-800: oklch(44.4% 0.177 26.899);\\n --color-red-900: oklch(39.6% 0.141 25.723);\\n --color-red-950: oklch(25.8% 0.092 26.042);\\n\\n --color-orange-50: oklch(98% 0.016 73.684);\\n --color-orange-100: oklch(95.4% 0.038 75.164);\\n --color-orange-200: oklch(90.1% 0.076 70.697);\\n --color-orange-300: oklch(83.7% 0.128 66.29);\\n --color-orange-400: oklch(75% 0.183 55.934);\\n --color-orange-500: oklch(70.5% 0.213 47.604);\\n --color-orange-600: oklch(64.6% 0.222 41.116);\\n --color-orange-700: oklch(55.3% 0.195 38.402);\\n --color-orange-800: oklch(47% 0.157 37.304);\\n --color-orange-900: oklch(40.8% 0.123 38.172);\\n --color-orange-950: oklch(26.6% 0.079 36.259);\\n\\n --color-amber-50: oklch(98.7% 0.022 95.277);\\n --color-amber-100: oklch(96.2% 0.059 95.617);\\n --color-amber-200: oklch(92.4% 0.12 95.746);\\n --color-amber-300: oklch(87.9% 0.169 91.605);\\n --color-amber-400: oklch(82.8% 0.189 84.429);\\n --color-amber-500: oklch(76.9% 0.188 70.08);\\n --color-amber-600: oklch(66.6% 0.179 58.318);\\n --color-amber-700: oklch(55.5% 0.163 48.998);\\n --color-amber-800: oklch(47.3% 0.137 46.201);\\n --color-amber-900: oklch(41.4% 0.112 45.904);\\n --color-amber-950: oklch(27.9% 0.077 45.635);\\n\\n --color-yellow-50: oklch(98.7% 0.026 102.212);\\n --color-yellow-100: oklch(97.3% 0.071 103.193);\\n --color-yellow-200: oklch(94.5% 0.129 101.54);\\n --color-yellow-300: oklch(90.5% 0.182 98.111);\\n --color-yellow-400: oklch(85.2% 0.199 91.936);\\n --color-yellow-500: oklch(79.5% 0.184 86.047);\\n --color-yellow-600: oklch(68.1% 0.162 75.834);\\n --color-yellow-700: oklch(55.4% 0.135 66.442);\\n --color-yellow-800: oklch(47.6% 0.114 61.907);\\n --color-yellow-900: oklch(42.1% 0.095 57.708);\\n --color-yellow-950: oklch(28.6% 0.066 53.813);\\n\\n --color-lime-50: oklch(98.6% 0.031 120.757);\\n --color-lime-100: oklch(96.7% 0.067 122.328);\\n --color-lime-200: oklch(93.8% 0.127 124.321);\\n --color-lime-300: oklch(89.7% 0.196 126.665);\\n --color-lime-400: oklch(84.1% 0.238 128.85);\\n --color-lime-500: oklch(76.8% 0.233 130.85);\\n --color-lime-600: oklch(64.8% 0.2 131.684);\\n --color-lime-700: oklch(53.2% 0.157 131.589);\\n --color-lime-800: oklch(45.3% 0.124 130.933);\\n --color-lime-900: oklch(40.5% 0.101 131.063);\\n --color-lime-950: oklch(27.4% 0.072 132.109);\\n\\n --color-green-50: oklch(98.2% 0.018 155.826);\\n --color-green-100: oklch(96.2% 0.044 156.743);\\n --color-green-200: oklch(92.5% 0.084 155.995);\\n --color-green-300: oklch(87.1% 0.15 154.449);\\n --color-green-400: oklch(79.2% 0.209 151.711);\\n --color-green-500: oklch(72.3% 0.219 149.579);\\n --color-green-600: oklch(62.7% 0.194 149.214);\\n --color-green-700: oklch(52.7% 0.154 150.069);\\n --color-green-800: oklch(44.8% 0.119 151.328);\\n --color-green-900: oklch(39.3% 0.095 152.535);\\n --color-green-950: oklch(26.6% 0.065 152.934);\\n\\n --color-emerald-50: oklch(97.9% 0.021 166.113);\\n --color-emerald-100: oklch(95% 0.052 163.051);\\n --color-emerald-200: oklch(90.5% 0.093 164.15);\\n --color-emerald-300: oklch(84.5% 0.143 164.978);\\n --color-emerald-400: oklch(76.5% 0.177 163.223);\\n --color-emerald-500: oklch(69.6% 0.17 162.48);\\n --color-emerald-600: oklch(59.6% 0.145 163.225);\\n --color-emerald-700: oklch(50.8% 0.118 165.612);\\n --color-emerald-800: oklch(43.2% 0.095 166.913);\\n --color-emerald-900: oklch(37.8% 0.077 168.94);\\n --color-emerald-950: oklch(26.2% 0.051 172.552);\\n\\n --color-teal-50: oklch(98.4% 0.014 180.72);\\n --color-teal-100: oklch(95.3% 0.051 180.801);\\n --color-teal-200: oklch(91% 0.096 180.426);\\n --color-teal-300: oklch(85.5% 0.138 181.071);\\n --color-teal-400: oklch(77.7% 0.152 181.912);\\n --color-teal-500: oklch(70.4% 0.14 182.503);\\n --color-teal-600: oklch(60% 0.118 184.704);\\n --color-teal-700: oklch(51.1% 0.096 186.391);\\n --color-teal-800: oklch(43.7% 0.078 188.216);\\n --color-teal-900: oklch(38.6% 0.063 188.416);\\n --color-teal-950: oklch(27.7% 0.046 192.524);\\n\\n --color-cyan-50: oklch(98.4% 0.019 200.873);\\n --color-cyan-100: oklch(95.6% 0.045 203.388);\\n --color-cyan-200: oklch(91.7% 0.08 205.041);\\n --color-cyan-300: oklch(86.5% 0.127 207.078);\\n --color-cyan-400: oklch(78.9% 0.154 211.53);\\n --color-cyan-500: oklch(71.5% 0.143 215.221);\\n --color-cyan-600: oklch(60.9% 0.126 221.723);\\n --color-cyan-700: oklch(52% 0.105 223.128);\\n --color-cyan-800: oklch(45% 0.085 224.283);\\n --color-cyan-900: oklch(39.8% 0.07 227.392);\\n --color-cyan-950: oklch(30.2% 0.056 229.695);\\n\\n --color-sky-50: oklch(97.7% 0.013 236.62);\\n --color-sky-100: oklch(95.1% 0.026 236.824);\\n --color-sky-200: oklch(90.1% 0.058 230.902);\\n --color-sky-300: oklch(82.8% 0.111 230.318);\\n --color-sky-400: oklch(74.6% 0.16 232.661);\\n --color-sky-500: oklch(68.5% 0.169 237.323);\\n --color-sky-600: oklch(58.8% 0.158 241.966);\\n --color-sky-700: oklch(50% 0.134 242.749);\\n --color-sky-800: oklch(44.3% 0.11 240.79);\\n --color-sky-900: oklch(39.1% 0.09 240.876);\\n --color-sky-950: oklch(29.3% 0.066 243.157);\\n\\n --color-blue-50: oklch(97% 0.014 254.604);\\n --color-blue-100: oklch(93.2% 0.032 255.585);\\n --color-blue-200: oklch(88.2% 0.059 254.128);\\n --color-blue-300: oklch(80.9% 0.105 251.813);\\n --color-blue-400: oklch(70.7% 0.165 254.624);\\n --color-blue-500: oklch(62.3% 0.214 259.815);\\n --color-blue-600: oklch(54.6% 0.245 262.881);\\n --color-blue-700: oklch(48.8% 0.243 264.376);\\n --color-blue-800: oklch(42.4% 0.199 265.638);\\n --color-blue-900: oklch(37.9% 0.146 265.522);\\n --color-blue-950: oklch(28.2% 0.091 267.935);\\n\\n --color-indigo-50: oklch(96.2% 0.018 272.314);\\n --color-indigo-100: oklch(93% 0.034 272.788);\\n --color-indigo-200: oklch(87% 0.065 274.039);\\n --color-indigo-300: oklch(78.5% 0.115 274.713);\\n --color-indigo-400: oklch(67.3% 0.182 276.935);\\n --color-indigo-500: oklch(58.5% 0.233 277.117);\\n --color-indigo-600: oklch(51.1% 0.262 276.966);\\n --color-indigo-700: oklch(45.7% 0.24 277.023);\\n --color-indigo-800: oklch(39.8% 0.195 277.366);\\n --color-indigo-900: oklch(35.9% 0.144 278.697);\\n --color-indigo-950: oklch(25.7% 0.09 281.288);\\n\\n --color-violet-50: oklch(96.9% 0.016 293.756);\\n --color-violet-100: oklch(94.3% 0.029 294.588);\\n --color-violet-200: oklch(89.4% 0.057 293.283);\\n --color-violet-300: oklch(81.1% 0.111 293.571);\\n --color-violet-400: oklch(70.2% 0.183 293.541);\\n --color-violet-500: oklch(60.6% 0.25 292.717);\\n --color-violet-600: oklch(54.1% 0.281 293.009);\\n --color-violet-700: oklch(49.1% 0.27 292.581);\\n --color-violet-800: oklch(43.2% 0.232 292.759);\\n --color-violet-900: oklch(38% 0.189 293.745);\\n --color-violet-950: oklch(28.3% 0.141 291.089);\\n\\n --color-purple-50: oklch(97.7% 0.014 308.299);\\n --color-purple-100: oklch(94.6% 0.033 307.174);\\n --color-purple-200: oklch(90.2% 0.063 306.703);\\n --color-purple-300: oklch(82.7% 0.119 306.383);\\n --color-purple-400: oklch(71.4% 0.203 305.504);\\n --color-purple-500: oklch(62.7% 0.265 303.9);\\n --color-purple-600: oklch(55.8% 0.288 302.321);\\n --color-purple-700: oklch(49.6% 0.265 301.924);\\n --color-purple-800: oklch(43.8% 0.218 303.724);\\n --color-purple-900: oklch(38.1% 0.176 304.987);\\n --color-purple-950: oklch(29.1% 0.149 302.717);\\n\\n --color-fuchsia-50: oklch(97.7% 0.017 320.058);\\n --color-fuchsia-100: oklch(95.2% 0.037 318.852);\\n --color-fuchsia-200: oklch(90.3% 0.076 319.62);\\n --color-fuchsia-300: oklch(83.3% 0.145 321.434);\\n --color-fuchsia-400: oklch(74% 0.238 322.16);\\n --color-fuchsia-500: oklch(66.7% 0.295 322.15);\\n --color-fuchsia-600: oklch(59.1% 0.293 322.896);\\n --color-fuchsia-700: oklch(51.8% 0.253 323.949);\\n --color-fuchsia-800: oklch(45.2% 0.211 324.591);\\n --color-fuchsia-900: oklch(40.1% 0.17 325.612);\\n --color-fuchsia-950: oklch(29.3% 0.136 325.661);\\n\\n --color-pink-50: oklch(97.1% 0.014 343.198);\\n --color-pink-100: oklch(94.8% 0.028 342.258);\\n --color-pink-200: oklch(89.9% 0.061 343.231);\\n --color-pink-300: oklch(82.3% 0.12 346.018);\\n --color-pink-400: oklch(71.8% 0.202 349.761);\\n --color-pink-500: oklch(65.6% 0.241 354.308);\\n --color-pink-600: oklch(59.2% 0.249 0.584);\\n --color-pink-700: oklch(52.5% 0.223 3.958);\\n --color-pink-800: oklch(45.9% 0.187 3.815);\\n --color-pink-900: oklch(40.8% 0.153 2.432);\\n --color-pink-950: oklch(28.4% 0.109 3.907);\\n\\n --color-rose-50: oklch(96.9% 0.015 12.422);\\n --color-rose-100: oklch(94.1% 0.03 12.58);\\n --color-rose-200: oklch(89.2% 0.058 10.001);\\n --color-rose-300: oklch(81% 0.117 11.638);\\n --color-rose-400: oklch(71.2% 0.194 13.428);\\n --color-rose-500: oklch(64.5% 0.246 16.439);\\n --color-rose-600: oklch(58.6% 0.253 17.585);\\n --color-rose-700: oklch(51.4% 0.222 16.935);\\n --color-rose-800: oklch(45.5% 0.188 13.697);\\n --color-rose-900: oklch(41% 0.159 10.272);\\n --color-rose-950: oklch(27.1% 0.105 12.094);\\n\\n --color-slate-50: oklch(98.4% 0.003 247.858);\\n --color-slate-100: oklch(96.8% 0.007 247.896);\\n --color-slate-200: oklch(92.9% 0.013 255.508);\\n --color-slate-300: oklch(86.9% 0.022 252.894);\\n --color-slate-400: oklch(70.4% 0.04 256.788);\\n --color-slate-500: oklch(55.4% 0.046 257.417);\\n --color-slate-600: oklch(44.6% 0.043 257.281);\\n --color-slate-700: oklch(37.2% 0.044 257.287);\\n --color-slate-800: oklch(27.9% 0.041 260.031);\\n --color-slate-900: oklch(20.8% 0.042 265.755);\\n --color-slate-950: oklch(12.9% 0.042 264.695);\\n\\n --color-gray-50: oklch(98.5% 0.002 247.839);\\n --color-gray-100: oklch(96.7% 0.003 264.542);\\n --color-gray-200: oklch(92.8% 0.006 264.531);\\n --color-gray-300: oklch(87.2% 0.01 258.338);\\n --color-gray-400: oklch(70.7% 0.022 261.325);\\n --color-gray-500: oklch(55.1% 0.027 264.364);\\n --color-gray-600: oklch(44.6% 0.03 256.802);\\n --color-gray-700: oklch(37.3% 0.034 259.733);\\n --color-gray-800: oklch(27.8% 0.033 256.848);\\n --color-gray-900: oklch(21% 0.034 264.665);\\n --color-gray-950: oklch(13% 0.028 261.692);\\n\\n --color-zinc-50: oklch(98.5% 0 none);\\n --color-zinc-100: oklch(96.7% 0.001 286.375);\\n --color-zinc-200: oklch(92% 0.004 286.32);\\n --color-zinc-300: oklch(87.1% 0.006 286.286);\\n --color-zinc-400: oklch(70.5% 0.015 286.067);\\n --color-zinc-500: oklch(55.2% 0.016 285.938);\\n --color-zinc-600: oklch(44.2% 0.017 285.786);\\n --color-zinc-700: oklch(37% 0.013 285.805);\\n --color-zinc-800: oklch(27.4% 0.006 286.033);\\n --color-zinc-900: oklch(21% 0.006 285.885);\\n --color-zinc-950: oklch(14.1% 0.005 285.823);\\n\\n --color-neutral-50: oklch(98.5% 0 none);\\n --color-neutral-100: oklch(97% 0 none);\\n --color-neutral-200: oklch(92.2% 0 none);\\n --color-neutral-300: oklch(87% 0 none);\\n --color-neutral-400: oklch(70.8% 0 none);\\n --color-neutral-500: oklch(55.6% 0 none);\\n --color-neutral-600: oklch(43.9% 0 none);\\n --color-neutral-700: oklch(37.1% 0 none);\\n --color-neutral-800: oklch(26.9% 0 none);\\n --color-neutral-900: oklch(20.5% 0 none);\\n --color-neutral-950: oklch(14.5% 0 none);\\n\\n --color-stone-50: oklch(98.5% 0.001 106.423);\\n --color-stone-100: oklch(97% 0.001 106.424);\\n --color-stone-200: oklch(92.3% 0.003 48.717);\\n --color-stone-300: oklch(86.9% 0.005 56.366);\\n --color-stone-400: oklch(70.9% 0.01 56.259);\\n --color-stone-500: oklch(55.3% 0.013 58.071);\\n --color-stone-600: oklch(44.4% 0.011 73.639);\\n --color-stone-700: oklch(37.4% 0.01 67.558);\\n --color-stone-800: oklch(26.8% 0.007 34.298);\\n --color-stone-900: oklch(21.6% 0.006 56.043);\\n --color-stone-950: oklch(14.7% 0.004 49.25);\\n\\n --color-mauve-50: oklch(98.5% 0 none);\\n --color-mauve-100: oklch(96% 0.003 325.6);\\n --color-mauve-200: oklch(92.2% 0.005 325.62);\\n --color-mauve-300: oklch(86.5% 0.012 325.68);\\n --color-mauve-400: oklch(71.1% 0.019 323.02);\\n --color-mauve-500: oklch(54.2% 0.034 322.5);\\n --color-mauve-600: oklch(43.5% 0.029 321.78);\\n --color-mauve-700: oklch(36.4% 0.029 323.89);\\n --color-mauve-800: oklch(26.3% 0.024 320.12);\\n --color-mauve-900: oklch(21.2% 0.019 322.12);\\n --color-mauve-950: oklch(14.5% 0.008 326);\\n\\n --color-olive-50: oklch(98.8% 0.003 106.5);\\n --color-olive-100: oklch(96.6% 0.005 106.5);\\n --color-olive-200: oklch(93% 0.007 106.5);\\n --color-olive-300: oklch(88% 0.011 106.6);\\n --color-olive-400: oklch(73.7% 0.021 106.9);\\n --color-olive-500: oklch(58% 0.031 107.3);\\n --color-olive-600: oklch(46.6% 0.025 107.3);\\n --color-olive-700: oklch(39.4% 0.023 107.4);\\n --color-olive-800: oklch(28.6% 0.016 107.4);\\n --color-olive-900: oklch(22.8% 0.013 107.4);\\n --color-olive-950: oklch(15.3% 0.006 107.1);\\n\\n --color-mist-50: oklch(98.7% 0.002 197.1);\\n --color-mist-100: oklch(96.3% 0.002 197.1);\\n --color-mist-200: oklch(92.5% 0.005 214.3);\\n --color-mist-300: oklch(87.2% 0.007 219.6);\\n --color-mist-400: oklch(72.3% 0.014 214.4);\\n --color-mist-500: oklch(56% 0.021 213.5);\\n --color-mist-600: oklch(45% 0.017 213.2);\\n --color-mist-700: oklch(37.8% 0.015 216);\\n --color-mist-800: oklch(27.5% 0.011 216.9);\\n --color-mist-900: oklch(21.8% 0.008 223.9);\\n --color-mist-950: oklch(14.8% 0.004 228.8);\\n\\n --color-taupe-50: oklch(98.6% 0.002 67.8);\\n --color-taupe-100: oklch(96% 0.002 17.2);\\n --color-taupe-200: oklch(92.2% 0.005 34.3);\\n --color-taupe-300: oklch(86.8% 0.007 39.5);\\n --color-taupe-400: oklch(71.4% 0.014 41.2);\\n --color-taupe-500: oklch(54.7% 0.021 43.1);\\n --color-taupe-600: oklch(43.8% 0.017 39.3);\\n --color-taupe-700: oklch(36.7% 0.016 35.7);\\n --color-taupe-800: oklch(26.8% 0.011 36.5);\\n --color-taupe-900: oklch(21.4% 0.009 43.1);\\n --color-taupe-950: oklch(14.7% 0.004 49.3);\\n\\n --color-black: #000;\\n --color-white: #fff;\\n\\n --spacing: 0.25rem;\\n\\n --breakpoint-sm: 40rem;\\n --breakpoint-md: 48rem;\\n --breakpoint-lg: 64rem;\\n --breakpoint-xl: 80rem;\\n --breakpoint-2xl: 96rem;\\n\\n --container-3xs: 16rem;\\n --container-2xs: 18rem;\\n --container-xs: 20rem;\\n --container-sm: 24rem;\\n --container-md: 28rem;\\n --container-lg: 32rem;\\n --container-xl: 36rem;\\n --container-2xl: 42rem;\\n --container-3xl: 48rem;\\n --container-4xl: 56rem;\\n --container-5xl: 64rem;\\n --container-6xl: 72rem;\\n --container-7xl: 80rem;\\n\\n --text-xs: 0.75rem;\\n --text-xs--line-height: calc(1 / 0.75);\\n --text-sm: 0.875rem;\\n --text-sm--line-height: calc(1.25 / 0.875);\\n --text-base: 1rem;\\n --text-base--line-height: calc(1.5 / 1);\\n --text-lg: 1.125rem;\\n --text-lg--line-height: calc(1.75 / 1.125);\\n --text-xl: 1.25rem;\\n --text-xl--line-height: calc(1.75 / 1.25);\\n --text-2xl: 1.5rem;\\n --text-2xl--line-height: calc(2 / 1.5);\\n --text-3xl: 1.875rem;\\n --text-3xl--line-height: calc(2.25 / 1.875);\\n --text-4xl: 2.25rem;\\n --text-4xl--line-height: calc(2.5 / 2.25);\\n --text-5xl: 3rem;\\n --text-5xl--line-height: 1;\\n --text-6xl: 3.75rem;\\n --text-6xl--line-height: 1;\\n --text-7xl: 4.5rem;\\n --text-7xl--line-height: 1;\\n --text-8xl: 6rem;\\n --text-8xl--line-height: 1;\\n --text-9xl: 8rem;\\n --text-9xl--line-height: 1;\\n\\n --font-weight-thin: 100;\\n --font-weight-extralight: 200;\\n --font-weight-light: 300;\\n --font-weight-normal: 400;\\n --font-weight-medium: 500;\\n --font-weight-semibold: 600;\\n --font-weight-bold: 700;\\n --font-weight-extrabold: 800;\\n --font-weight-black: 900;\\n\\n --tracking-tighter: -0.05em;\\n --tracking-tight: -0.025em;\\n --tracking-normal: 0em;\\n --tracking-wide: 0.025em;\\n --tracking-wider: 0.05em;\\n --tracking-widest: 0.1em;\\n\\n --leading-tight: 1.25;\\n --leading-snug: 1.375;\\n --leading-normal: 1.5;\\n --leading-relaxed: 1.625;\\n --leading-loose: 2;\\n\\n --radius-xs: 0.125rem;\\n --radius-sm: 0.25rem;\\n --radius-md: 0.375rem;\\n --radius-lg: 0.5rem;\\n --radius-xl: 0.75rem;\\n --radius-2xl: 1rem;\\n --radius-3xl: 1.5rem;\\n --radius-4xl: 2rem;\\n\\n --shadow-2xs: 0 1px rgb(0 0 0 / 0.05);\\n --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);\\n --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\\n --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\\n --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\\n --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\\n --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);\\n\\n --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);\\n --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);\\n --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);\\n\\n --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);\\n --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);\\n --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);\\n --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);\\n --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);\\n --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);\\n\\n --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);\\n --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);\\n --text-shadow-sm:\\n 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075);\\n --text-shadow-md:\\n 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1);\\n --text-shadow-lg:\\n 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1);\\n\\n --ease-in: cubic-bezier(0.4, 0, 1, 1);\\n --ease-out: cubic-bezier(0, 0, 0.2, 1);\\n --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);\\n\\n --animate-spin: spin 1s linear infinite;\\n --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\\n --animate-bounce: bounce 1s infinite;\\n\\n @keyframes spin {\\n to {\\n transform: rotate(360deg);\\n }\\n }\\n\\n @keyframes ping {\\n 75%,\\n 100% {\\n transform: scale(2);\\n opacity: 0;\\n }\\n }\\n\\n @keyframes pulse {\\n 50% {\\n opacity: 0.5;\\n }\\n }\\n\\n @keyframes bounce {\\n 0%,\\n 100% {\\n transform: translateY(-25%);\\n animation-timing-function: cubic-bezier(0.8, 0, 1, 1);\\n }\\n\\n 50% {\\n transform: none;\\n animation-timing-function: cubic-bezier(0, 0, 0.2, 1);\\n }\\n }\\n\\n --blur-xs: 4px;\\n --blur-sm: 8px;\\n --blur-md: 12px;\\n --blur-lg: 16px;\\n --blur-xl: 24px;\\n --blur-2xl: 40px;\\n --blur-3xl: 64px;\\n\\n --perspective-dramatic: 100px;\\n --perspective-near: 300px;\\n --perspective-normal: 500px;\\n --perspective-midrange: 800px;\\n --perspective-distant: 1200px;\\n\\n --aspect-video: 16 / 9;\\n\\n --default-transition-duration: 150ms;\\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\\n --default-font-family: --theme(--font-sans, initial);\\n --default-font-feature-settings: --theme(--font-sans--font-feature-settings, initial);\\n --default-font-variation-settings: --theme(--font-sans--font-variation-settings, initial);\\n --default-mono-font-family: --theme(--font-mono, initial);\\n --default-mono-font-feature-settings: --theme(--font-mono--font-feature-settings, initial);\\n --default-mono-font-variation-settings: --theme(--font-mono--font-variation-settings, initial);\\n}\\n\\n/* Deprecated */\\n@theme default inline reference {\\n --blur: 8px;\\n --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\\n --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);\\n --drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06);\\n --radius: 0.25rem;\\n --max-width-prose: 65ch;\\n}\\n\";\n","import { compile } from 'tailwindcss';\n\n// Loaded as `theme(reference)` below so utilities can resolve theme-dependent\n// values (colors, spacing, font sizes, ...) without re-emitting the `@theme`\n// block itself — see https://tailwindcss.com/docs/functions-and-directives#reference-directive.\n// A checked-in copy (not a `?raw` import of the real file) because `?raw` is\n// a Vite convention tsdown's bundler doesn't resolve, which would otherwise\n// ship an unresolved specifier in dist/ that breaks for non-Vite consumers.\nimport themeCSS from './theme-css';\n\nconst compileClasses = async (classes: string[]): Promise<string> => {\n if (classes.length === 0) {\n return '';\n }\n\n const compiler = await compile(\n `@import \"tailwindcss/theme.css\" theme(reference); @tailwind utilities;`,\n {\n loadStylesheet: async () => ({\n content: themeCSS,\n base: '',\n path: 'tailwindcss/theme.css',\n }),\n },\n );\n\n return compiler.build(classes);\n};\n\n// Scans an already-rendered DOM subtree for `class` attributes, rather than\n// regex-scanning the compiled source text. Source-text scanning can only see\n// classes the reader typed literally (e.g. `className=\"p-6\"`) — it has no\n// way to know what classes an imported component (e.g. ui-kit's `Button`,\n// `Typography.Title`) renders internally, since those live in that\n// component's own compiled output, not the previewed source. Scanning the\n// real DOM after mount catches both, because by then every class — reader-\n// authored or contributed by a component — is actually present as an\n// attribute.\nexport const generateTailwindCSSFromDOM = async (\n root: Element,\n): Promise<string> => {\n const classes = new Set<string>();\n\n const collect = (el: Element) => {\n el.getAttribute('class')\n ?.split(/\\s+/)\n .forEach(cls => {\n if (cls.trim()) {\n classes.add(cls.trim());\n }\n });\n };\n\n collect(root);\n root.querySelectorAll('[class]').forEach(collect);\n\n return compileClasses(Array.from(classes));\n};\n"],"mappings":";;AAYA,IAAA,oBAAe;;;ACFf,MAAM,iBAAiB,OAAO,YAAuC;CACnE,IAAI,QAAQ,WAAW,GACrB,OAAO;CAcT,QAAO,MAXgB,QACrB,0EACA,EACE,gBAAgB,aAAa;EAC3B,SAASA;EACT,MAAM;EACN,MAAM;CACR,GACF,CACF,EAAA,CAEgB,MAAM,OAAO;AAC/B;AAWA,MAAa,6BAA6B,OACxC,SACoB;CACpB,MAAM,0BAAU,IAAI,IAAY;CAEhC,MAAM,WAAW,OAAgB;EAC/B,GAAG,aAAa,OAAO,CAAC,EACpB,MAAM,KAAK,CAAC,CACb,SAAQ,QAAO;GACd,IAAI,IAAI,KAAK,GACX,QAAQ,IAAI,IAAI,KAAK,CAAC;EAE1B,CAAC;CACL;CAEA,QAAQ,IAAI;CACZ,KAAK,iBAAiB,SAAS,CAAC,CAAC,QAAQ,OAAO;CAEhD,OAAO,eAAe,MAAM,KAAK,OAAO,CAAC;AAC3C"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["themeCSS"],"sources":["../../../src/utils/tailwind/theme-css.ts","../../../src/utils/tailwind/index.ts"],"sourcesContent":["// Generated from `tailwindcss/theme.css` (v4.3.3) — do NOT hand-edit.\n//\n// generateTailwindCSS() below compiles arbitrary utility classes typed at\n// runtime (see ~/utils/tailwind), and needs Tailwind's default theme tokens\n// (colors, spacing, font sizes, ...) in scope to resolve anything beyond\n// keyword-only utilities like `text-center`. Importing `tailwindcss/theme.css`\n// directly would need a `?raw`-style loader, which is a Vite convention that\n// tsdown's bundler (used for the published package) doesn't understand —\n// baking the text in as a plain string works with any consumer bundler.\n// Regenerate by re-running the snippet in the commit that added this file\n// after bumping the `tailwindcss` version.\n\nexport default \"@theme default {\\n --font-sans:\\n -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial,\\n sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\\n --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;\\n --font-mono:\\n ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',\\n monospace;\\n\\n --color-red-50: oklch(97.1% 0.013 17.38);\\n --color-red-100: oklch(93.6% 0.032 17.717);\\n --color-red-200: oklch(88.5% 0.062 18.334);\\n --color-red-300: oklch(80.8% 0.114 19.571);\\n --color-red-400: oklch(70.4% 0.191 22.216);\\n --color-red-500: oklch(63.7% 0.237 25.331);\\n --color-red-600: oklch(57.7% 0.245 27.325);\\n --color-red-700: oklch(50.5% 0.213 27.518);\\n --color-red-800: oklch(44.4% 0.177 26.899);\\n --color-red-900: oklch(39.6% 0.141 25.723);\\n --color-red-950: oklch(25.8% 0.092 26.042);\\n\\n --color-orange-50: oklch(98% 0.016 73.684);\\n --color-orange-100: oklch(95.4% 0.038 75.164);\\n --color-orange-200: oklch(90.1% 0.076 70.697);\\n --color-orange-300: oklch(83.7% 0.128 66.29);\\n --color-orange-400: oklch(75% 0.183 55.934);\\n --color-orange-500: oklch(70.5% 0.213 47.604);\\n --color-orange-600: oklch(64.6% 0.222 41.116);\\n --color-orange-700: oklch(55.3% 0.195 38.402);\\n --color-orange-800: oklch(47% 0.157 37.304);\\n --color-orange-900: oklch(40.8% 0.123 38.172);\\n --color-orange-950: oklch(26.6% 0.079 36.259);\\n\\n --color-amber-50: oklch(98.7% 0.022 95.277);\\n --color-amber-100: oklch(96.2% 0.059 95.617);\\n --color-amber-200: oklch(92.4% 0.12 95.746);\\n --color-amber-300: oklch(87.9% 0.169 91.605);\\n --color-amber-400: oklch(82.8% 0.189 84.429);\\n --color-amber-500: oklch(76.9% 0.188 70.08);\\n --color-amber-600: oklch(66.6% 0.179 58.318);\\n --color-amber-700: oklch(55.5% 0.163 48.998);\\n --color-amber-800: oklch(47.3% 0.137 46.201);\\n --color-amber-900: oklch(41.4% 0.112 45.904);\\n --color-amber-950: oklch(27.9% 0.077 45.635);\\n\\n --color-yellow-50: oklch(98.7% 0.026 102.212);\\n --color-yellow-100: oklch(97.3% 0.071 103.193);\\n --color-yellow-200: oklch(94.5% 0.129 101.54);\\n --color-yellow-300: oklch(90.5% 0.182 98.111);\\n --color-yellow-400: oklch(85.2% 0.199 91.936);\\n --color-yellow-500: oklch(79.5% 0.184 86.047);\\n --color-yellow-600: oklch(68.1% 0.162 75.834);\\n --color-yellow-700: oklch(55.4% 0.135 66.442);\\n --color-yellow-800: oklch(47.6% 0.114 61.907);\\n --color-yellow-900: oklch(42.1% 0.095 57.708);\\n --color-yellow-950: oklch(28.6% 0.066 53.813);\\n\\n --color-lime-50: oklch(98.6% 0.031 120.757);\\n --color-lime-100: oklch(96.7% 0.067 122.328);\\n --color-lime-200: oklch(93.8% 0.127 124.321);\\n --color-lime-300: oklch(89.7% 0.196 126.665);\\n --color-lime-400: oklch(84.1% 0.238 128.85);\\n --color-lime-500: oklch(76.8% 0.233 130.85);\\n --color-lime-600: oklch(64.8% 0.2 131.684);\\n --color-lime-700: oklch(53.2% 0.157 131.589);\\n --color-lime-800: oklch(45.3% 0.124 130.933);\\n --color-lime-900: oklch(40.5% 0.101 131.063);\\n --color-lime-950: oklch(27.4% 0.072 132.109);\\n\\n --color-green-50: oklch(98.2% 0.018 155.826);\\n --color-green-100: oklch(96.2% 0.044 156.743);\\n --color-green-200: oklch(92.5% 0.084 155.995);\\n --color-green-300: oklch(87.1% 0.15 154.449);\\n --color-green-400: oklch(79.2% 0.209 151.711);\\n --color-green-500: oklch(72.3% 0.219 149.579);\\n --color-green-600: oklch(62.7% 0.194 149.214);\\n --color-green-700: oklch(52.7% 0.154 150.069);\\n --color-green-800: oklch(44.8% 0.119 151.328);\\n --color-green-900: oklch(39.3% 0.095 152.535);\\n --color-green-950: oklch(26.6% 0.065 152.934);\\n\\n --color-emerald-50: oklch(97.9% 0.021 166.113);\\n --color-emerald-100: oklch(95% 0.052 163.051);\\n --color-emerald-200: oklch(90.5% 0.093 164.15);\\n --color-emerald-300: oklch(84.5% 0.143 164.978);\\n --color-emerald-400: oklch(76.5% 0.177 163.223);\\n --color-emerald-500: oklch(69.6% 0.17 162.48);\\n --color-emerald-600: oklch(59.6% 0.145 163.225);\\n --color-emerald-700: oklch(50.8% 0.118 165.612);\\n --color-emerald-800: oklch(43.2% 0.095 166.913);\\n --color-emerald-900: oklch(37.8% 0.077 168.94);\\n --color-emerald-950: oklch(26.2% 0.051 172.552);\\n\\n --color-teal-50: oklch(98.4% 0.014 180.72);\\n --color-teal-100: oklch(95.3% 0.051 180.801);\\n --color-teal-200: oklch(91% 0.096 180.426);\\n --color-teal-300: oklch(85.5% 0.138 181.071);\\n --color-teal-400: oklch(77.7% 0.152 181.912);\\n --color-teal-500: oklch(70.4% 0.14 182.503);\\n --color-teal-600: oklch(60% 0.118 184.704);\\n --color-teal-700: oklch(51.1% 0.096 186.391);\\n --color-teal-800: oklch(43.7% 0.078 188.216);\\n --color-teal-900: oklch(38.6% 0.063 188.416);\\n --color-teal-950: oklch(27.7% 0.046 192.524);\\n\\n --color-cyan-50: oklch(98.4% 0.019 200.873);\\n --color-cyan-100: oklch(95.6% 0.045 203.388);\\n --color-cyan-200: oklch(91.7% 0.08 205.041);\\n --color-cyan-300: oklch(86.5% 0.127 207.078);\\n --color-cyan-400: oklch(78.9% 0.154 211.53);\\n --color-cyan-500: oklch(71.5% 0.143 215.221);\\n --color-cyan-600: oklch(60.9% 0.126 221.723);\\n --color-cyan-700: oklch(52% 0.105 223.128);\\n --color-cyan-800: oklch(45% 0.085 224.283);\\n --color-cyan-900: oklch(39.8% 0.07 227.392);\\n --color-cyan-950: oklch(30.2% 0.056 229.695);\\n\\n --color-sky-50: oklch(97.7% 0.013 236.62);\\n --color-sky-100: oklch(95.1% 0.026 236.824);\\n --color-sky-200: oklch(90.1% 0.058 230.902);\\n --color-sky-300: oklch(82.8% 0.111 230.318);\\n --color-sky-400: oklch(74.6% 0.16 232.661);\\n --color-sky-500: oklch(68.5% 0.169 237.323);\\n --color-sky-600: oklch(58.8% 0.158 241.966);\\n --color-sky-700: oklch(50% 0.134 242.749);\\n --color-sky-800: oklch(44.3% 0.11 240.79);\\n --color-sky-900: oklch(39.1% 0.09 240.876);\\n --color-sky-950: oklch(29.3% 0.066 243.157);\\n\\n --color-blue-50: oklch(97% 0.014 254.604);\\n --color-blue-100: oklch(93.2% 0.032 255.585);\\n --color-blue-200: oklch(88.2% 0.059 254.128);\\n --color-blue-300: oklch(80.9% 0.105 251.813);\\n --color-blue-400: oklch(70.7% 0.165 254.624);\\n --color-blue-500: oklch(62.3% 0.214 259.815);\\n --color-blue-600: oklch(54.6% 0.245 262.881);\\n --color-blue-700: oklch(48.8% 0.243 264.376);\\n --color-blue-800: oklch(42.4% 0.199 265.638);\\n --color-blue-900: oklch(37.9% 0.146 265.522);\\n --color-blue-950: oklch(28.2% 0.091 267.935);\\n\\n --color-indigo-50: oklch(96.2% 0.018 272.314);\\n --color-indigo-100: oklch(93% 0.034 272.788);\\n --color-indigo-200: oklch(87% 0.065 274.039);\\n --color-indigo-300: oklch(78.5% 0.115 274.713);\\n --color-indigo-400: oklch(67.3% 0.182 276.935);\\n --color-indigo-500: oklch(58.5% 0.233 277.117);\\n --color-indigo-600: oklch(51.1% 0.262 276.966);\\n --color-indigo-700: oklch(45.7% 0.24 277.023);\\n --color-indigo-800: oklch(39.8% 0.195 277.366);\\n --color-indigo-900: oklch(35.9% 0.144 278.697);\\n --color-indigo-950: oklch(25.7% 0.09 281.288);\\n\\n --color-violet-50: oklch(96.9% 0.016 293.756);\\n --color-violet-100: oklch(94.3% 0.029 294.588);\\n --color-violet-200: oklch(89.4% 0.057 293.283);\\n --color-violet-300: oklch(81.1% 0.111 293.571);\\n --color-violet-400: oklch(70.2% 0.183 293.541);\\n --color-violet-500: oklch(60.6% 0.25 292.717);\\n --color-violet-600: oklch(54.1% 0.281 293.009);\\n --color-violet-700: oklch(49.1% 0.27 292.581);\\n --color-violet-800: oklch(43.2% 0.232 292.759);\\n --color-violet-900: oklch(38% 0.189 293.745);\\n --color-violet-950: oklch(28.3% 0.141 291.089);\\n\\n --color-purple-50: oklch(97.7% 0.014 308.299);\\n --color-purple-100: oklch(94.6% 0.033 307.174);\\n --color-purple-200: oklch(90.2% 0.063 306.703);\\n --color-purple-300: oklch(82.7% 0.119 306.383);\\n --color-purple-400: oklch(71.4% 0.203 305.504);\\n --color-purple-500: oklch(62.7% 0.265 303.9);\\n --color-purple-600: oklch(55.8% 0.288 302.321);\\n --color-purple-700: oklch(49.6% 0.265 301.924);\\n --color-purple-800: oklch(43.8% 0.218 303.724);\\n --color-purple-900: oklch(38.1% 0.176 304.987);\\n --color-purple-950: oklch(29.1% 0.149 302.717);\\n\\n --color-fuchsia-50: oklch(97.7% 0.017 320.058);\\n --color-fuchsia-100: oklch(95.2% 0.037 318.852);\\n --color-fuchsia-200: oklch(90.3% 0.076 319.62);\\n --color-fuchsia-300: oklch(83.3% 0.145 321.434);\\n --color-fuchsia-400: oklch(74% 0.238 322.16);\\n --color-fuchsia-500: oklch(66.7% 0.295 322.15);\\n --color-fuchsia-600: oklch(59.1% 0.293 322.896);\\n --color-fuchsia-700: oklch(51.8% 0.253 323.949);\\n --color-fuchsia-800: oklch(45.2% 0.211 324.591);\\n --color-fuchsia-900: oklch(40.1% 0.17 325.612);\\n --color-fuchsia-950: oklch(29.3% 0.136 325.661);\\n\\n --color-pink-50: oklch(97.1% 0.014 343.198);\\n --color-pink-100: oklch(94.8% 0.028 342.258);\\n --color-pink-200: oklch(89.9% 0.061 343.231);\\n --color-pink-300: oklch(82.3% 0.12 346.018);\\n --color-pink-400: oklch(71.8% 0.202 349.761);\\n --color-pink-500: oklch(65.6% 0.241 354.308);\\n --color-pink-600: oklch(59.2% 0.249 0.584);\\n --color-pink-700: oklch(52.5% 0.223 3.958);\\n --color-pink-800: oklch(45.9% 0.187 3.815);\\n --color-pink-900: oklch(40.8% 0.153 2.432);\\n --color-pink-950: oklch(28.4% 0.109 3.907);\\n\\n --color-rose-50: oklch(96.9% 0.015 12.422);\\n --color-rose-100: oklch(94.1% 0.03 12.58);\\n --color-rose-200: oklch(89.2% 0.058 10.001);\\n --color-rose-300: oklch(81% 0.117 11.638);\\n --color-rose-400: oklch(71.2% 0.194 13.428);\\n --color-rose-500: oklch(64.5% 0.246 16.439);\\n --color-rose-600: oklch(58.6% 0.253 17.585);\\n --color-rose-700: oklch(51.4% 0.222 16.935);\\n --color-rose-800: oklch(45.5% 0.188 13.697);\\n --color-rose-900: oklch(41% 0.159 10.272);\\n --color-rose-950: oklch(27.1% 0.105 12.094);\\n\\n --color-slate-50: oklch(98.4% 0.003 247.858);\\n --color-slate-100: oklch(96.8% 0.007 247.896);\\n --color-slate-200: oklch(92.9% 0.013 255.508);\\n --color-slate-300: oklch(86.9% 0.022 252.894);\\n --color-slate-400: oklch(70.4% 0.04 256.788);\\n --color-slate-500: oklch(55.4% 0.046 257.417);\\n --color-slate-600: oklch(44.6% 0.043 257.281);\\n --color-slate-700: oklch(37.2% 0.044 257.287);\\n --color-slate-800: oklch(27.9% 0.041 260.031);\\n --color-slate-900: oklch(20.8% 0.042 265.755);\\n --color-slate-950: oklch(12.9% 0.042 264.695);\\n\\n --color-gray-50: oklch(98.5% 0.002 247.839);\\n --color-gray-100: oklch(96.7% 0.003 264.542);\\n --color-gray-200: oklch(92.8% 0.006 264.531);\\n --color-gray-300: oklch(87.2% 0.01 258.338);\\n --color-gray-400: oklch(70.7% 0.022 261.325);\\n --color-gray-500: oklch(55.1% 0.027 264.364);\\n --color-gray-600: oklch(44.6% 0.03 256.802);\\n --color-gray-700: oklch(37.3% 0.034 259.733);\\n --color-gray-800: oklch(27.8% 0.033 256.848);\\n --color-gray-900: oklch(21% 0.034 264.665);\\n --color-gray-950: oklch(13% 0.028 261.692);\\n\\n --color-zinc-50: oklch(98.5% 0 none);\\n --color-zinc-100: oklch(96.7% 0.001 286.375);\\n --color-zinc-200: oklch(92% 0.004 286.32);\\n --color-zinc-300: oklch(87.1% 0.006 286.286);\\n --color-zinc-400: oklch(70.5% 0.015 286.067);\\n --color-zinc-500: oklch(55.2% 0.016 285.938);\\n --color-zinc-600: oklch(44.2% 0.017 285.786);\\n --color-zinc-700: oklch(37% 0.013 285.805);\\n --color-zinc-800: oklch(27.4% 0.006 286.033);\\n --color-zinc-900: oklch(21% 0.006 285.885);\\n --color-zinc-950: oklch(14.1% 0.005 285.823);\\n\\n --color-neutral-50: oklch(98.5% 0 none);\\n --color-neutral-100: oklch(97% 0 none);\\n --color-neutral-200: oklch(92.2% 0 none);\\n --color-neutral-300: oklch(87% 0 none);\\n --color-neutral-400: oklch(70.8% 0 none);\\n --color-neutral-500: oklch(55.6% 0 none);\\n --color-neutral-600: oklch(43.9% 0 none);\\n --color-neutral-700: oklch(37.1% 0 none);\\n --color-neutral-800: oklch(26.9% 0 none);\\n --color-neutral-900: oklch(20.5% 0 none);\\n --color-neutral-950: oklch(14.5% 0 none);\\n\\n --color-stone-50: oklch(98.5% 0.001 106.423);\\n --color-stone-100: oklch(97% 0.001 106.424);\\n --color-stone-200: oklch(92.3% 0.003 48.717);\\n --color-stone-300: oklch(86.9% 0.005 56.366);\\n --color-stone-400: oklch(70.9% 0.01 56.259);\\n --color-stone-500: oklch(55.3% 0.013 58.071);\\n --color-stone-600: oklch(44.4% 0.011 73.639);\\n --color-stone-700: oklch(37.4% 0.01 67.558);\\n --color-stone-800: oklch(26.8% 0.007 34.298);\\n --color-stone-900: oklch(21.6% 0.006 56.043);\\n --color-stone-950: oklch(14.7% 0.004 49.25);\\n\\n --color-mauve-50: oklch(98.5% 0 none);\\n --color-mauve-100: oklch(96% 0.003 325.6);\\n --color-mauve-200: oklch(92.2% 0.005 325.62);\\n --color-mauve-300: oklch(86.5% 0.012 325.68);\\n --color-mauve-400: oklch(71.1% 0.019 323.02);\\n --color-mauve-500: oklch(54.2% 0.034 322.5);\\n --color-mauve-600: oklch(43.5% 0.029 321.78);\\n --color-mauve-700: oklch(36.4% 0.029 323.89);\\n --color-mauve-800: oklch(26.3% 0.024 320.12);\\n --color-mauve-900: oklch(21.2% 0.019 322.12);\\n --color-mauve-950: oklch(14.5% 0.008 326);\\n\\n --color-olive-50: oklch(98.8% 0.003 106.5);\\n --color-olive-100: oklch(96.6% 0.005 106.5);\\n --color-olive-200: oklch(93% 0.007 106.5);\\n --color-olive-300: oklch(88% 0.011 106.6);\\n --color-olive-400: oklch(73.7% 0.021 106.9);\\n --color-olive-500: oklch(58% 0.031 107.3);\\n --color-olive-600: oklch(46.6% 0.025 107.3);\\n --color-olive-700: oklch(39.4% 0.023 107.4);\\n --color-olive-800: oklch(28.6% 0.016 107.4);\\n --color-olive-900: oklch(22.8% 0.013 107.4);\\n --color-olive-950: oklch(15.3% 0.006 107.1);\\n\\n --color-mist-50: oklch(98.7% 0.002 197.1);\\n --color-mist-100: oklch(96.3% 0.002 197.1);\\n --color-mist-200: oklch(92.5% 0.005 214.3);\\n --color-mist-300: oklch(87.2% 0.007 219.6);\\n --color-mist-400: oklch(72.3% 0.014 214.4);\\n --color-mist-500: oklch(56% 0.021 213.5);\\n --color-mist-600: oklch(45% 0.017 213.2);\\n --color-mist-700: oklch(37.8% 0.015 216);\\n --color-mist-800: oklch(27.5% 0.011 216.9);\\n --color-mist-900: oklch(21.8% 0.008 223.9);\\n --color-mist-950: oklch(14.8% 0.004 228.8);\\n\\n --color-taupe-50: oklch(98.6% 0.002 67.8);\\n --color-taupe-100: oklch(96% 0.002 17.2);\\n --color-taupe-200: oklch(92.2% 0.005 34.3);\\n --color-taupe-300: oklch(86.8% 0.007 39.5);\\n --color-taupe-400: oklch(71.4% 0.014 41.2);\\n --color-taupe-500: oklch(54.7% 0.021 43.1);\\n --color-taupe-600: oklch(43.8% 0.017 39.3);\\n --color-taupe-700: oklch(36.7% 0.016 35.7);\\n --color-taupe-800: oklch(26.8% 0.011 36.5);\\n --color-taupe-900: oklch(21.4% 0.009 43.1);\\n --color-taupe-950: oklch(14.7% 0.004 49.3);\\n\\n --color-black: #000;\\n --color-white: #fff;\\n\\n --spacing: 0.25rem;\\n\\n --breakpoint-sm: 40rem;\\n --breakpoint-md: 48rem;\\n --breakpoint-lg: 64rem;\\n --breakpoint-xl: 80rem;\\n --breakpoint-2xl: 96rem;\\n\\n --container-3xs: 16rem;\\n --container-2xs: 18rem;\\n --container-xs: 20rem;\\n --container-sm: 24rem;\\n --container-md: 28rem;\\n --container-lg: 32rem;\\n --container-xl: 36rem;\\n --container-2xl: 42rem;\\n --container-3xl: 48rem;\\n --container-4xl: 56rem;\\n --container-5xl: 64rem;\\n --container-6xl: 72rem;\\n --container-7xl: 80rem;\\n\\n --text-xs: 0.75rem;\\n --text-xs--line-height: calc(1 / 0.75);\\n --text-sm: 0.875rem;\\n --text-sm--line-height: calc(1.25 / 0.875);\\n --text-base: 1rem;\\n --text-base--line-height: calc(1.5 / 1);\\n --text-lg: 1.125rem;\\n --text-lg--line-height: calc(1.75 / 1.125);\\n --text-xl: 1.25rem;\\n --text-xl--line-height: calc(1.75 / 1.25);\\n --text-2xl: 1.5rem;\\n --text-2xl--line-height: calc(2 / 1.5);\\n --text-3xl: 1.875rem;\\n --text-3xl--line-height: calc(2.25 / 1.875);\\n --text-4xl: 2.25rem;\\n --text-4xl--line-height: calc(2.5 / 2.25);\\n --text-5xl: 3rem;\\n --text-5xl--line-height: 1;\\n --text-6xl: 3.75rem;\\n --text-6xl--line-height: 1;\\n --text-7xl: 4.5rem;\\n --text-7xl--line-height: 1;\\n --text-8xl: 6rem;\\n --text-8xl--line-height: 1;\\n --text-9xl: 8rem;\\n --text-9xl--line-height: 1;\\n\\n --font-weight-thin: 100;\\n --font-weight-extralight: 200;\\n --font-weight-light: 300;\\n --font-weight-normal: 400;\\n --font-weight-medium: 500;\\n --font-weight-semibold: 600;\\n --font-weight-bold: 700;\\n --font-weight-extrabold: 800;\\n --font-weight-black: 900;\\n\\n --tracking-tighter: -0.05em;\\n --tracking-tight: -0.025em;\\n --tracking-normal: 0em;\\n --tracking-wide: 0.025em;\\n --tracking-wider: 0.05em;\\n --tracking-widest: 0.1em;\\n\\n --leading-tight: 1.25;\\n --leading-snug: 1.375;\\n --leading-normal: 1.5;\\n --leading-relaxed: 1.625;\\n --leading-loose: 2;\\n\\n --radius-xs: 0.125rem;\\n --radius-sm: 0.25rem;\\n --radius-md: 0.375rem;\\n --radius-lg: 0.5rem;\\n --radius-xl: 0.75rem;\\n --radius-2xl: 1rem;\\n --radius-3xl: 1.5rem;\\n --radius-4xl: 2rem;\\n\\n --shadow-2xs: 0 1px rgb(0 0 0 / 0.05);\\n --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);\\n --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\\n --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\\n --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\\n --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\\n --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);\\n\\n --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);\\n --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);\\n --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);\\n\\n --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);\\n --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);\\n --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);\\n --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);\\n --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);\\n --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);\\n\\n --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);\\n --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);\\n --text-shadow-sm:\\n 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075);\\n --text-shadow-md:\\n 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1);\\n --text-shadow-lg:\\n 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1);\\n\\n --ease-in: cubic-bezier(0.4, 0, 1, 1);\\n --ease-out: cubic-bezier(0, 0, 0.2, 1);\\n --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);\\n\\n --animate-spin: spin 1s linear infinite;\\n --animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;\\n --animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;\\n --animate-bounce: bounce 1s infinite;\\n\\n @keyframes spin {\\n to {\\n transform: rotate(360deg);\\n }\\n }\\n\\n @keyframes ping {\\n 75%,\\n 100% {\\n transform: scale(2);\\n opacity: 0;\\n }\\n }\\n\\n @keyframes pulse {\\n 50% {\\n opacity: 0.5;\\n }\\n }\\n\\n @keyframes bounce {\\n 0%,\\n 100% {\\n transform: translateY(-25%);\\n animation-timing-function: cubic-bezier(0.8, 0, 1, 1);\\n }\\n\\n 50% {\\n transform: none;\\n animation-timing-function: cubic-bezier(0, 0, 0.2, 1);\\n }\\n }\\n\\n --blur-xs: 4px;\\n --blur-sm: 8px;\\n --blur-md: 12px;\\n --blur-lg: 16px;\\n --blur-xl: 24px;\\n --blur-2xl: 40px;\\n --blur-3xl: 64px;\\n\\n --perspective-dramatic: 100px;\\n --perspective-near: 300px;\\n --perspective-normal: 500px;\\n --perspective-midrange: 800px;\\n --perspective-distant: 1200px;\\n\\n --aspect-video: 16 / 9;\\n\\n --default-transition-duration: 150ms;\\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\\n --default-font-family: --theme(--font-sans, initial);\\n --default-font-feature-settings: --theme(--font-sans--font-feature-settings, initial);\\n --default-font-variation-settings: --theme(--font-sans--font-variation-settings, initial);\\n --default-mono-font-family: --theme(--font-mono, initial);\\n --default-mono-font-feature-settings: --theme(--font-mono--font-feature-settings, initial);\\n --default-mono-font-variation-settings: --theme(--font-mono--font-variation-settings, initial);\\n}\\n\\n/* Deprecated */\\n@theme default inline reference {\\n --blur: 8px;\\n --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\\n --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);\\n --drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06);\\n --radius: 0.25rem;\\n --max-width-prose: 65ch;\\n}\\n\";\n","import { compile } from 'tailwindcss';\n\n// Loaded as `theme(reference)` below so utilities can resolve theme-dependent\n// values (colors, spacing, font sizes, ...) without re-emitting the `@theme`\n// block itself — see https://tailwindcss.com/docs/functions-and-directives#reference-directive.\n// A checked-in copy (not a `?raw` import of the real file) because `?raw` is\n// a Vite convention tsdown's bundler doesn't resolve, which would otherwise\n// ship an unresolved specifier in dist/ that breaks for non-Vite consumers.\nimport themeCSS from './theme-css';\n\nconst compileClasses = async (classes: string[]): Promise<string> => {\n if (classes.length === 0) {\n return '';\n }\n\n const compiler = await compile(\n `@import \"tailwindcss/theme.css\" theme(reference); @tailwind utilities;`,\n {\n loadStylesheet: async () => ({\n content: themeCSS,\n base: '',\n path: 'tailwindcss/theme.css',\n }),\n },\n );\n\n return compiler.build(classes);\n};\n\n// Scans an already-rendered DOM subtree for `class` attributes, rather than\n// regex-scanning the compiled source text. Source-text scanning can only see\n// classes the reader typed literally (e.g. `className=\"p-6\"`) — it has no\n// way to know what classes an imported component (e.g. ui-kit's `Button`,\n// `Typography.Title`) renders internally, since those live in that\n// component's own compiled output, not the previewed source. Scanning the\n// real DOM after mount catches both, because by then every class — reader-\n// authored or contributed by a component — is actually present as an\n// attribute.\nexport const generateTailwindCSSFromDOM = async (\n root: Element,\n): Promise<string> => {\n const classes = new Set<string>();\n\n const collect = (el: Element) => {\n el.getAttribute('class')\n ?.split(/\\s+/)\n .forEach(cls => {\n if (cls.trim()) {\n classes.add(cls.trim());\n }\n });\n };\n\n collect(root);\n root.querySelectorAll('[class]').forEach(collect);\n\n return compileClasses(Array.from(classes));\n};\n"],"mappings":";;AAYA,IAAA,oBAAe;;;ACFf,MAAM,iBAAiB,OAAO,YAAuC;CACnE,IAAI,QAAQ,WAAW,GACrB,OAAO;CAcT,QAAO,MAXgB,QACrB,0EACA,EACE,gBAAgB,aAAa;EAC3B,SAASA;EACT,MAAM;EACN,MAAM;CACR,GACF,CACF,EAAA,CAEgB,MAAM,OAAO;AAC/B;AAWA,MAAa,6BAA6B,OACxC,SACoB;CACpB,MAAM,0BAAU,IAAI,IAAY;CAEhC,MAAM,WAAW,OAAgB;EAC/B,GAAG,aAAa,OAAO,CAAC,EACpB,MAAM,KAAK,CAAC,CACb,SAAQ,QAAO;GACd,IAAI,IAAI,KAAK,GACX,QAAQ,IAAI,IAAI,KAAK,CAAC;EAE1B,CAAC;CACL;CAEA,QAAQ,IAAI;CACZ,KAAK,iBAAiB,SAAS,CAAC,CAAC,QAAQ,OAAO;CAEhD,OAAO,eAAe,MAAM,KAAK,OAAO,CAAC;AAC3C"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "4.0
|
|
7
|
+
"version": "4.1.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"module": "./dist/index.js",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
"@dnd-kit/modifiers": "^9.0.0",
|
|
110
110
|
"@dnd-kit/sortable": "^10.0.0",
|
|
111
111
|
"@dnd-kit/utilities": "^3.2.2",
|
|
112
|
-
"@jbpark/ui-kit": "^
|
|
112
|
+
"@jbpark/ui-kit": "^10.0.2",
|
|
113
113
|
"@jbpark/use-hooks": "^4.1.0",
|
|
114
114
|
"@uiw/codemirror-theme-vscode": "^4.25.11",
|
|
115
115
|
"@uiw/react-codemirror": "^4.25.11",
|