sculpted 0.3.0 → 0.3.2

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/README.md CHANGED
@@ -117,13 +117,10 @@ instead of pretending the full cascade can be edited safely.
117
117
 
118
118
  ## Documentation
119
119
 
120
- - [Vite plugin options](docs/vite-plugin.md) covers setup, defaults, endpoint configuration, and
121
- dev/prod behavior.
120
+ - [Vite plugin options](docs/vite-plugin.md) covers setup, defaults, and dev/prod behavior.
122
121
  - [Source writeback](docs/source-writeback.md) covers the safety model, supported edit shapes, and
123
122
  common failure modes.
124
- - [Source syntax adapters](docs/source-syntax-adapters.md) covers TSRX and custom parser adapters.
125
- - [Example apps](docs/examples.md) covers the React and Preact Panda CSS examples used for manual
126
- verification.
123
+ - [Source syntax adapters](docs/source-syntax-adapters.md) covers opt-in TSRX support.
127
124
 
128
125
  ## Troubleshooting
129
126
 
@@ -45,7 +45,8 @@ declare class SculptedRuntime {
45
45
  requestTokenConfigEdit(request: TokenConfigEditRequest, write: boolean): Promise<TokenConfigEditResponse>;
46
46
  openSourceLocation(request: OpenSourceLocationRequest): Promise<OpenSourceLocationResponse>;
47
47
  selectElement(element: Element): Promise<SelectedElementInfo>;
48
- startInspecting(onSelect?: (info: SelectedElementInfo, element: Element) => void, onStop?: () => void): () => void;
48
+ inspectElementEvidence(element: Element): SelectedElementInfo['evidence'];
49
+ startInspecting(onSelect?: (info: SelectedElementInfo, element: Element) => void, onStop?: () => void, onInspect?: (element: Element, evidence: SelectedElementInfo['evidence']) => void): () => void;
49
50
  stopInspecting(): void;
50
51
  highlightElement(element: Element): void;
51
52
  highlightElements(elements: readonly Element[]): void;
@@ -1,2 +1,2 @@
1
- import { i as installSculptedRuntime, n as RuntimeInspectorOptions, r as SculptedRuntime, t as RuntimeEnvironment } from "./runtime-C911j-aR.mjs";
1
+ import { i as installSculptedRuntime, n as RuntimeInspectorOptions, r as SculptedRuntime, t as RuntimeEnvironment } from "./runtime-C1gUOAc9.mjs";
2
2
  export { RuntimeEnvironment, RuntimeInspectorOptions, SculptedRuntime, installSculptedRuntime };
package/dist/runtime.mjs CHANGED
@@ -262,7 +262,10 @@ var SculptedRuntime = class {
262
262
  message: target?.reason ?? "Selected Panda source target is not editable."
263
263
  };
264
264
  }
