@codespark/react 1.0.6 → 1.0.8

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/index.js CHANGED
@@ -57,6 +57,16 @@ function useLatest(value) {
57
57
  ref.current = value;
58
58
  return ref;
59
59
  }
60
+ function useFramework(workspace) {
61
+ const framework = useMemo(() => {
62
+ const fwInput = workspace.framework;
63
+ if (typeof fwInput === "string") return registry.get(fwInput);
64
+ if (typeof fwInput === "function") return new fwInput();
65
+ return fwInput;
66
+ }, []);
67
+ if (!framework) throw new Error(`Framework not found: ${workspace.framework}`);
68
+ return framework;
69
+ }
60
70
  function getLanguageFromFile(name) {
61
71
  const ext = name.split(".").pop()?.toLowerCase();
62
72
  return ext ? {
@@ -131,10 +141,10 @@ var Workspace = class extends OPFS {
131
141
  constructor(config) {
132
142
  super();
133
143
  this.config = config;
134
- const { id, OPFS: OPFS$1 = false, files } = config;
144
+ const { id, OPFS = false, files } = config;
135
145
  this.id = id || "";
136
146
  this.initialFiles = { ...files };
137
- if (OPFS$1) super.initOPFS(this.files);
147
+ if (OPFS) super.initOPFS(this.files);
138
148
  }
139
149
  notifyListeners() {
140
150
  this.listeners.forEach((fn) => fn());
@@ -320,33 +330,26 @@ var Workspace = class extends OPFS {
320
330
  * @returns Workspace state including files, compiled code, and the workspace instance
321
331
  */
322
332
  function useWorkspace(init) {
323
- const uid$1 = useId();
333
+ const uid = useId();
324
334
  const context = useCodespark();
325
335
  const workspace = useMemo(() => {
326
336
  let ws;
327
337
  if (init instanceof Workspace) ws = init;
328
338
  else if (init) ws = new Workspace(init);
329
339
  else ws = context?.workspace;
330
- if (!ws?.id) ws?.[INTERNAL_SET_ID](`workspace${uid$1}`);
340
+ if (!ws?.id) ws?.[INTERNAL_SET_ID](`workspace${uid}`);
331
341
  return ws;
332
342
  }, []);
333
343
  if (!workspace) throw Error("Can not find any workspace instance. Make sure provide a workspace during runtime.");
334
- const framework = useMemo(() => {
335
- const fwInput = workspace.framework;
336
- if (typeof fwInput === "string") return registry.get(fwInput);
337
- if (typeof fwInput === "function") return new fwInput();
338
- return fwInput;
339
- }, []);
340
- if (!framework) throw new Error(`Framework not found: ${workspace.framework}`);
341
- const standalone = context ? false : !workspace[INTERNAL_BOUND]();
342
- const subscribe = useMemo(() => standalone ? (cb) => workspace[INTERNAL_SUBSCRIBE](cb) : NOOP_SUBSCRIBE, []);
344
+ const framework = useFramework(workspace);
345
+ const subscribe = useMemo(() => (context ? false : !workspace[INTERNAL_BOUND]()) ? (cb) => workspace[INTERNAL_SUBSCRIBE](cb) : NOOP_SUBSCRIBE, []);
343
346
  const files = useSyncExternalStore(subscribe, () => workspace.files, () => workspace.files);
344
347
  const currentFile = useSyncExternalStore(subscribe, () => workspace.currentFile, () => workspace.currentFile);
345
348
  const derivedState = useMemo(() => {
346
349
  if (context) {
347
- const { fileTree: fileTree$1, vendor, compiled, compileError } = context;
350
+ const { fileTree, vendor, compiled, compileError } = context;
348
351
  return {
349
- fileTree: fileTree$1,
352
+ fileTree,
350
353
  vendor,
351
354
  compiled,
352
355
  compileError
@@ -393,13 +396,13 @@ function useWorkspace(init) {
393
396
  return root;
394
397
  })();
395
398
  try {
396
- framework.analyze(workspace.entry, files);
397
- const compiled = framework.compile();
399
+ framework.analyze(files);
400
+ const compiled = framework.compile(workspace.entry);
398
401
  workspace[INTERNAL_EMIT]("compiled", compiled);
399
402
  const modules = framework.getOutput(LoaderType.ESModule);
400
403
  const styles = framework.getOutput(LoaderType.Style);
401
404
  const scripts = framework.getOutput(LoaderType.Script);
402
- const externals = modules.flatMap(({ externals: externals$1 }) => externals$1).reduce((acc, { name, imported }) => {
405
+ const externals = modules.flatMap(({ externals }) => externals).reduce((acc, { name, imported }) => {
403
406
  if (!acc[name]) acc[name] = /* @__PURE__ */ new Set();
404
407
  imported.forEach((i) => acc[name].add(i));
405
408
  return acc;
@@ -542,10 +545,10 @@ function CodesparkProvider(props) {
542
545
 
543
546
  //#endregion
544
547
  //#region src/lib/editor-adapter/index.ts
545
- let EditorEngine = /* @__PURE__ */ function(EditorEngine$1) {
546
- EditorEngine$1[EditorEngine$1["Monaco"] = 0] = "Monaco";
547
- EditorEngine$1[EditorEngine$1["CodeMirror"] = 1] = "CodeMirror";
548
- return EditorEngine$1;
548
+ let EditorEngine = /* @__PURE__ */ function(EditorEngine) {
549
+ EditorEngine[EditorEngine["Monaco"] = 0] = "Monaco";
550
+ EditorEngine[EditorEngine["CodeMirror"] = 1] = "CodeMirror";
551
+ return EditorEngine;
549
552
  }({});
550
553
 
551
554
  //#endregion
@@ -574,7 +577,7 @@ const buttonVariants = cva("inline-flex items-center justify-center gap-2 whites
574
577
  size: "default"
575
578
  }
576
579
  });
577
- const Button = React.forwardRef(function Button$1({ className, variant = "default", size = "default", asChild = false, ...props }, ref) {
580
+ const Button = React.forwardRef(function Button({ className, variant = "default", size = "default", asChild = false, ...props }, ref) {
578
581
  return /* @__PURE__ */ jsx(asChild ? Slot.Root : "button", {
579
582
  "data-slot": "button",
580
583
  "data-variant": variant,
@@ -596,10 +599,7 @@ const Icons = {
596
599
  xmlns: "http://www.w3.org/2000/svg",
597
600
  viewBox: "0 0 24 24",
598
601
  ...props,
599
- children: /* @__PURE__ */ jsx("path", {
600
- fill: "currentColor",
601
- d: "M12.043 23.968c.479-.004.953-.029 1.426-.094a11.805 11.805 0 0 0 3.146-.863 12.404 12.404 0 0 0 3.793-2.542 11.977 11.977 0 0 0 2.44-3.427 11.794 11.794 0 0 0 1.02-3.476c.149-1.16.135-2.346-.045-3.499a11.96 11.96 0 0 0-.793-2.788 11.197 11.197 0 0 0-.854-1.617c-1.168-1.837-2.861-3.314-4.81-4.3a12.835 12.835 0 0 0-2.172-.87h-.005c.119.063.24.132.345.201.12.074.239.146.351.225a8.93 8.93 0 0 1 1.559 1.33c1.063 1.145 1.797 2.548 2.218 4.041.284.982.434 1.998.495 3.017.044.743.044 1.491-.047 2.229-.149 1.27-.554 2.51-1.228 3.596a7.475 7.475 0 0 1-1.903 2.084c-1.244.928-2.877 1.482-4.436 1.114a3.916 3.916 0 0 1-.748-.258 4.692 4.692 0 0 1-.779-.45 6.08 6.08 0 0 1-1.244-1.105 6.507 6.507 0 0 1-1.049-1.747 7.366 7.366 0 0 1-.494-2.54c-.03-1.273.225-2.553.854-3.67a6.43 6.43 0 0 1 1.663-1.918c.225-.178.464-.333.704-.479l.016-.007a5.121 5.121 0 0 0-1.441-.12 4.963 4.963 0 0 0-1.228.24c-.359.12-.704.27-1.019.45a6.146 6.146 0 0 0-.733.494c-.211.18-.42.36-.615.555-1.123 1.153-1.768 2.682-2.022 4.256-.15.973-.15 1.96-.091 2.95.105 1.395.391 2.787.945 4.062a8.518 8.518 0 0 0 1.348 2.173 8.14 8.14 0 0 0 3.132 2.23 7.934 7.934 0 0 0 2.113.54c.074.015.149.015.209.015zm-2.934-.398a4.102 4.102 0 0 1-.45-.228 8.5 8.5 0 0 1-2.038-1.534c-1.094-1.137-1.827-2.566-2.247-4.08a15.184 15.184 0 0 1-.495-3.172 12.14 12.14 0 0 1 .046-2.082c.135-1.257.495-2.501 1.124-3.58a6.889 6.889 0 0 1 1.783-2.053 6.23 6.23 0 0 1 1.633-.9 5.363 5.363 0 0 1 3.522-.045c.029 0 .029 0 .045.03.015.015.045.015.06.03.045.016.104.045.165.074.239.12.479.271.704.42a6.294 6.294 0 0 1 2.097 2.502c.42.914.615 1.934.631 2.938.014 1.079-.18 2.157-.645 3.146a6.42 6.42 0 0 1-2.638 2.832c.09.03.18.045.271.075.225.044.449.074.688.074 1.468.045 2.892-.66 3.94-1.647.195-.18.375-.375.54-.585.225-.27.435-.54.614-.823.239-.375.435-.75.614-1.154a8.112 8.112 0 0 0 .509-1.664c.196-1.004.211-2.022.149-3.026-.135-2.022-.673-4.045-1.842-5.724a9.054 9.054 0 0 0-.555-.719 9.868 9.868 0 0 0-1.063-1.034 8.477 8.477 0 0 0-1.363-.915 9.927 9.927 0 0 0-1.692-.598l-.3-.06c-.209-.03-.42-.044-.634-.06a8.453 8.453 0 0 0-1.015.016c-.704.045-1.412.16-2.112.337C5.799 1.227 2.863 3.566 1.3 6.67A11.834 11.834 0 0 0 .238 9.801a11.81 11.81 0 0 0-.104 3.775c.12 1.02.374 2.023.778 2.977.227.57.511 1.124.825 1.648 1.094 1.783 2.683 3.236 4.51 4.24.688.39 1.408.69 2.157.944.226.074.45.15.689.21z"
602
- })
602
+ children: /* @__PURE__ */ jsx("path", { d: "M12.043 23.968c.479-.004.953-.029 1.426-.094a11.805 11.805 0 0 0 3.146-.863 12.404 12.404 0 0 0 3.793-2.542 11.977 11.977 0 0 0 2.44-3.427 11.794 11.794 0 0 0 1.02-3.476c.149-1.16.135-2.346-.045-3.499a11.96 11.96 0 0 0-.793-2.788 11.197 11.197 0 0 0-.854-1.617c-1.168-1.837-2.861-3.314-4.81-4.3a12.835 12.835 0 0 0-2.172-.87h-.005c.119.063.24.132.345.201.12.074.239.146.351.225a8.93 8.93 0 0 1 1.559 1.33c1.063 1.145 1.797 2.548 2.218 4.041.284.982.434 1.998.495 3.017.044.743.044 1.491-.047 2.229-.149 1.27-.554 2.51-1.228 3.596a7.475 7.475 0 0 1-1.903 2.084c-1.244.928-2.877 1.482-4.436 1.114a3.916 3.916 0 0 1-.748-.258 4.692 4.692 0 0 1-.779-.45 6.08 6.08 0 0 1-1.244-1.105 6.507 6.507 0 0 1-1.049-1.747 7.366 7.366 0 0 1-.494-2.54c-.03-1.273.225-2.553.854-3.67a6.43 6.43 0 0 1 1.663-1.918c.225-.178.464-.333.704-.479l.016-.007a5.121 5.121 0 0 0-1.441-.12 4.963 4.963 0 0 0-1.228.24c-.359.12-.704.27-1.019.45a6.146 6.146 0 0 0-.733.494c-.211.18-.42.36-.615.555-1.123 1.153-1.768 2.682-2.022 4.256-.15.973-.15 1.96-.091 2.95.105 1.395.391 2.787.945 4.062a8.518 8.518 0 0 0 1.348 2.173 8.14 8.14 0 0 0 3.132 2.23 7.934 7.934 0 0 0 2.113.54c.074.015.149.015.209.015zm-2.934-.398a4.102 4.102 0 0 1-.45-.228 8.5 8.5 0 0 1-2.038-1.534c-1.094-1.137-1.827-2.566-2.247-4.08a15.184 15.184 0 0 1-.495-3.172 12.14 12.14 0 0 1 .046-2.082c.135-1.257.495-2.501 1.124-3.58a6.889 6.889 0 0 1 1.783-2.053 6.23 6.23 0 0 1 1.633-.9 5.363 5.363 0 0 1 3.522-.045c.029 0 .029 0 .045.03.015.015.045.015.06.03.045.016.104.045.165.074.239.12.479.271.704.42a6.294 6.294 0 0 1 2.097 2.502c.42.914.615 1.934.631 2.938.014 1.079-.18 2.157-.645 3.146a6.42 6.42 0 0 1-2.638 2.832c.09.03.18.045.271.075.225.044.449.074.688.074 1.468.045 2.892-.66 3.94-1.647.195-.18.375-.375.54-.585.225-.27.435-.54.614-.823.239-.375.435-.75.614-1.154a8.112 8.112 0 0 0 .509-1.664c.196-1.004.211-2.022.149-3.026-.135-2.022-.673-4.045-1.842-5.724a9.054 9.054 0 0 0-.555-.719 9.868 9.868 0 0 0-1.063-1.034 8.477 8.477 0 0 0-1.363-.915 9.927 9.927 0 0 0-1.692-.598l-.3-.06c-.209-.03-.42-.044-.634-.06a8.453 8.453 0 0 0-1.015.016c-.704.045-1.412.16-2.112.337C5.799 1.227 2.863 3.566 1.3 6.67A11.834 11.834 0 0 0 .238 9.801a11.81 11.81 0 0 0-.104 3.775c.12 1.02.374 2.023.778 2.977.227.57.511 1.124.825 1.648 1.094 1.783 2.683 3.236 4.51 4.24.688.39 1.408.69 2.157.944.226.074.45.15.689.21z" })
603
603
  }),
604
604
  ts: (props) => /* @__PURE__ */ jsx("svg", {
605
605
  xmlns: "http://www.w3.org/2000/svg",
@@ -616,12 +616,13 @@ const Icons = {
616
616
  };
617
617
  function getIconForLanguageExtension(language) {
618
618
  switch (language) {
619
- case "json": return /* @__PURE__ */ jsx(Icons.json, {});
619
+ case "json": return /* @__PURE__ */ jsx(Icons.json, { className: "fill-foreground" });
620
620
  case "css": return /* @__PURE__ */ jsx(Icons.css, { className: "fill-foreground" });
621
621
  case "js":
622
622
  case "jsx":
623
623
  case "ts":
624
624
  case "tsx":
625
+ case "javascript":
625
626
  case "typescript": return /* @__PURE__ */ jsx(Icons.ts, { className: "fill-foreground" });
626
627
  default: return /* @__PURE__ */ jsx(FileIcon, {});
627
628
  }
@@ -731,7 +732,7 @@ const LANGUAGE_EXTENSIONS = {
731
732
  };
732
733
  const CodeMirror = {
733
734
  kind: EditorEngine.CodeMirror,
734
- Component: memo(function CodeMirror$1(props) {
735
+ Component: memo(function CodeMirror(props) {
735
736
  const { id, basicSetup, extensions = [], width, height, fontFamily, lang, onMount, ...rest } = props;
736
737
  const [mounted, setMounted] = useState(false);
737
738
  const editorRef = useRef(null);
@@ -794,8 +795,8 @@ function CodesparkEditor(props) {
794
795
  entry: "./App.tsx",
795
796
  files: { "./App.tsx": value }
796
797
  }));
797
- const uid$1 = useId();
798
- const editorId = id ?? `editor${uid$1}`;
798
+ const uid = useId();
799
+ const editorId = id ?? `editor${uid}`;
799
800
  const editorRef = useRef(null);
800
801
  const currentFileRef = useLatest(currentFile);
801
802
  const { copyToClipboard, isCopied } = useCopyToClipboard();
@@ -838,14 +839,14 @@ function CodesparkEditor(props) {
838
839
  workspace[INTERNAL_REGISTER_EDITOR](editorId, adapter);
839
840
  }, []);
840
841
  const renderEditor = () => {
841
- const id$1 = `${workspace.id}${editorId}`;
842
+ const id = `${workspace.id}${editorId}`;
842
843
  if (editor.kind === EditorEngine.Monaco && propsTypeGuard(props, editor, EditorEngine.Monaco)) {
843
844
  const { height, width, wrapperProps, options, onChange, onMount } = props;
844
845
  const { fontFamily = globalFontFamily } = options || {};
845
846
  return /* @__PURE__ */ jsx(editor.Component, {
846
- id: id$1,
847
+ id,
847
848
  value: value || currentFile.code,
848
- path: `file:///${id$1}/${currentFile.path.replace(/^(\.\.?\/)+/, "")}`,
849
+ path: `file:///${id}/${currentFile.path.replace(/^(\.\.?\/)+/, "")}`,
849
850
  theme: theme === "light" ? "vitesse-light" : "vitesse-dark",
850
851
  files,
851
852
  imports: vendor.imports,
@@ -876,7 +877,7 @@ function CodesparkEditor(props) {
876
877
  if (editor.kind === EditorEngine.CodeMirror && propsTypeGuard(props, editor, EditorEngine.CodeMirror)) {
877
878
  const { height, width, basicSetup, fontFamily, readOnly, onChange, onMount } = props;
878
879
  return /* @__PURE__ */ jsx(editor.Component, {
879
- id: id$1,
880
+ id,
880
881
  className,
881
882
  value: value || currentFile.code,
882
883
  height: height ?? "200px",
@@ -918,7 +919,7 @@ function CodesparkEditor(props) {
918
919
  className: "border-border flex items-center justify-between p-2",
919
920
  children: [/* @__PURE__ */ jsxs("div", {
920
921
  className: "[&_svg]:text-code-foreground flex items-center gap-x-2 px-2 [&_svg]:size-4 [&_svg]:opacity-70",
921
- children: [getIconForLanguageExtension("typescript"), /* @__PURE__ */ jsx("span", {
922
+ children: [getIconForLanguageExtension(currentFile.language ?? "typescript"), /* @__PURE__ */ jsx("span", {
922
923
  className: "text-card-foreground",
923
924
  children: currentFile.path.replace(/^(\.\.?\/)+/, "")
924
925
  })]
@@ -932,11 +933,12 @@ function CodesparkEditor(props) {
932
933
  if (isValidElement(t)) return t;
933
934
  const item = typeof t === "string" ? toolboxItems[t] : t;
934
935
  if (!item) return null;
935
- const { tooltip, icon, asChild = true, onClick, render } = item;
936
+ const { tooltip, disabled = false, icon, asChild = true, onClick, render } = item;
936
937
  function renderTriggerContent() {
937
938
  if (icon) return /* @__PURE__ */ jsx(Button, {
938
939
  variant: "ghost",
939
940
  size: "icon-sm",
941
+ disabled,
940
942
  onClick: () => onClick?.(editorRef.current),
941
943
  children: icon
942
944
  });
@@ -1165,11 +1167,11 @@ function useInjections(children) {
1165
1167
  Children.forEach(children, (child) => {
1166
1168
  if (isValidElement(child)) {
1167
1169
  if (child.type === Style) {
1168
- const { children: children$1, ...attrs } = child.props;
1169
- result.push(`<style${serializeAttributes(attrs)}>${children$1?.trim() || ""}</style>`);
1170
+ const { children, ...attrs } = child.props;
1171
+ result.push(`<style${serializeAttributes(attrs)}>${children?.trim() || ""}</style>`);
1170
1172
  } else if (child.type === Script) {
1171
- const { children: children$1, ...attrs } = child.props;
1172
- result.push(`<script${serializeAttributes(attrs)}>${children$1?.trim() || ""}<\/script>`);
1173
+ const { children, ...attrs } = child.props;
1174
+ result.push(`<script${serializeAttributes(attrs)}>${children?.trim() || ""}<\/script>`);
1173
1175
  } else if (child.type === Link) {
1174
1176
  const attrs = child.props;
1175
1177
  result.push(`<link${serializeAttributes(attrs)} />`);
@@ -1428,13 +1430,13 @@ var TailwindCSSJit = class TailwindCSSJit {
1428
1430
  return this.env.querySelectorAll(`style[type="${TailwindCSSJit.STYLE_TYPE}"]`);
1429
1431
  }
1430
1432
  async createCompiler() {
1431
- let css$1 = "";
1432
- for (const sheet of this.stylesheets) css$1 += sheet.textContent + "\n";
1433
- if (!css$1.includes("@import")) css$1 = `@import "tailwindcss";${css$1}`;
1434
- if (this.lastCss === css$1) return;
1435
- this.lastCss = css$1;
1433
+ let css = "";
1434
+ for (const sheet of this.stylesheets) css += sheet.textContent + "\n";
1435
+ if (!css.includes("@import")) css = `@import "tailwindcss";${css}`;
1436
+ if (this.lastCss === css) return;
1437
+ this.lastCss = css;
1436
1438
  try {
1437
- this.compiler = await tailwindcss.compile(css$1, {
1439
+ this.compiler = await tailwindcss.compile(css, {
1438
1440
  base: "/",
1439
1441
  loadStylesheet: this.loadStylesheet,
1440
1442
  loadModule: this.loadModule
@@ -1522,8 +1524,8 @@ function useTailwindCSS() {
1522
1524
  });
1523
1525
  };
1524
1526
  const rebuild = async (kind) => {
1525
- const css$1 = await jitRef.current?.rebuild(kind);
1526
- if (css$1 !== void 0 && sheetRef.current) sheetRef.current.textContent = css$1;
1527
+ const css = await jitRef.current?.rebuild(kind);
1528
+ if (css !== void 0 && sheetRef.current) sheetRef.current.textContent = css;
1527
1529
  };
1528
1530
  const mount = (doc) => {
1529
1531
  jitRef.current ??= new TailwindCSSJit(doc);
@@ -1623,7 +1625,7 @@ body {
1623
1625
  function CodesparkPreview(props) {
1624
1626
  const { imports: globalImports, theme: globalTheme } = useConfig();
1625
1627
  const { workspace: contextWorkspace, imports: contextImports, theme: contextTheme, framework: contextFramework } = useCodespark() || {};
1626
- const { code = "", framework = contextFramework, className, tailwindcss: tailwindcss$1 = true, preflight = true, imports, theme = contextTheme ?? globalTheme ?? "light", children, height, onError, onLoad, onRendered, onConsole } = props;
1628
+ const { code = "", framework = contextFramework, className, tailwindcss = true, preflight = true, imports, theme = contextTheme ?? globalTheme ?? "light", children, height, onError, onLoad, onRendered, onConsole } = props;
1627
1629
  const { compiled, vendor, workspace } = useWorkspace(props.workspace ?? contextWorkspace ?? new Workspace({
1628
1630
  entry: "./App.tsx",
1629
1631
  files: { "./App.tsx": code },
@@ -1653,12 +1655,12 @@ function CodesparkPreview(props) {
1653
1655
  onConsole
1654
1656
  });
1655
1657
  useEffect(() => {
1656
- if (!tailwindcss$1) unmountTailwind();
1658
+ if (!tailwindcss) unmountTailwind();
1657
1659
  else readyRef.current.promise.then((doc) => {
1658
1660
  if (doc) mountTailwind(doc);
1659
1661
  });
1660
1662
  return unmountTailwind;
1661
- }, [tailwindcss$1]);
1663
+ }, [tailwindcss]);
1662
1664
  useEffect(() => {
1663
1665
  if (typeof window === "undefined" || !code) return;
1664
1666
  workspace.setFile(workspace.entry, code);
@@ -1693,6 +1695,193 @@ function CodesparkPreview(props) {
1693
1695
  });
1694
1696
  }
1695
1697
 
1698
+ //#endregion
1699
+ //#region src/ui/input.tsx
1700
+ function Input({ className, type, ...props }) {
1701
+ return /* @__PURE__ */ jsx("input", {
1702
+ type,
1703
+ "data-slot": "input",
1704
+ className: cn("dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 file:text-foreground placeholder:text-muted-foreground h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm", className),
1705
+ ...props
1706
+ });
1707
+ }
1708
+
1709
+ //#endregion
1710
+ //#region src/ui/input-group.tsx
1711
+ function InputGroup({ className, ...props }) {
1712
+ return /* @__PURE__ */ jsx("div", {
1713
+ "data-slot": "input-group",
1714
+ role: "group",
1715
+ className: cn("border-input dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-disabled:bg-input/50 dark:has-disabled:bg-input/80 group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-3 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5", className),
1716
+ ...props
1717
+ });
1718
+ }
1719
+ const inputGroupAddonVariants = cva("text-muted-foreground h-auto gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4 flex cursor-text items-center justify-center select-none", {
1720
+ variants: { align: {
1721
+ "inline-start": "pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem] order-first",
1722
+ "inline-end": "pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem] order-last",
1723
+ "block-start": "px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start",
1724
+ "block-end": "px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start"
1725
+ } },
1726
+ defaultVariants: { align: "inline-start" }
1727
+ });
1728
+ function InputGroupAddon({ className, align = "inline-start", ...props }) {
1729
+ return /* @__PURE__ */ jsx("div", {
1730
+ role: "group",
1731
+ "data-slot": "input-group-addon",
1732
+ "data-align": align,
1733
+ className: cn(inputGroupAddonVariants({ align }), className),
1734
+ onClick: (e) => {
1735
+ if (e.target.closest("button")) return;
1736
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
1737
+ },
1738
+ ...props
1739
+ });
1740
+ }
1741
+ const inputGroupButtonVariants = cva("gap-2 text-sm shadow-none flex items-center", {
1742
+ variants: { size: {
1743
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
1744
+ sm: "",
1745
+ "icon-xs": "size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0",
1746
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0"
1747
+ } },
1748
+ defaultVariants: { size: "xs" }
1749
+ });
1750
+ function InputGroupButton({ className, type = "button", variant = "ghost", size = "xs", ...props }) {
1751
+ return /* @__PURE__ */ jsx(Button, {
1752
+ type,
1753
+ "data-size": size,
1754
+ variant,
1755
+ className: cn(inputGroupButtonVariants({ size }), className),
1756
+ ...props
1757
+ });
1758
+ }
1759
+ function InputGroupInput({ className, ...props }) {
1760
+ return /* @__PURE__ */ jsx(Input, {
1761
+ "data-slot": "input-group-control",
1762
+ className: cn("flex-1 rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent", className),
1763
+ ...props
1764
+ });
1765
+ }
1766
+
1767
+ //#endregion
1768
+ //#region src/components/browser/index.tsx
1769
+ const parseUrlInput = (input) => {
1770
+ let path = input.trim();
1771
+ path = path.replace(/^https?:\/\//, "");
1772
+ path = path.replace(/^localhost(:\d+)?/, "");
1773
+ if (!path.startsWith("/")) path = "/" + path;
1774
+ return path;
1775
+ };
1776
+ function CodesparkBrowser(props) {
1777
+ const { workspace: contextWorkspace } = useCodespark() || {};
1778
+ const { defaultPath = "/", onPathChange, loading = false, className, onLoad } = props;
1779
+ const { workspace } = useWorkspace(props.workspace ?? contextWorkspace);
1780
+ const [currentPath, setCurrentPath] = useState(defaultPath);
1781
+ const framework = useMemo(() => {
1782
+ const fwInput = workspace.framework;
1783
+ if (typeof fwInput === "string") return registry.get(fwInput);
1784
+ if (typeof fwInput === "function") return new fwInput();
1785
+ return fwInput;
1786
+ }, []);
1787
+ const supported = (fw) => fw?.name === "node-http" || fw?.name === "node-vite";
1788
+ const [src, setSrc] = useState("about:blank");
1789
+ useEffect(() => {
1790
+ if (!supported(framework)) return;
1791
+ framework.on("serverReady", () => {
1792
+ handleRequest("/");
1793
+ });
1794
+ framework.on("serverShutdown", () => {
1795
+ setSrc("about:blank");
1796
+ });
1797
+ const handleMessage = (event) => {
1798
+ if (event.data?.type === "navigate") {
1799
+ const path = event.data.path;
1800
+ setCurrentPath(path);
1801
+ handleRequest(path);
1802
+ }
1803
+ };
1804
+ window.addEventListener("message", handleMessage);
1805
+ return () => {
1806
+ window.removeEventListener("message", handleMessage);
1807
+ };
1808
+ }, []);
1809
+ const handleRequest = (path) => {
1810
+ if (!supported(framework)) return;
1811
+ framework.request(path).then(setSrc);
1812
+ };
1813
+ const handleAddressSubmit = (e) => {
1814
+ e.preventDefault();
1815
+ const path = parseUrlInput(currentPath);
1816
+ setCurrentPath(path);
1817
+ handleRequest(path);
1818
+ };
1819
+ return /* @__PURE__ */ jsxs("div", {
1820
+ className: cn("relative flex flex-col", className),
1821
+ children: [
1822
+ loading ? /* @__PURE__ */ jsx("div", {
1823
+ className: "absolute right-2 bottom-2 z-10 h-8 w-8 **:box-border",
1824
+ children: /* @__PURE__ */ jsx("div", {
1825
+ className: "flex -translate-x-1 translate-y-[9px] scale-[0.13] **:absolute **:h-24 **:w-24",
1826
+ children: /* @__PURE__ */ jsxs("div", {
1827
+ className: "fill-mode-forwards **:border-foreground **:bg-background transform-[rotateX(-25.5deg)_rotateY(45deg)] animate-[cube-rotate_1s_linear_infinite] transform-3d **:rounded-lg **:border-10",
1828
+ children: [
1829
+ /* @__PURE__ */ jsx("div", { className: "origin-[50%_50%] transform-[rotateX(90deg)_translateZ(44px)]" }),
1830
+ /* @__PURE__ */ jsx("div", { className: "origin-[50%_50%] transform-[rotateY(90deg)_translateZ(44px)]" }),
1831
+ /* @__PURE__ */ jsx("div", { className: "origin-[50%_50%] transform-[rotateX(-90deg)_translateZ(44px)]" }),
1832
+ /* @__PURE__ */ jsx("div", { className: "origin-[50%_50%] transform-[rotateY(-90deg)_translateZ(44px)]" }),
1833
+ /* @__PURE__ */ jsx("div", { className: "origin-[50%_50%] transform-[rotateY(0deg)_translateZ(44px)]" }),
1834
+ /* @__PURE__ */ jsx("div", { className: "origin-[50%_50%] transform-[rotateY(-180deg)_translateZ(44px)]" })
1835
+ ]
1836
+ })
1837
+ })
1838
+ }) : null,
1839
+ /* @__PURE__ */ jsx("form", {
1840
+ onSubmit: handleAddressSubmit,
1841
+ className: "bg-muted/50 border-border relative z-10 flex items-center gap-2 border-b p-2",
1842
+ children: /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupInput, {
1843
+ value: currentPath,
1844
+ onChange: (e) => {
1845
+ const path = e.target.value;
1846
+ setCurrentPath(path);
1847
+ onPathChange?.(path);
1848
+ },
1849
+ onKeyDown: (e) => {
1850
+ if (e.key === "Enter") handleAddressSubmit(e);
1851
+ }
1852
+ }), /* @__PURE__ */ jsx(InputGroupAddon, {
1853
+ align: "inline-end",
1854
+ children: /* @__PURE__ */ jsx(InputGroupButton, {
1855
+ type: "submit",
1856
+ variant: "secondary",
1857
+ children: "Go"
1858
+ })
1859
+ })] })
1860
+ }),
1861
+ src === "about:blank" ? /* @__PURE__ */ jsxs("div", {
1862
+ className: "bg-background flex h-full w-full flex-1 flex-col items-center justify-center gap-4",
1863
+ children: [/* @__PURE__ */ jsx("span", {
1864
+ className: "text-muted-foreground/50 text-sm",
1865
+ children: "Ready to preview"
1866
+ }), /* @__PURE__ */ jsxs("div", {
1867
+ className: "text-muted-foreground/30 flex gap-2 text-xs",
1868
+ children: [
1869
+ /* @__PURE__ */ jsx("span", { children: "localhost" }),
1870
+ /* @__PURE__ */ jsx("span", { children: "•" }),
1871
+ /* @__PURE__ */ jsx("span", { children: "Press Go to navigate" })
1872
+ ]
1873
+ })]
1874
+ }) : /* @__PURE__ */ jsx("iframe", {
1875
+ src,
1876
+ className: "h-full w-full flex-1",
1877
+ onLoad: (e) => {
1878
+ onLoad?.(e.target);
1879
+ }
1880
+ })
1881
+ ]
1882
+ });
1883
+ }
1884
+
1696
1885
  //#endregion
1697
1886
  //#region src/index.tsx
1698
1887
  registerFramework(react);
@@ -1704,7 +1893,7 @@ registerFramework(react);
1704
1893
  * Supports both single-file mode (via `code` prop) and multi-file mode (via `files` prop).
1705
1894
  */
1706
1895
  function Codespark(props) {
1707
- const { code, files, name = "./App.tsx", theme, editor, framework = "react", showEditor = true, showPreview = true, showFileExplorer = true, readonly: readOnly, className, toolbox, tailwindcss: tailwindcss$1, onConsole, onError, children, defaultExpanded, getWorkspace, editorHeight, previewHeight, orientation = "vertical", preflight } = props;
1896
+ const { code, files, name = "./App.tsx", theme, editor, framework = "react", showEditor = true, showPreview = true, showFileExplorer = true, readonly: readOnly, className, toolbox, tailwindcss, onConsole, onError, children, defaultExpanded, getWorkspace, editorHeight, previewHeight, orientation = "vertical", preflight } = props;
1708
1897
  const { workspace, fileTree, compileError } = useWorkspace({
1709
1898
  entry: name,
1710
1899
  files: files ?? { [name]: code || "" },
@@ -1754,10 +1943,10 @@ function Codespark(props) {
1754
1943
  theme,
1755
1944
  children: /* @__PURE__ */ jsxs("div", {
1756
1945
  className: cn("border-border relative grid w-full overflow-hidden rounded-lg border", orientation === "horizontal" && "grid-cols-[2fr_1fr]", className),
1757
- children: [/* @__PURE__ */ jsxs("div", {
1946
+ children: [showPreview ? /* @__PURE__ */ jsxs("div", {
1758
1947
  className: cn("border-border relative", showPreview && showEditor ? orientation === "vertical" ? "border-b" : "border-l" : "", orientation === "horizontal" && "order-2"),
1759
- children: [showPreview ? /* @__PURE__ */ jsx(CodesparkPreview, {
1760
- tailwindcss: tailwindcss$1,
1948
+ children: [/* @__PURE__ */ jsx(CodesparkPreview, {
1949
+ tailwindcss,
1761
1950
  onConsole,
1762
1951
  onError: (error) => {
1763
1952
  onError?.(error);
@@ -1766,7 +1955,7 @@ function Codespark(props) {
1766
1955
  height: previewHeight,
1767
1956
  preflight,
1768
1957
  children
1769
- }) : null, runtimeError ? /* @__PURE__ */ jsxs("div", {
1958
+ }), runtimeError ? /* @__PURE__ */ jsxs("div", {
1770
1959
  className: "bg-background absolute inset-0 z-20 overflow-auto p-6",
1771
1960
  children: [/* @__PURE__ */ jsx("div", {
1772
1961
  className: "text-2xl text-red-500",
@@ -1776,7 +1965,7 @@ function Codespark(props) {
1776
1965
  children: runtimeError.stack || runtimeError.message
1777
1966
  })]
1778
1967
  }) : null]
1779
- }), showEditor ? /* @__PURE__ */ jsxs("div", {
1968
+ }) : null, showEditor ? /* @__PURE__ */ jsxs("div", {
1780
1969
  className: cn("flex h-full w-full divide-x", orientation === "horizontal" && "order-1"),
1781
1970
  children: [expanded && showFileExplorer ? /* @__PURE__ */ jsx(CodesparkFileExplorer, {}) : null, renderEditor()]
1782
1971
  }) : null]
@@ -1792,4 +1981,4 @@ const useMDXComponents = () => {
1792
1981
  };
1793
1982
 
1794
1983
  //#endregion
1795
- export { Codespark, CodesparkEditor, CodesparkFileExplorer, CodesparkPreview, CodesparkProvider, ConfigProvider, EditorEngine, Link, Script, Style, Workspace, createWorkspace, useMDXComponents, useWorkspace };
1984
+ export { Codespark, CodesparkBrowser, CodesparkEditor, CodesparkFileExplorer, CodesparkPreview, CodesparkProvider, ConfigProvider, EditorEngine, Link, Script, Style, Workspace, createWorkspace, useMDXComponents, useWorkspace };