265
- startInspecting(onSelect, onStop) {
265
+ inspectElementEvidence(element) {
266
+ return this.#elementEvidence(element);
267
+ }
268
+ startInspecting(onSelect, onStop, onInspect) {
266
269
  this.stopInspecting();
267
270
  const { window } = this.#environment;
268
271
  const onPointerMove = (event) => {
@@ -279,6 +282,7 @@ var SculptedRuntime = class {
279
282
  event.preventDefault();
280
283
  event.stopPropagation();
281
284
  this.stopInspecting();
285
+ onInspect?.(element, this.#elementEvidence(element));
282
286
  this.selectElement(element).then((info) => {
283
287
  onSelect?.(info, element);
284
288
  });
package/dist/ui.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { F as RuntimePropertyContext, L as SelectedElementInfo, N as RuntimeCssDeclaration, j as RuntimeComponentLayer } from "./types-CdByW0ji.mjs";
2
- import { r as SculptedRuntime } from "./runtime-C911j-aR.mjs";
2
+ import { r as SculptedRuntime } from "./runtime-C1gUOAc9.mjs";
3
3
 
4
4
  //#region src/ui/inspectorPanel.d.ts
5
5
  type ReadonlyInspectorPanelOptions = {
package/dist/ui.mjs CHANGED
@@ -1011,6 +1011,23 @@ const RefreshCw = createLucideIcon("refresh-cw", [
1011
1011
  }]
1012
1012
  ]);
1013
1013
  //#endregion
1014
+ //#region node_modules/.pnpm/lucide-preact@1.16.0_preact@10.29.2/node_modules/lucide-preact/dist/esm/icons/settings.mjs
1015
+ /**
1016
+ * @license lucide-preact v1.16.0 - ISC
1017
+ *
1018
+ * This source code is licensed under the ISC license.
1019
+ * See the LICENSE file in the root directory of this source tree.
1020
+ */
1021
+ const Settings = createLucideIcon("settings", [["path", {
1022
+ d: "M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",
1023
+ key: "1i5ecw"
1024
+ }], ["circle", {
1025
+ cx: "12",
1026
+ cy: "12",
1027
+ r: "3",
1028
+ key: "1v7zrd"
1029
+ }]]);
1030
+ //#endregion
1014
1031
  //#region node_modules/.pnpm/lucide-preact@1.16.0_preact@10.29.2/node_modules/lucide-preact/dist/esm/icons/square-dashed-mouse-pointer.mjs
1015
1032
  /**
1016
1033
  * @license lucide-preact v1.16.0 - ISC
@@ -7461,6 +7478,9 @@ const INSPECTOR_DIALOG_PORTAL_ROOT = "data-sculpted-dialog-root";
7461
7478
  const INSPECTOR_MENU_PORTAL_ROOT = "data-sculpted-menu-root";
7462
7479
  const INLINE_SOURCE_PREVIEW_PATH = ["__inlineSource"];
7463
7480
  const STYLE_MODULE_ACTION_PREVIEW_PATH = ["__styleModuleAction"];
7481
+ const COPY_ELEMENT_PATH_AFTER_INSPECT_STORAGE_KEY = "sculpted.copyElementPathAfterInspect";
7482
+ const PANEL_DOCKED_STORAGE_KEY = "sculpted.panelDocked";
7483
+ const PANEL_SIDE_STORAGE_KEY = "sculpted.panelSide";
7464
7484
  function installReadonlyInspectorPanel(runtime, options = {}) {
7465
7485
  let panel = null;
7466
7486
  let previousBodyMarginLeft;
@@ -7575,14 +7595,41 @@ function applyInspectorPanelFrame(panel, state) {
7575
7595
  panel.style.borderRadius = "8px";
7576
7596
  panel.style.boxShadow = "0 18px 54px rgba(15, 23, 42, 0.18)";
7577
7597
  }
7598
+ function loadBooleanPreference(storageKey, defaultValue) {
7599
+ try {
7600
+ const stored = window.localStorage.getItem(storageKey);
7601
+ if (stored === "true") return true;
7602
+ if (stored === "false") return false;
7603
+ } catch {}
7604
+ return defaultValue;
7605
+ }
7606
+ function saveBooleanPreference(storageKey, value) {
7607
+ try {
7608
+ window.localStorage.setItem(storageKey, value ? "true" : "false");
7609
+ } catch {}
7610
+ }
7611
+ function loadPanelSidePreference(defaultValue) {
7612
+ try {
7613
+ const stored = window.localStorage.getItem(PANEL_SIDE_STORAGE_KEY);
7614
+ if (stored === "left" || stored === "right") return stored;
7615
+ } catch {}
7616
+ return defaultValue;
7617
+ }
7618
+ function savePanelSidePreference(value) {
7619
+ try {
7620
+ window.localStorage.setItem(PANEL_SIDE_STORAGE_KEY, value);
7621
+ } catch {}
7622
+ }
7578
7623
  function InspectorPanel(props) {
7579
7624
  const { runtime, title, onFrameChange } = props;
7580
7625
  const selected = useSignal();
7581
7626
  const visible = useSignal(false);
7582
- const docked = useSignal(false);
7583
- const side = useSignal("right");
7627
+ const docked = useSignal(loadBooleanPreference(PANEL_DOCKED_STORAGE_KEY, false));
7628
+ const side = useSignal(loadPanelSidePreference("right"));
7584
7629
  const isInspecting = useSignal(false);
7630
+ const settingsOpen = useSignal(false);
7585
7631
  const previewEnabled = useSignal(true);
7632
+ const copyElementPathAfterInspect = useSignal(loadBooleanPreference(COPY_ELEMENT_PATH_AFTER_INSPECT_STORAGE_KEY, false));
7586
7633
  const forcedPreviewStates = useSignal(/* @__PURE__ */ new Set());
7587
7634
  const pendingPreviewChanges = useSignal(/* @__PURE__ */ new Map());
7588
7635
  const expandedShorthandInputs = useSignal(/* @__PURE__ */ new Set());
@@ -7593,6 +7640,7 @@ function InspectorPanel(props) {
7593
7640
  const elementStyleModule = useSignal({ status: "idle" });
7594
7641
  const showingStyleModulePage = useComputed(() => styleModulePanel.value.status !== "idle");
7595
7642
  const panelHeaderTitle = useComputed(() => {
7643
+ if (settingsOpen.value) return "Settings";
7596
7644
  return styleModulePanel.value.status === "idle" ? title : "Style List";
7597
7645
  });
7598
7646
  const editorMetadata = useSignal();
@@ -7923,6 +7971,11 @@ function InspectorPanel(props) {
7923
7971
  isInspecting.value = false;
7924
7972
  clearInspectCursor();
7925
7973
  };
7974
+ const copyInspectedElementPath = (evidence) => {
7975
+ if (!copyElementPathAfterInspect.value) return;
7976
+ const identity = inspectedElementIdentityFromLayers(evidence?.componentLayers ?? []);
7977
+ if (identity) navigator.clipboard?.writeText(identity).catch(() => {});
7978
+ };
7926
7979
  const isPanelEditableFocused = () => {
7927
7980
  const root = shell.current?.getRootNode();
7928
7981
  const active = root && isShadowRoot(root) ? root.activeElement : document.activeElement;
@@ -7971,6 +8024,7 @@ function InspectorPanel(props) {
7971
8024
  document.getSelection()?.removeAllRanges();
7972
8025
  stopActiveInspecting();
7973
8026
  clearModifierPreview();
8027
+ copyInspectedElementPath(typeof runtime.inspectElementEvidence === "function" ? runtime.inspectElementEvidence(element) : void 0);
7974
8028
  runtime.selectElement(element).then((info) => {
7975
8029
  selectedElement.current = element;
7976
8030
  selectedElementAutofocusRevision.value += 1;
@@ -8015,9 +8069,12 @@ function InspectorPanel(props) {
8015
8069
  selectedElement.current = element;
8016
8070
  selectedElementAutofocusRevision.value += 1;
8017
8071
  selected.value = info;
8072
+ settingsOpen.value = false;
8018
8073
  applyPreviewChanges(pendingPreviewChanges.value, previewEnabled.value);
8019
8074
  setPanelVisible(true);
8020
- }, onStopInspecting);
8075
+ }, onStopInspecting, (_element, evidence) => {
8076
+ copyInspectedElementPath(evidence);
8077
+ });
8021
8078
  isInspecting.value = true;
8022
8079
  setInspectCursor();
8023
8080
  };
@@ -8050,6 +8107,7 @@ function InspectorPanel(props) {
8050
8107
  };
8051
8108
  const toggleDocked = () => {
8052
8109
  docked.value = !docked.value;
8110
+ saveBooleanPreference(PANEL_DOCKED_STORAGE_KEY, docked.value);
8053
8111
  onFrameChange({
8054
8112
  visible: visible.value,
8055
8113
  docked: docked.value,
@@ -8059,12 +8117,20 @@ function InspectorPanel(props) {
8059
8117
  const snapPanelSide = (nextSide) => {
8060
8118
  if (side.value === nextSide) return;
8061
8119
  side.value = nextSide;
8120
+ savePanelSidePreference(nextSide);
8062
8121
  onFrameChange({
8063
8122
  visible: visible.value,
8064
8123
  docked: docked.value,
8065
8124
  side: nextSide
8066
8125
  });
8067
8126
  };
8127
+ const openSettings = () => {
8128
+ settingsOpen.value = true;
8129
+ };
8130
+ const updateCopyElementPathAfterInspect = (enabled) => {
8131
+ copyElementPathAfterInspect.value = enabled;
8132
+ saveBooleanPreference(COPY_ELEMENT_PATH_AFTER_INSPECT_STORAGE_KEY, enabled);
8133
+ };
8068
8134
  const togglePreview = (enabled) => {
8069
8135
  previewEnabled.value = enabled;
8070
8136
  applyPreviewChanges(pendingPreviewChanges.value, enabled);
@@ -8469,8 +8535,10 @@ function InspectorPanel(props) {
8469
8535
  title: panelHeaderTitle,
8470
8536
  isInspecting,
8471
8537
  docked,
8472
- showInspect: !showingStyleModulePage.value,
8473
- onBack: showingStyleModulePage.value ? () => {
8538
+ showInspect: !showingStyleModulePage.value && !settingsOpen.value,
8539
+ onBack: settingsOpen.value ? () => {
8540
+ settingsOpen.value = false;
8541
+ } : showingStyleModulePage.value ? () => {
8474
8542
  styleModulePanel.value = { status: "idle" };
8475
8543
  } : void 0,
8476
8544
  onInspect: toggleInspecting,
@@ -8481,6 +8549,7 @@ function InspectorPanel(props) {
8481
8549
  disabled: saving,
8482
8550
  onUndoPreview: undoPreviewChange,
8483
8551
  onRedoPreview: redoPreviewChange,
8552
+ onSettings: openSettings,
8484
8553
  onToggleDocked: toggleDocked,
8485
8554
  onToggleSide: () => {
8486
8555
  snapPanelSide(side.value === "right" ? "left" : "right");
@@ -8494,11 +8563,15 @@ function InspectorPanel(props) {
8494
8563
  flex: "1 1 auto",
8495
8564
  padding: "12px",
8496
8565
  display: "grid",
8566
+ alignContent: "start",
8497
8567
  gap: "12px",
8498
8568
  overflow: "auto",
8499
8569
  minHeight: 0
8500
8570
  },
8501
- children: [/* @__PURE__ */ u(SaveStatusSection, { saveFlow }), showingStyleModulePage.value ? /* @__PURE__ */ u(StyleModuleSection, {
8571
+ children: [/* @__PURE__ */ u(SaveStatusSection, { saveFlow }), settingsOpen.value ? /* @__PURE__ */ u(SettingsSection, {
8572
+ copyElementPathAfterInspect,
8573
+ onCopyElementPathAfterInspectChange: updateCopyElementPathAfterInspect
8574
+ }) : showingStyleModulePage.value ? /* @__PURE__ */ u(StyleModuleSection, {
8502
8575
  state: styleModulePanel,
8503
8576
  pendingChanges: pendingPreviewChanges,
8504
8577
  preview,
@@ -9015,6 +9088,22 @@ function PanelHeader(props) {
9015
9088
  children: "Clear"
9016
9089
  })]
9017
9090
  })
9091
+ }),
9092
+ /* @__PURE__ */ u(ShadowMenuItem, {
9093
+ class: "sculpted-menu-item",
9094
+ disabled: props.disabled.value,
9095
+ onSelect: props.onSettings,
9096
+ children: /* @__PURE__ */ u("span", {
9097
+ "data-menu-action": "settings",
9098
+ style: { display: "contents" },
9099
+ children: [/* @__PURE__ */ u(Settings, {
9100
+ size: 15,
9101
+ "aria-hidden": "true"
9102
+ }), /* @__PURE__ */ u("span", {
9103
+ style: { font: "inherit" },
9104
+ children: "Settings"
9105
+ })]
9106
+ })
9018
9107
  })
9019
9108
  ]
9020
9109
  })]
@@ -9064,6 +9153,39 @@ function SaveStatusSection(props) {
9064
9153
  children: /* @__PURE__ */ u("div", { children: state.message })
9065
9154
  });
9066
9155
  }
9156
+ function SettingsSection(props) {
9157
+ return /* @__PURE__ */ u("section", {
9158
+ "data-settings-section": "true",
9159
+ style: {
9160
+ display: "grid",
9161
+ gap: "10px"
9162
+ },
9163
+ children: /* @__PURE__ */ u("label", {
9164
+ style: {
9165
+ display: "flex",
9166
+ alignItems: "center",
9167
+ justifyContent: "space-between",
9168
+ gap: "12px",
9169
+ border: "1px solid #d6dde8",
9170
+ borderRadius: "6px",
9171
+ padding: "10px",
9172
+ cursor: "pointer"
9173
+ },
9174
+ children: [/* @__PURE__ */ u("span", {
9175
+ style: { fontWeight: 700 },
9176
+ children: "Copy element path after inspect"
9177
+ }), /* @__PURE__ */ u("input", {
9178
+ type: "checkbox",
9179
+ "data-setting": "copy-element-path-after-inspect",
9180
+ checked: props.copyElementPathAfterInspect.value,
9181
+ onChange: (event) => {
9182
+ props.onCopyElementPathAfterInspectChange(event.currentTarget.checked);
9183
+ },
9184
+ style: { margin: 0 }
9185
+ })]
9186
+ })
9187
+ });
9188
+ }
9067
9189
  function StyleModuleSection(props) {
9068
9190
  const { state, pendingChanges, preview, forcedPreviewStates, expandedShorthandInputs, shorthandFocusRequest, colorTokenOptions, fontTokenOptions, tokenSources, propertyOptions, saving, addedInputActivationRequest, onPreviewInput, onCreateColorToken, onAddedInputActivationHandled, onAddProperty, onRemoveProperty, onFocusRestoreButton, onFocusPreviewControl, onRestoreProperty, onHighlightSourceTarget, onClearHighlight, onOpenSource, onInputMenuOpenChange, onToggleShorthandInput, onExpandShorthandInput, onCollapseShorthandInput, onRequestShorthandFocus, onShorthandFocusRequestHandled, onAddSource } = props;
9069
9191
  if (state.value.status === "idle") return null;
@@ -10977,11 +11099,19 @@ function ComponentLayersSection(props) {
10977
11099
  })] });
10978
11100
  }
10979
11101
  function componentLayerElementIdentity(view, layerIndex, elementIndex, jsxSource) {
10980
- const layers = view.componentLayers;
11102
+ return componentLayerElementIdentityFromLayers(view.componentLayers, layerIndex, elementIndex, jsxSource);
11103
+ }
11104
+ function componentLayerElementIdentityFromLayers(layers, layerIndex, elementIndex, jsxSource) {
10981
11105
  const parentComponents = layers.slice(layerIndex).toReversed().map((layer) => layer.component);
10982
11106
  const elementPath = layers[layerIndex]?.elements.slice(elementIndex).toReversed().map((element) => element.tagName);
10983
11107
  return `I want to edit the following JSX element:\n ${[...parentComponents, ...elementPath ?? []].join(" → ")}${sourceLocationAvailable(jsxSource) ? `\n (found at ${jsxSource})` : ""}\n\n\n`;
10984
11108
  }
11109
+ function inspectedElementIdentityFromLayers(layers) {
11110
+ for (const [layerIndex, layer] of layers.entries()) {
11111
+ const elementIndex = layer.elements.findIndex((element) => element.inspected === true);
11112
+ if (elementIndex !== -1) return componentLayerElementIdentityFromLayers(layers, layerIndex, elementIndex, layer.elements[elementIndex]?.source);
11113
+ }
11114
+ }
10985
11115
  function componentLayerSource(layer) {
10986
11116
  return layer.elements.find((element) => sourceLocationAvailable(element.source))?.source;
10987
11117
  }
@@ -11031,12 +11161,19 @@ function ComputedRowsSection(props) {
11031
11161
  gridTemplateColumns: "120px 1fr",
11032
11162
  gap: "8px",
11033
11163
  marginTop: "4px",
11034
- color: "#526070"
11164
+ color: "#526070",
11165
+ userSelect: "text"
11035
11166
  },
11036
- children: [/* @__PURE__ */ u("code", { children: row.property }), /* @__PURE__ */ u("code", {
11167
+ children: [/* @__PURE__ */ u("code", {
11168
+ "data-computed-css-property": "true",
11169
+ style: { userSelect: "text" },
11170
+ children: row.property
11171
+ }), /* @__PURE__ */ u("code", {
11172
+ "data-computed-css-value": "true",
11037
11173
  style: {
11038
11174
  whiteSpace: "normal",
11039
- wordBreak: "break-word"
11175
+ wordBreak: "break-word",
11176
+ userSelect: "text"
11040
11177
  },
11041
11178
  children: row.value
11042
11179
  })]
package/dist/vite.d.mts CHANGED
@@ -9,12 +9,8 @@ type InspectorVitePluginOptions = {
9
9
  readonly panda?: {
10
10
  readonly configPath?: string;
11
11
  readonly cssImportSources?: readonly string[];
12
- readonly recipeImportSources?: readonly string[];
13
- readonly cssFunctionNames?: readonly string[];
14
- readonly cxFunctionNames?: readonly string[];
15
12
  };
16
13
  readonly manifest?: {
17
- readonly outFile?: string;
18
14
  readonly virtualEndpoint?: string;
19
15
  };
20
16
  readonly metadata?: {
@@ -22,13 +18,6 @@ type InspectorVitePluginOptions = {
22
18
  };
23
19
  readonly runtime?: {
24
20
  readonly inject?: boolean;
25
- readonly globalName?: string;
26
- };
27
- readonly attributes?: {
28
- readonly editId?: string;
29
- readonly source?: string;
30
- readonly jsxSource?: string;
31
- readonly component?: string;
32
21
  };
33
22
  readonly sourceSyntax?: SourceSyntaxOption;
34
23
  };
package/dist/vite.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as markerClassForEditId, c as DEFAULT_OPEN_SOURCE_ENDPOINT, d as DEFAULT_TOKEN_WRITEBACK_ENDPOINT, f as DEFAULT_WRITEBACK_ENDPOINT, p as SCULPTED_EVENTS, u as DEFAULT_STYLE_MODULE_ENDPOINT } from "./protocol-D5heR2QM.mjs";
1
+ import { _ as markerClassForEditId, a as DEFAULT_JSX_SOURCE_ATTRIBUTE, c as DEFAULT_OPEN_SOURCE_ENDPOINT, d as DEFAULT_TOKEN_WRITEBACK_ENDPOINT, f as DEFAULT_WRITEBACK_ENDPOINT, l as DEFAULT_SOURCE_ATTRIBUTE, p as SCULPTED_EVENTS, r as DEFAULT_EDIT_ID_ATTRIBUTE, t as DEFAULT_COMPONENT_ATTRIBUTE, u as DEFAULT_STYLE_MODULE_ENDPOINT } from "./protocol-D5heR2QM.mjs";
2
2
  import { S as resolveSourceParserAdapter, _ as analyzePandaCssSource, a as createStyleModuleSourcePatch, b as parsePandaSource, c as resolveProjectPath, d as toRelativeProjectPath$1, f as trustedManifestFilePath, g as createInlineCssSourcePatch, h as createStaticCssPatch, i as createStyleModuleDetachPatch, l as safeProjectSourcePath, m as createStaticCssBatchPatch, n as componentStyleModulePaths, o as readComponentStyleModule, p as trustedTokenSourceFilePath, r as createStyleModuleAttachPatch, s as normalizePath$1, t as createTokenConfigPatch, u as stripViteQuery, v as hashSource } from "./patcher-DQgKdozw.mjs";
3
3
  import ts from "typescript";
4
4
  import { access, mkdir, readFile, writeFile } from "node:fs/promises";
@@ -998,7 +998,6 @@ function registerRuntimeModuleRoutes(server, options) {
998
998
  response.end(runtimeBootstrapSource({
999
999
  manifestEndpoint: options.manifestEndpoint,
1000
1000
  editorMetadataEndpoint: options.editorMetadataEndpoint,
1001
- globalName: options.globalName,
1002
1001
  runtimeModuleEndpoint: options.runtimeModuleEndpoint,
1003
1002
  uiModuleEndpoint: options.uiModuleEndpoint
1004
1003
  }));
@@ -1084,7 +1083,6 @@ function registerRuntimeModuleRoutes(server, options) {
1084
1083
  }
1085
1084
  function runtimeBootstrapSource(options) {
1086
1085
  const runtimeOptions = JSON.stringify({
1087
- globalName: options.globalName,
1088
1086
  manifestEndpoint: options.manifestEndpoint,
1089
1087
  editorMetadataEndpoint: options.editorMetadataEndpoint
1090
1088
  });
@@ -2189,10 +2187,10 @@ function sculpted(options = {}) {
2189
2187
  const uiModuleEndpoint = DEFAULT_UI_MODULE_ENDPOINT;
2190
2188
  const runtimeChunkEndpoint = DEFAULT_RUNTIME_CHUNK_ENDPOINT;
2191
2189
  const attributes = {
2192
- editId: options.attributes?.editId ?? "data-sculpted-edit-id",
2193
- source: options.attributes?.source ?? "data-sculpted-source",
2194
- jsxSource: options.attributes?.jsxSource ?? "data-sculpted-jsx-source",
2195
- component: options.attributes?.component ?? "data-sculpted-component"
2190
+ editId: DEFAULT_EDIT_ID_ATTRIBUTE,
2191
+ source: DEFAULT_SOURCE_ATTRIBUTE,
2192
+ jsxSource: DEFAULT_JSX_SOURCE_ATTRIBUTE,
2193
+ component: DEFAULT_COMPONENT_ATTRIBUTE
2196
2194
  };
2197
2195
  let projectRoot = normalizePath$1(options.projectRoot ?? "");
2198
2196
  let devEnabled = options.enabled !== false;
@@ -2273,7 +2271,6 @@ function sculpted(options = {}) {
2273
2271
  registerRuntimeModuleRoutes(nextServer, {
2274
2272
  manifestEndpoint: endpoint,
2275
2273
  editorMetadataEndpoint,
2276
- globalName: options.runtime?.globalName,
2277
2274
  runtimeBootstrapEndpoint,
2278
2275
  runtimeModuleEndpoint,
2279
2276
  uiModuleEndpoint,
package/docs/examples.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Example Apps
2
2
 
3
- Sculpted includes minimal Vite + Panda CSS apps for manually verifying inspector behavior and source
4
- writeback while the package is being built.
3
+ Sculpted includes minimal Vite + Panda CSS apps for contributors who need to manually verify
4
+ inspector behavior and source writeback while developing the package.
5
5
 
6
6
  ## React
7
7
 
@@ -26,5 +26,5 @@ pnpm install
26
26
  pnpm dev
27
27
  ```
28
28
 
29
- Use these apps to verify supported edits, unsupported read-only cases, token creation checks, React
30
- `className`, Preact `class`, TSRX parsing, and production-dark behavior while developing Sculpted.
29
+ These apps intentionally include edge cases and maintainer-focused checks. Most users should start
30
+ with the setup examples in the main README instead.
@@ -1,13 +1,8 @@
1
1
  # Source Syntax Adapters
2
2
 
3
- Sculpted can support non-standard source syntax when a parser adapter exposes stable ranges into
4
- the original authoring source. The patcher edits that original file directly after revalidating
5
- hashes, source containment, and AST shape.
6
-
7
- Sourcemaps are not the writeback authority. A future fallback may use sourcemaps to explain
8
- generated-code provenance, but safe writes still require an original-source parser and patchable
9
- target. If the adapter cannot provide stable original ranges for a source shape, Sculpted should
10
- report that target as read-only.
3
+ Sculpted can support non-standard source syntax when that syntax can be parsed back to stable
4
+ locations in the original authoring file. Unsupported source shapes are shown as read-only instead
5
+ of guessed.
11
6
 
12
7
  ## TSRX Support
13
8
 
@@ -30,17 +25,6 @@ export default defineConfig({
30
25
  })
31
26
  ```
32
27
 
33
- When a config imports more than one syntax adapter, alias the TSRX export at the import site:
34
-
35
- ```ts
36
- import { sourceSyntax as tsrx } from 'sculpted/tsrx'
37
-
38
- sculpted({
39
- include: ['src/**/*.{ts,tsx,tsrx,view}'],
40
- sourceSyntax: [tsrx, customViewSyntax],
41
- })
42
- ```
43
-
44
28
  The supported TSRX authoring shape is a TSRX component with a static Panda `css({ ... })` object:
45
29
 
46
30
  ```ts
@@ -56,38 +40,11 @@ export function Card() {
56
40
  TSRX support covers:
57
41
 
58
42
  - static `css({ ... })` object literal analysis;
59
- - marker-class instrumentation for element selection;
60
- - existing literal `set` writeback after re-parsing the original `.tsrx` source.
43
+ - element selection in the inspector;
44
+ - saving edits to existing literal values in the original `.tsrx` source.
61
45
 
62
46
  TSRX support does not cover:
63
47
 
64
- - direct `data-panda-*` metadata insertion;
65
48
  - inline source creation;
66
49
  - add, delete, or rename operations;
67
- - generated TSX or sourcemap-based writeback authority.
68
-
69
- ## Custom Adapters
70
-
71
- Languages that can expose original source ranges can opt into the same writeback lane with a
72
- `sourceSyntax` parser adapter. The option accepts one adapter or an ordered adapter list.
73
-
74
- ```ts
75
- sculpted({
76
- include: ['src/**/*.view'],
77
- sourceSyntax: {
78
- languageId: 'my-tsx-superset',
79
- kind: 'typescript',
80
- isSupportedFile: (file) => file.endsWith('.view'),
81
- parse({ filePath, sourceText }) {
82
- return {
83
- kind: 'typescript',
84
- languageId: 'my-tsx-superset',
85
- sourceFile: parseToTypeScriptCompatibleSourceFile(filePath, sourceText),
86
- }
87
- },
88
- },
89
- })
90
- ```
91
-
92
- Parser adapters must expose node ranges as offsets into the original authoring source text. Use
93
- read-only failures for any syntax that cannot provide stable original ranges for a source shape.
50
+ - generated TSX or sourcemap-based writeback.
@@ -31,17 +31,12 @@ Sculpted does not edit:
31
31
 
32
32
  ## Safety Model
33
33
 
34
- Source writes are revalidated on the dev server before writing:
34
+ Source writes are revalidated on the dev server before writing. Sculpted only writes to files inside
35
+ the configured project root, re-checks the current source before saving, and rejects stale source,
36
+ unsupported shapes, duplicate keys, parser errors, and unsafe paths.
35
37
 
36
- - the browser sends manifest edit IDs, not trusted file paths;
37
- - the server resolves edit IDs through the trusted manifest;
38
- - the patcher re-reads source and validates project-root containment;
39
- - stale source hashes, unsupported source shapes, duplicate keys, parse errors, and path escapes are
40
- rejected;
41
- - batched saves apply same-file edits against one source snapshot before writing.
42
-
43
- The UI saves immediately after clicking Save. The writeback endpoint still supports dry-run patch
44
- responses with focused diffs for tests and tooling.
38
+ The UI saves immediately after clicking Save. If a save cannot be applied confidently, Sculpted
39
+ shows the failure instead of guessing at a source edit.
45
40
 
46
41
  ## Supported Edit Example
47
42
 
@@ -68,12 +68,8 @@ type InspectorVitePluginOptions = {
68
68
  readonly panda?: {
69
69
  readonly configPath?: string
70
70
  readonly cssImportSources?: readonly string[]
71
- readonly recipeImportSources?: readonly string[]
72
- readonly cssFunctionNames?: readonly string[]
73
- readonly cxFunctionNames?: readonly string[]
74
71
  }
75
72
  readonly manifest?: {
76
- readonly outFile?: string
77
73
  readonly virtualEndpoint?: string
78
74
  }
79
75
  readonly metadata?: {
@@ -81,13 +77,6 @@ type InspectorVitePluginOptions = {
81
77
  }
82
78
  readonly runtime?: {
83
79
  readonly inject?: boolean
84
- readonly globalName?: string
85
- }
86
- readonly attributes?: {
87
- readonly editId?: string
88
- readonly source?: string
89
- readonly jsxSource?: string
90
- readonly component?: string
91
80
  }
92
81
  readonly sourceSyntax?: SourceSyntaxOption
93
82
  }
@@ -169,12 +158,6 @@ sculpted({
169
158
  })
170
159
  ```
171
160
 
172
- ### Reserved Panda Options
173
-
174
- `panda.recipeImportSources`, `panda.cssFunctionNames`, and `panda.cxFunctionNames` are part of the
175
- public option type but are not wired into the Vite plugin implementation. Recipes, patterns,
176
- `cva()`, and broader function-name customization are not supported.
177
-
178
161
  ### `manifest.virtualEndpoint`
179
162
 
180
163
  Defaults to `/@sculpted/manifest`.
@@ -190,10 +173,6 @@ sculpted({
190
173
  })
191
174
  ```
192
175
 
193
- ### `manifest.outFile`
194
-
195
- Reserved. The option is typed but not wired into the Vite plugin implementation.
196
-
197
176
  ### `metadata.virtualEndpoint`
198
177
 
199
178
  Defaults to `/@sculpted/editor-metadata`.
@@ -223,46 +202,10 @@ sculpted({
223
202
  })
224
203
  ```
225
204
 
226
- ### `runtime.globalName`
227
-
228
- Overrides the browser global name used by the installed runtime.
229
-
230
- ```ts
231
- sculpted({
232
- runtime: {
233
- globalName: '__mySculptedRuntime',
234
- },
235
- })
236
- ```
237
-
238
- ### `attributes`
239
-
240
- Overrides the DOM attributes used for inspector metadata.
241
-
242
- Defaults:
243
-
244
- - `editId`: `data-sculpted-edit-id`
245
- - `source`: `data-sculpted-source`
246
- - `jsxSource`: `data-sculpted-jsx-source`
247
- - `component`: `data-sculpted-component`
248
-
249
- Use these only when the defaults collide with app-specific tooling.
250
-
251
- ```ts
252
- sculpted({
253
- attributes: {
254
- editId: 'data-dev-edit-id',
255
- source: 'data-dev-source',
256
- jsxSource: 'data-dev-jsx-source',
257
- component: 'data-dev-component',
258
- },
259
- })
260
- ```
261
-
262
205
  ### `sourceSyntax`
263
206
 
264
- Adds one source parser adapter, or an ordered list of adapters, for non-standard source syntax that
265
- can expose original source ranges. See [source syntax adapters](source-syntax-adapters.md).
207
+ Adds source parsing support for non-standard source syntax. Sculpted currently documents this for
208
+ the bundled TSRX adapter. See [source syntax adapters](source-syntax-adapters.md).
266
209
 
267
210
  ```ts
268
211
  import { sourceSyntax } from 'sculpted/tsrx'
@@ -273,30 +216,8 @@ sculpted({
273
216
  })
274
217
  ```
275
218
 
276
- If the config combines multiple adapters, alias the TSRX export where it is imported:
277
-
278
- ```ts
279
- import { sourceSyntax as tsrx } from 'sculpted/tsrx'
280
-
281
- sculpted({
282
- include: ['src/**/*.{ts,tsx,tsrx,view}'],
283
- sourceSyntax: [tsrx, customViewSyntax],
284
- })
285
- ```
286
-
287
- ## Endpoint Defaults
288
-
289
- These endpoint defaults are fixed unless an option above says otherwise:
290
-
291
- - Manifest: `/@sculpted/manifest`
292
- - Editor metadata: `/@sculpted/editor-metadata`
293
- - Source writeback: `/@sculpted/writeback`
294
- - Token writeback: `/@sculpted/token-writeback`
295
- - Open source location: `/@sculpted/open-source`
296
- - Style module route: `/@sculpted/style-module`
297
- - Runtime bootstrap: `/@sculpted/runtime`
298
- - Runtime module: `/@sculpted/runtime-module`
299
- - UI module: `/@sculpted/ui-module`
219
+ ## Development Routes
300
220
 
301
- The writeback, token writeback, open-source, style-module, and runtime module endpoints are internal
302
- runtime contracts today. They are listed here so local tooling can avoid route collisions.
221
+ Sculpted reserves development-only routes under `/@sculpted/*`. The manifest and editor metadata
222
+ routes can be customized with `manifest.virtualEndpoint` and `metadata.virtualEndpoint`; other
223
+ routes are internal runtime details and should not be treated as public integration points.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sculpted",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Experimental alpha dev inspector for editing Panda CSS styles and writing safe source updates.",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "author": "Alec Larson",