@hazem3500/komo 0.9.27 → 0.9.29
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 +21 -6
- package/dist/adapters/react-fiber.d.ts +8 -4
- package/dist/adapters/react-fiber.js +1 -1
- package/dist/adapters/react-preview.d.ts +16 -0
- package/dist/adapters/react-preview.js +1 -0
- package/dist/chunk-HTMUFH7I.js +1 -0
- package/dist/chunk-YSTPKET2.js +1 -0
- package/dist/design-mode.js +1 -1
- package/dist/design-system.d.ts +23 -1
- package/dist/index.js +1 -1
- package/dist/{inline-text-editor-F4CSRB4G.js → inline-text-editor-OMRCO3H3.js} +1 -1
- package/dist/node.mjs +1 -1
- package/dist/pin-move-6QISN27D.js +1 -0
- package/dist/pin-move.d.ts +22 -0
- package/dist/react-inspector.d.ts +7 -6
- package/dist/react-props-panel-Y7F2P3AG.js +1 -0
- package/dist/react-props-panel.d.ts +4 -4
- package/dist/react.js +1 -1
- package/dist/server.js +1 -1
- package/dist/setup.js +1 -1
- package/package.json +7 -1
- package/server/setup-client.txt +46 -39
- package/dist/chunk-K6ETEZER.js +0 -1
- package/dist/chunk-ZSDIMEPV.js +0 -1
- package/dist/react-props-panel-MN5XOAGL.js +0 -1
package/README.md
CHANGED
|
@@ -80,11 +80,14 @@ Comments are shared across deployments by default. Use `pnpm exec komo init --br
|
|
|
80
80
|
- Group tags: add them while writing a comment or on an open thread, with suggestions from tags already in the project.
|
|
81
81
|
- Safe HTTP(S) links and simple Markdown links in comment messages.
|
|
82
82
|
- Searchable sidebar, draggable dock, and Google or guest profiles.
|
|
83
|
+
|
|
83
84
|
- Dismiss the toolbar for the current tab with ×; restore it with Shift+K or `controller.open()`. Set `showToolbar: false` to start hidden.
|
|
84
85
|
- Keyboard shortcuts: C to comment, V to browse, D to toggle Design mode, L to view all comments, Shift+K to restore. Remap or disable them with `shortcuts`; see [Choosing shortcuts](#choosing-shortcuts).
|
|
85
86
|
- Copy open feedback with selectors, source paths, page URLs, replies, and geometry into an agent.
|
|
86
87
|
- Hosted Cloudflare storage, or your own Worker/D1 or Node/PostgreSQL service.
|
|
87
88
|
|
|
89
|
+
Comment pins stay anchored during ordinary pointer drags. Authors and verified reviewers can choose **Comment actions → Move pin** to reposition one explicitly: drag it, or use arrow keys (Shift for larger steps), then Enter or **Save position**. Escape or **Cancel move** restores its previous position without saving. Completed moves use the existing thread anchor endpoint and remain attached after reload; the page element itself never moves. Dragging a floating comment card is independent of pin placement.
|
|
90
|
+
|
|
88
91
|
Design mode edits the rendered page only. Preview styles and inline text edits are temporary and reset when the page refreshes; styles are restored when the Komo widget is destroyed. Use **Copy CSS** to apply a rule in your site stylesheet; Komo does not write source files. Double-click text, or use **Edit text**, to edit it inline. Edits accept plain text only and change text in place: nested markup, links, and buttons keep their structure. Text marked `data-private` or `data-sensitive`, form fields, and text inside graphics, media, or frames stay read-only. An explicitly registered React `textProp` routes edits through the app's state callback. The inspector can select an iframe as one element but cannot edit its isolated contents. Elements inside open or closed shadow roots are not traversed; select the component host instead.
|
|
89
92
|
|
|
90
93
|
The design inspector loads as a separate optional browser chunk when Design mode is first opened, so the default widget load does not pay its bundle cost. The package size check measures this chunk separately from the core bundle.
|
|
@@ -95,7 +98,7 @@ Design mode also takes interaction cues from established design tools: select a
|
|
|
95
98
|
|
|
96
99
|
### Opt-in React prop inspection
|
|
97
100
|
|
|
98
|
-
React teams can register selected component roots for typed prop previews through the `./react` entry. A build-time TypeScript Compiler API pass generates the prop manifest from an explicitly marked function component and props type; the inspector edits only strings, numbers, booleans, and literal unions. Functions, `ReactNode`, objects, generics
|
|
101
|
+
React teams can register selected component roots for typed prop previews through the `./react` entry. A build-time TypeScript Compiler API pass generates the prop manifest from an explicitly marked function component and props type; the inspector edits only strings, numbers, booleans, and literal unions. Functions, refs, `ReactNode`, objects, generics and unsupported types are omitted from editable controls. This metadata is a safe allowlist, not runtime discovery of every React component; `defaultProps` and every React component form are not inferred.
|
|
99
102
|
|
|
100
103
|
The app provides an `onChange` callback that updates its own state. Komo previews those values through React's normal render cycle, offers undo/reset, and can prefill an explicit comment with the proposed before/after values and source path. Posting still requires the user to submit the comment. Komo's core never accesses React Fiber internals and never writes source files; the one exception is the separate, opt-in [React fiber adapter](#discovering-react-components), which reads React internals only for apps that install it. Preview prop changes reset on refresh. A component may opt one leaf render into direct text editing by setting `textProp` to the name of an allowed string prop; Komo does not infer which child text belongs to a prop. See [`examples/react-props`](./examples/react-props/README.md) for the generated fixture and limitations.
|
|
101
104
|
|
|
@@ -214,9 +217,21 @@ initKomo({ project, design: { components: discoverReactComponents() } });
|
|
|
214
217
|
```
|
|
215
218
|
|
|
216
219
|
- **What it reads.** The `__reactFiber$*` key React puts on DOM nodes (or, when present, the renderers of `window.__REACT_DEVTOOLS_GLOBAL_HOOK__`), then `return`/`child` links, `memoizedProps`, `_debugSource` (React 18) and `_debugStack` (React 19 dev). It climbs from the picked element, through shadow hosts, to the nearest function, class, `forwardRef` or `memo` component, and picks that fiber's current copy so props are not stale after updates. Several React roots and renderers on a page are fine.
|
|
217
|
-
- **
|
|
218
|
-
- **
|
|
219
|
-
- **
|
|
220
|
+
- **Useful props first.** Strings, finite numbers and booleans appear in **Discovered props**. Callbacks, refs, undefined values, React children, opaque objects and framework internals are omitted without invoking getters. Technical primitive attributes are in collapsed **Advanced attributes**; `aria-label` stays with useful props. Secret-looking names and `redact(name)` matches are excluded from both the panel and proposals. `maxProps` (24) and `maxString` (80) bound the display.
|
|
221
|
+
- **Location and precedence.** “Rendered at `file:line`” identifies the JSX call site. Use `resolveSource(file, line, column)` to map bundled locations. Explicit `useKomoInspectable` registrations and your own `adapter` win. A descendant points to its component root; props edit that instance only.
|
|
222
|
+
- **Runtime editing is optional.** Import `@hazem3500/komo/adapters/react-preview` before the first `react-dom/client` import, then use `discoverReactComponents({ edit: true })`. The separate bootstrap captures React 18/19 development renderer capabilities, preserves an existing DevTools hook, and calls the renderer's own prop override method. It never assigns Fiber fields. Production and unsupported renderers, or renderers whose capabilities were not captured, stay read-only. Discovered class components need an explicit editor/registration. Import order matters: calling the installer after React has loaded cannot recover missing renderer capabilities.
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
// First import in the app's development entry, before its React/router graph.
|
|
226
|
+
import "@hazem3500/komo/adapters/react-preview";
|
|
227
|
+
// In the lazily enabled feedback configuration:
|
|
228
|
+
const components = discoverReactComponents({ edit: true });
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Primitive controls use current prop types. Declare optional or enum controls through `schema(identity)` when you have component metadata; runtime discovery cannot infer a union from one string. Edits stay applied through parent re-renders, suspend outside Design, and support Before/After, Undo, per-field Reset and Reset all. Reset restores the pre-edit value and releases the override; unmounting never transfers it to another instance. These are runtime previews, with proposed changes available for comments, not source edits.
|
|
232
|
+
|
|
233
|
+
For a framework-independent integration, a `ComponentAdapter` may supply `editor(identity)` returning a stable `ComponentEditor` with `schema`, `read()` and `apply(next)`. Apply through the app's state or supported renderer API, preserve other props, and keep the preview stable through re-renders. Optional `available()` rejects detached instances; `release(properties)` stops retaining overrides after baseline restoration, and `subscribe(listener)` refreshes computed controls after a render commits. Existing `useKomoInspectable` registrations remain supported and take precedence.
|
|
234
|
+
|
|
220
235
|
- **Graceful no-op.** Every access is guarded. Non-React pages, unknown React versions or fiber shapes, production builds and hostile props yield nothing rather than an error. Production React keeps no debug fields, so there is no location; names that look minified (one or two characters) or are missing are not shown. `include(name)` hides components you don't want listed.
|
|
221
236
|
- **Fragile by design.** These fields are private React implementation details, and React can rename or remove them in any release. React 18.3 and 19.2 are tested here (unit tests and a Chrome run of the demo for each); another version may quietly show nothing until the adapter is updated. If that matters more than convenience, register the components you care about with `useKomoInspectable` instead.
|
|
222
237
|
|
|
@@ -235,13 +250,13 @@ const mode = classTheme({
|
|
|
235
250
|
});
|
|
236
251
|
const product = classTheme({
|
|
237
252
|
id: "product",
|
|
238
|
-
options: [{ id: "
|
|
253
|
+
options: [{ id: "studio", attribute: { "data-product": "studio" } }, { id: "docs", attribute: { "data-product": "docs" } }],
|
|
239
254
|
});
|
|
240
255
|
|
|
241
256
|
// Generate this from your design-system foundations.
|
|
242
257
|
const tokens: TailwindToken[] = [
|
|
243
258
|
{ path: "color.text.primary", type: "color", class: "text-primary", properties: ["color"], group: "Text",
|
|
244
|
-
values: { light: "#1f1f1f", dark: "#f5f5f5", "
|
|
259
|
+
values: { light: "#1f1f1f", dark: "#f5f5f5", "docs+dark": "#fce5d8" } },
|
|
245
260
|
{ path: "color.bg.primary-interactive", type: "color", class: "bg-primary-interactive",
|
|
246
261
|
properties: ["background-color"], value: "#e57cd8", states: ["hover", "active", "disabled"] },
|
|
247
262
|
{ path: "radius.md", type: "dimension", class: "rounded-md", properties: ["border-radius"], value: "6px" },
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import type { ComponentAdapter } from "../design-system.js";
|
|
1
|
+
import type { ComponentAdapter, ComponentIdentity, ComponentProperty } from "../design-system.js";
|
|
2
2
|
export interface DiscoverReactComponentsOptions {
|
|
3
3
|
/** The app's own adapter, asked first; this adapter answers only when it names nothing. */
|
|
4
4
|
adapter?: ComponentAdapter;
|
|
5
|
+
/** Enable runtime editing when the optional react-preview bridge supports this renderer. */
|
|
6
|
+
edit?: boolean;
|
|
7
|
+
/** Declare enums or optional props that discovery cannot infer from their current values. */
|
|
8
|
+
schema?: (identity: ComponentIdentity) => ComponentProperty[] | undefined;
|
|
5
9
|
/** Component names to show; return false to skip a component (e.g. library wrappers). */
|
|
6
10
|
include?: (name: string) => boolean;
|
|
7
11
|
/**
|
|
@@ -14,13 +18,13 @@ export interface DiscoverReactComponentsOptions {
|
|
|
14
18
|
redact?: (name: string) => boolean;
|
|
15
19
|
/** Most props listed; default 24. */
|
|
16
20
|
maxProps?: number;
|
|
17
|
-
/**
|
|
21
|
+
/** @deprecated Opaque values are no longer displayed. */
|
|
18
22
|
maxDepth?: number;
|
|
19
|
-
/**
|
|
23
|
+
/** @deprecated Opaque values are no longer displayed. */
|
|
20
24
|
maxItems?: number;
|
|
21
25
|
/** Longest string shown; default 80. */
|
|
22
26
|
maxString?: number;
|
|
23
|
-
/**
|
|
27
|
+
/** @deprecated Only bounded primitive values are displayed. */
|
|
24
28
|
maxValue?: number;
|
|
25
29
|
}
|
|
26
30
|
/** A `ComponentAdapter` that finds the nearest React component for a picked element. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=new Set([0,1,11,15]),t
|
|
1
|
+
var e=new Set([0,1,11,15]),t=/pass(word|wd)?|secret|token|auth|api[-_]?key|credential|cookie|session|private/i,n=/^[a-z_$][\w$]?$/i,r=e=>/^(key|ref|children|dangerouslySetInnerHTML|suppressHydrationWarning)$|^on[A-Z]|^_|^\$\$/.test(e),l=e=>/^(className|id|role|tabIndex|asChild)$|^(data-|aria-)/.test(e)&&"aria-label"!==e,a=new WeakMap,i=e=>{try{return e()}catch{return}},o=(e,t)=>{let n=String(e).replace(/\s+/g," ");return n.length>t?`${n.slice(0,t)}…`:n},d=e=>!!e&&"object"==typeof e;function s(e){for(let t of Object.keys(e))if(t.startsWith("__reactFiber$")){let n=e[t];if(d(n))return n}let t=i(()=>globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__);for(let n of t?.renderers?.values?.()??[]){let t=i(()=>n.findFiberByHostInstance?.(e));if(d(t))return t}return null}function u(e){let t=[];for(let n=e;n&&t.length<5e3;n=n.return)t.push(n);let n=t[t.length-1],r=3===n?.tag&&d(n.stateNode)?n.stateNode.current:void 0;if(!d(r))return e;let l=r;for(let n=t.length-2;n>=0;n--){let r=l.child;for(;r&&r!==t[n]&&r!==t[n].alternate;)r=r.sibling;if(!r)return e;l=r}return l}function c(e,t=0){if("function"==typeof e){let t=e,n="string"==typeof t.displayName&&t.displayName?t.displayName:t.name;return"string"==typeof n&&n?n:void 0}if(e&&"object"==typeof e&&t<3){let n=e;return"string"==typeof n.displayName&&n.displayName?n.displayName:c(n.render??n.type,t+1)}}function p(e){let t=e.child;for(let e=0;t&&e<2e3;e++){if(5===t.tag)return t.stateNode instanceof Element?t.stateNode:null;t=t.child??t.sibling}return null}var f=/jsx[-_](dev[-_])?runtime|react-stack|react[-_.]development|node_modules[\\/](\.[\w-]+[\\/])*(react|react-dom|scheduler)[@\\/]/,m=/(?:\(|@|\bat\s+|^\s*)((?:[a-z][a-z0-9+.-]*:\/\/|\/|[a-z]:\\)[^()]*?):(\d+):(\d+)\)?\s*$/i;function g(e,t,n,r){let l=(e=>e.replace(/^[a-z][a-z0-9+.-]*:\/\/[^/]*/i,"").replace(/[?#].*$/,"").replace(/^\/@fs/,"").replace(/%20/g," "))(e);if(!l||!t)return;let a=i(()=>r?r(l,t,n):`${l}:${t}`);return"string"==typeof a&&a?o(a,160):void 0}function b(e,t){let n=e._debugSource;if(d(n)&&"string"==typeof n.fileName)return g(n.fileName,Number(n.lineNumber)||0,Number(n.columnNumber)||0,t);let r=i(()=>e._debugStack?.stack);return"string"==typeof r?function(e,t){let n=0;for(let r of e.split("\n").slice(0,40)){let e=f.test(r)?null:m.exec(r.trim());if(!e||++n>8)continue;let l=g(e[1],Number(e[2]),Number(e[3]),t);if(l&&!f.test(l))return l}}(r,t):void 0}function y(e,t){let n=document.createElement("label");n.className="design-field design-react-field";let r=document.createElement("span");r.textContent=e,r.title=e;let l=document.createElement("input");return l.value=t,l.title=t,l.readOnly=!0,l.setAttribute("aria-label",`${e} (discovered, read-only)`),n.append(r,l),n}function h(f={}){let m=Math.max(8,f.maxString??80),g=new WeakMap,h=Math.max(1,f.maxProps??24),v=e=>t.test(e)||!!i(()=>f.redact?.(e));function N(t){let g=function(e){let t=e;for(let e=0;t&&e<2e3;e++){if(1===t.nodeType){let e=s(t);if(e)return e}t=t.parentNode??t.host??null}return null}(t);if(!g)return null;let y=g;for(let t=0;y&&t<5e3&&(void 0===y.tag||!e.has(y.tag));t++)y=y.return;if(!y||!e.has(y.tag))return null;y=u(y);let N=c(y.type);if(!N||n.test(N)||f.include&&!f.include(N))return null;let _=d(y.memoizedProps)?y.memoizedProps:{},$=i(()=>Object.keys(_))??[],O=[],E={},k=[],x=0;for(let e of $){let t=Object.getOwnPropertyDescriptor(_,e);if(!t||!("value"in t))continue;let n=t.value;if(v(e)||r(e))continue;if(null===n){l(e)||(E[e]=null);continue}if(void 0===n||!("string"==typeof n||"boolean"==typeof n||"number"==typeof n&&Number.isFinite(n)))continue;if((l(e)?k:O).length>=h){x++;continue}let a="string"==typeof n?JSON.stringify(o(n,m)):String(n);l(e)?k.push([e,a]):(O.push([e,a]),E[e]=n)}let w=b(y,f.resolveSource),S={name:o(N,80),props:E,element:p(y)??t,...w?{source:w}:{}};return a.set(S,{props:O,advanced:k,hidden:x,location:w,fiber:y}),S}return{identify(e){try{let t=i(()=>f.adapter?.identify(e));return t?.name?t:N(e)}catch{return null}},editor(e){let t=a.get(e);if(!t)return i(()=>f.adapter?.editor?.(e))??null;if(!f.edit||1===t.fiber.tag)return null;let n=g.get(e.element);if(n&&(n.fiber===t.fiber||n.fiber.alternate===t.fiber)&&!1!==n.editor.available?.())return n.editor;let l=(i(()=>f.schema?.(e))??Object.entries(e.props??{}).filter(([,e])=>null!==e).map(([e,t])=>({name:e,kind:typeof t,required:!0,typeLabel:typeof t}))).filter(e=>!v(e.name)&&!r(e.name)&&"unsupported"!==e.kind),o=()=>i(()=>{if(!e.element.isConnected)return null;let n=u(t.fiber),r=n;for(let e=0;r.return&&e<5e3;e++)r=r.return;let l=r.stateNode;return 3!==r.tag||l?.current!==r||p(n)!==e.element?null:{fiber:n,root:l,props:n.memoizedProps??{}}})??null,d=globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__,s=i(()=>d?.[Symbol.for("inline-feedback.react-preview")]?.editor({schema:l,current:o}));return s&&g.set(e.element,{fiber:t.fiber,editor:s}),s??null},panel(e){let t=a.get(e);if(!t)return i(()=>f.adapter?.panel?.(e))??null;let n=document.createElement("details");n.className="design-group design-react-group design-react-discovered",n.open=!0;let r=document.createElement("summary");r.textContent="Discovered props";let l=document.createElement("small");if(l.className="design-react-source",l.textContent=`${e.name} · read-only${t.location?` · rendered at ${t.location}`:""}`,l.title=f.edit?"Runtime editing needs the React preview bridge loaded before a supported development renderer, or a component editor adapter.":"Enable a component editor adapter or React runtime previews to edit these props.",n.append(r,l),!t.props.length){let e=document.createElement("small");e.className="design-react-source",e.textContent="No props.",n.append(e)}for(let[e,r]of t.props)n.append(y(e,r));if(t.advanced.length){let e=document.createElement("details");e.className="design-react-advanced";let r=document.createElement("summary");r.textContent="Advanced attributes",e.append(r);for(let[n,r]of t.advanced)e.append(y(n,r));n.append(e)}if(t.hidden){let e=document.createElement("small");e.className="design-react-source",e.textContent=`+${t.hidden} more props not shown`,n.append(e)}return n}}}export{h as discoverReactComponents};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ComponentEditor, ComponentProperty } from "../design-system.js";
|
|
2
|
+
interface Snapshot {
|
|
3
|
+
fiber: object;
|
|
4
|
+
root: object;
|
|
5
|
+
props: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface ReactPreviewRequest {
|
|
8
|
+
schema: ComponentProperty[];
|
|
9
|
+
current(): Snapshot | null;
|
|
10
|
+
}
|
|
11
|
+
export declare const reactPreviewKey: unique symbol;
|
|
12
|
+
export interface ReactPreviewBridge {
|
|
13
|
+
editor(request: ReactPreviewRequest): ComponentEditor | null;
|
|
14
|
+
}
|
|
15
|
+
export declare function installReactPreview(): boolean;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=e=>Object.defineProperties({},Object.fromEntries(Object.entries(Object.getOwnPropertyDescriptors(e)).map(([e,r])=>[e,{...r,configurable:!0,..."value"in r?{writable:!0}:{}}]))),r=Symbol.for("inline-feedback.react-preview");function t(){try{return function(){if(typeof window>"u")return!1;let t=globalThis,o=t.__REACT_DEVTOOLS_GLOBAL_HOOK__;if(o?.[r])return!0;if(!o){let e=new Map,r=new Map;o={supportsFiber:!0,renderers:e,inject(r){let t=e.size+1;return e.set(t,r),t},getFiberRoots(e){let t=r.get(e);return t||r.set(e,t=new Set),t}};try{t.__REACT_DEVTOOLS_GLOBAL_HOOK__=o}catch{return!1}}if(!o.supportsFiber||!o.renderers)return!1;let i=new Set,n=new Set,l=new WeakMap;for(let[e,r]of o.renderers)for(let t of o.getFiberRoots?.(e)??[])l.set(t,r);let s=o.onCommitFiberRoot,a=!1,f=function(e,r,...t){try{s?.call(this,e,r,...t)}finally{let t=o.renderers.get(e);t&&l.set(r,t),n.add(r),i.size&&!a?(a=!0,queueMicrotask(()=>{a=!1;let e=[...n];n.clear();for(let r of e)for(let e of[...i])e(r)})):i.size||n.clear()}};try{o.onCommitFiberRoot=f}catch{return!1}if(o.onCommitFiberRoot!==f)return!1;let c={editor(r){let t=r.current(),o=t&&l.get(t.root);if(!o?.overrideProps||1!==o.bundleType||"react-dom"!==o.rendererPackageName||!/^(18|19)\./.test(o.version??""))return null;let n,s=new Map,a=new Set,f=()=>r.current(),c=r=>{let t=f();if(!t)return i.delete(c),s.clear(),void(n=void 0);if(t.root===r){if(n=void 0,s.size){let r=e(t.props),i=!1;for(let[e,t]of s)Object.is(r[e],t.value)||(r[e]=t.value,i=!0);if(i)return void o.overrideProps(t.fiber,[],r)}for(let e of a)e();!s.size&&!a.size&&i.delete(c)}};return{schema:r.schema,available:()=>!!f(),release(e){for(let r of e)s.delete(r)},subscribe:e=>(a.add(e),i.add(c),()=>{a.delete(e),!a.size&&!s.size&&!n&&i.delete(c)}),read(){let e={},t=n??f()?.props??{};for(let o of r.schema)e[o.name]=Object.getOwnPropertyDescriptor(t,o.name)?.value;return e},apply(t){let l=f();if(!l)return;let a=n??l.props,u=e(l.props);for(let e of r.schema){let r=e.name,o=t[r],i=s.get(r);!i&&!Object.is(a[r],o)&&(i={before:a[r],present:Object.hasOwn(a,r),value:o},s.set(r,i)),i&&(i.value=o,u[r]=o,Object.is(o,i.before)&&(i.present||delete u[r],s.delete(r)))}n=u,i.add(c),o.overrideProps(l.fiber,[],u)}}}};try{o[r]=c}catch{return o.onCommitFiberRoot=s,!1}return!0}()}catch{return!1}}t();export{t as installReactPreview,r as reactPreviewKey};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e}from"./chunk-RPY7OOOR.js";var t=new WeakMap,r=new WeakMap,n=new WeakMap;function o(e,t){let r=n.get(e.element);if(r?.editor===t)return r.component;let o={id:e.name,name:e.name,source:e.source??"",line:0,props:t.schema},i={definition:o,preview:"adapter",releaseProps:e=>t.release?.(e),subscribe:t.subscribe?.bind(t),get props(){return l(o,t.read())},onChange:e=>t.apply(e),setProps(e){if(!1===t.available?.())return;let r=l(o,e);if(Object.keys(r).length!==Object.keys(e).length||o.props.some(e=>"unsupported"!==e.kind&&e.required&&!(e.name in r)))throw new Error("Component props no longer match the editor schema.");t.apply(r)}};return n.set(e.element,{editor:t,component:i}),i}function i(e,t){return void 0===t?!e.required:!(!function(e){return void 0===e||"string"==typeof e||"number"==typeof e&&Number.isFinite(e)||"boolean"==typeof e}(t)||"unsupported"===e.kind)&&("string"===e.kind?"string"==typeof t&&t.length<=500:"number"===e.kind?"number"==typeof t&&Number.isFinite(t):"boolean"===e.kind?"boolean"==typeof t:"enum"===e.kind&&(e.values??[]).includes(t))}function l(e,t){let r={};for(let n of e.props){if("unsupported"===n.kind)continue;let e=t[n.name];i(n,e)&&(r[n.name]=e)}return r}function s(e,n,o,i){let s=n.textProp&&n.props.some(e=>e.name===n.textProp&&"string"===e.kind)?n.textProp:void 0,a=l(n,o),p=new Set,u={definition:n,props:a,onChange:i,subscribe:e=>(p.add(e),()=>{p.delete(e)}),setProps(e){let t=l(n,e);if(Object.keys(t).length===Object.keys(e).length){for(let e of n.props)if("unsupported"!==e.kind&&e.required&&!(e.name in t))return;u.props=t,u.onChange(t)}}};return t.set(e,u),e.dataset.komoInspectable=n.id,s?e.dataset.komoTextProp=s:delete e.dataset.komoTextProp,r.set(u,p),()=>{t.get(e)===u&&(t.delete(e),p.clear(),e.dataset.komoInspectable===n.id&&delete e.dataset.komoInspectable,e.dataset.komoTextProp===s&&delete e.dataset.komoTextProp)}}function a(e,n,o,i){if(!e)return;let s=t.get(e);if(!s||s.definition.id!==n.id)return;s.definition=n,s.props=l(n,o),s.onChange=i;let a=n.textProp&&n.props.some(e=>e.name===n.textProp&&"string"===e.kind)?n.textProp:void 0;a?e.dataset.komoTextProp=a:delete e.dataset.komoTextProp,r.get(s)?.forEach(e=>e())}function p(e){let r=e&&t.get(e);if(r&&e.getAttribute("data-komo-inspectable")===r.definition.id)return r;let o=e&&n.get(e);return o&&!1!==o.editor.available?.()?o.component:null}function u(e){for(let t=e?.parentElement;t;t=t.parentElement){let e=p(t);if(e)return{root:t,component:e}}return null}var f=new Set,d=new WeakMap,m=new WeakMap,c=new WeakMap,h={color:new Set(["color","background-color","border-color"]),dimension:new Set(["gap","padding","margin","border-radius","font-size","width","height"]),fontFamily:new Set(["font-family"]),fontWeight:new Set(["font-weight"]),lineHeight:new Set(["line-height"])};function g(e,t){if(t.length>100||t.some(e=>!function(e){return!!e&&"string"==typeof e.path&&e.path.length<=160&&/^--[a-zA-Z0-9_-]+$/.test(e.cssVariable)&&!!h[e.type]&&Array.isArray(e.properties)&&e.properties.length>0&&e.properties.every(t=>h[e.type].has(t))&&"string"==typeof e.impactSelector&&e.impactSelector.length<=200}(e)))throw new Error("Komo design tokens must use supported, explicit CSS-variable metadata");let r=new Set(t.map(e=>e.path)),n=new Set(t.map(e=>e.cssVariable));if(r.size!==t.length||n.size!==t.length)throw new Error("Komo design token paths and CSS variables must be unique");for(let r of t)e.querySelectorAll(r.impactSelector);let o={root:e,tokens:t.map(e=>({...e,properties:[...e.properties]})),themeEdits:new Map,elementOriginals:new Map,elementBindings:new Map,previousMarker:e.getAttribute("data-komo-design-tokens")};return d.set(e,o),f.add(o),c.set(o,[]),e.setAttribute("data-komo-design-tokens",String(t.length)),()=>{if(d.get(e)===o){for(let[t,r]of o.themeEdits){let n=o.tokens.find(e=>e.path===t);n&&(r.inlineBefore?e.style.setProperty(n.cssVariable,r.inlineBefore):e.style.removeProperty(n.cssVariable))}for(let[e,t]of o.elementOriginals)for(let[r,n]of t)n.value?e.style.setProperty(r,n.value,n.priority):e.style.removeProperty(r);o.elementBindings.clear(),f.delete(o),d.delete(e),null===o.previousMarker?e.removeAttribute("data-komo-design-tokens"):e.setAttribute("data-komo-design-tokens",o.previousMarker)}}}function y(e){if(!e)return null;let t=null;for(let r of f)(r.root===e||r.root.contains(e))&&(!t||t.root.contains(r.root))&&(t=r);return t}function k(e,t){return e.root.ownerDocument.defaultView?.getComputedStyle(e.root).getPropertyValue(t.cssVariable).trim()??""}function b(e,t){try{return e.root.querySelectorAll(t.impactSelector).length}catch{return 0}}function P(e,t,r,n=!1){if(!e.tokens.some(e=>e===t||e.path===t.path)||!function(e,t,r){if(!r||r.length>160||/[{};]/.test(r)||/(?:url|expression)\s*\(/i.test(r))return!1;let n=e.root.ownerDocument.defaultView?.CSS;return!n?.supports||t.properties.some(e=>n.supports(e,r))}(e,t,r))return!1;let o=k(e,t),i=e.themeEdits.get(t.path),l=e.root.style.getPropertyValue(t.cssVariable),s=i?.inlineBefore??l,a=c.get(e)??[];if(o===r)return!0;e.root.style.setProperty(t.cssVariable,r),r===(i?.before??o)?e.themeEdits.delete(t.path):e.themeEdits.set(t.path,{before:i?.before??o,after:r,inlineBefore:s});let p=a.at(-1);return n&&"theme"===p?.kind&&p.token.path===t.path?r===p.before?a.pop():p.after=r:a.push({kind:"theme",source:e,token:t,before:o,after:r,inlineBefore:l}),c.set(e,a),!0}function v(e){for(let t of f)for(let[r,n]of t.themeEdits){let o=t.tokens.find(e=>e.path===r)?.cssVariable;if(!o)continue;let i=e?n.inlineBefore:n.after;i?t.root.style.setProperty(o,i):t.root.style.removeProperty(o)}}function w(e,t){let r=e.themeEdits.get(t.path),n=c.get(e)??[],o=n.find(e=>"theme"===e.kind&&e.token.path===t.path),i=r?.inlineBefore??("theme"===o?.kind?o.inlineBefore:void 0);void 0!==i&&(i?e.root.style.setProperty(t.cssVariable,i):e.root.style.removeProperty(t.cssVariable),e.themeEdits.delete(t.path),c.set(e,n.filter(e=>"theme"!==e.kind||e.token.path!==t.path)))}function V(e,t,r,n,o={}){if(!e.tokens.some(e=>e.path===r.path)||!r.properties.includes(n))return!1;let i=e.elementOriginals.get(t);i||e.elementOriginals.set(t,i=new Map),i.has(n)||i.set(n,{value:t.style.getPropertyValue(n),priority:t.style.getPropertyPriority(n)});let l=t.style.getPropertyValue(n),s=t.style.getPropertyPriority(n),a=`var(${r.cssVariable})`,p=e.elementBindings.get(t);p||e.elementBindings.set(t,p=new Map);let u=p.get(n);if(p.set(n,{tokenPath:r.path,initialValue:u?.initialValue??l,initialPriority:u?.initialPriority??s,mode:"token",declaredPath:u?u.declaredPath:A(e,t,n)?.token.path}),t.style.setProperty(n,a,s),!1===o.recordHistory)return!0;let f={kind:"element",element:t,property:n,before:l,priority:s,after:a},d=c.get(e)??[];d.push(f),c.set(e,d);let h=m.get(t)??[];return h.push(f),m.set(t,h),!0}function B(e,t,r,n){let o=e.elementBindings.get(t),i=o?.get(r);if(!i){let n=A(e,t,r);if(!n)return;o||e.elementBindings.set(t,o=new Map),i={tokenPath:n.token.path,initialValue:t.style.getPropertyValue(r),initialPriority:t.style.getPropertyPriority(r),mode:"custom",declaredPath:n.token.path},o.set(r,i)}i.mode="custom",i.customValue=n}function S(e,t,r){let n=e.elementBindings.get(t)?.get(r);if(!n)return;let o=t.style.getPropertyValue(r);o!==n.initialValue||t.style.getPropertyPriority(r)!==n.initialPriority?e.tokens.find(e=>e.path===n.tokenPath&&e.properties.includes(r)&&o===`var(${e.cssVariable})`)?(n.mode="token",delete n.customValue):(n.mode="custom",n.customValue=o):e.elementBindings.get(t)?.delete(r)}function $(e,t,r){let n=e.elementBindings.get(t)?.get(r);return n?{...n}:null}var E={"background-color":["background"],"border-color":["border"],"font-family":["font"],"font-size":["font"],"font-weight":["font"],"line-height":["font"]};function x(e,t,r,n){let o=[...r.matchAll(/var\(\s*(--[\w-]+)/g)].map(e=>e[1]);if(!o.length||n&&!/^var\(\s*--[\w-]+\s*(?:,[^;{}]*)?\)$/.test(r.trim()))return;let i=e.tokens.filter(e=>e.properties.includes(t)&&o.includes(e.cssVariable));return 1===i.length?i[0]:void 0}function M(e){let t=e.replace(/:(?:where)\([^)]*\)/g,"").replace(/"[^"]*"|'[^']*'/g,"");return 1e4*(t.match(/#[\w-]+/g)?.length??0)+100*(t.match(/\.[\w-]+|\[[^\]]*\]|:(?!:)[\w-]+/g)?.length??0)+(t.match(/(?:^|[\s>+~(])[a-z][\w-]*/gi)?.length??0)}function O(e){let t=[],r=0,n=0;for(let o=0;o<e.length;o++){let i=e[o];"("===i||"["===i?r++:")"===i||"]"===i?r--:","===i&&0===r&&(t.push(e.slice(n,o)),n=o+1)}return t.push(e.slice(n)),t.map(e=>e.trim()).filter(Boolean)}function A(e,t,r,n=t.style.getPropertyValue(r),o=t.style.getPropertyPriority(r)){let i=t.ownerDocument.defaultView,l=null,s=0,a=e=>{for(let n of e){s++;let e=n.media;if(e&&i?.matchMedia&&e.mediaText&&!i.matchMedia(e.mediaText).matches)continue;let o=n.style,p=n.selectorText;if(o&&p)for(let e of[r,...E[r]??[]]){let r=o.getPropertyValue(e).trim();if(!r)continue;let n=-1;for(let e of O(p))try{t.matches(e)&&(n=Math.max(n,M(e)))}catch{}if(!(n<0)){n+=o.getPropertyPriority(e)?1e9:0,(!l||n>l.rank||n===l.rank&&s>=l.order)&&(l={value:r,property:e,rank:n,order:s});break}}let u=n.cssRules;u&&!o&&a(u)}};for(let e of t.ownerDocument.styleSheets)try{e.disabled||a(e.cssRules)}catch{}let p=l;if(n&&(!(p&&p.rank>=1e9)||o)){let t=x(e,r,n,!0);return t?{token:t,origin:"inline"}:null}if(!p)return null;let u=x(e,r,p.value,p.property===r);return u?{token:u,origin:"stylesheet"}:null}function T(e,t,r){let n=e.elementBindings.get(t)?.get(r),o=e.elementOriginals.get(t)?.get(r),i=n?.initialValue??o?.value??"",l=n?.initialPriority??o?.priority??"";i?t.style.setProperty(r,i,l):t.style.removeProperty(r),e.elementBindings.get(t)?.delete(r)}function C(e,t){return e.tokens.filter(e=>e.properties.includes(t))}function z(e){let t=y(e);return!!t&&(t.themeEdits.size>0||!!m.get(e)?.length||!!t.elementBindings.get(e)?.size)}function j(e){let t=y(e);return!!t&&!!c.get(t)?.length}function q(e){let t=y(e),r=t&&c.get(t)?.pop();if(!t||!r)return;if("theme"===r.kind){r.inlineBefore?t.root.style.setProperty(r.token.cssVariable,r.inlineBefore):t.root.style.removeProperty(r.token.cssVariable);let e=t.themeEdits.get(r.token.path);if(e&&e.after===r.after)e.before===r.before?t.themeEdits.delete(r.token.path):t.themeEdits.set(r.token.path,{...e,after:r.before});else if(!e){let e=c.get(t).find(e=>"theme"===e.kind&&e.token.path===r.token.path);t.themeEdits.set(r.token.path,{before:r.after,after:r.before,inlineBefore:("theme"===e?.kind?e:r).inlineBefore})}return}r.before?r.element.style.setProperty(r.property,r.before,r.priority):r.element.style.removeProperty(r.property);let n=m.get(r.element)??[];n.pop(),n.length||m.delete(r.element)}function W(e){let t=y(e);if(!t)return;for(let[e,r]of t.themeEdits){let n=t.tokens.find(t=>t.path===e);n&&(r.inlineBefore?t.root.style.setProperty(n.cssVariable,r.inlineBefore):t.root.style.removeProperty(n.cssVariable))}t.themeEdits.clear();let r=t.elementOriginals.get(e);for(let[t,n]of r??[])n.value?e.style.setProperty(t,n.value,n.priority):e.style.removeProperty(t);t.elementOriginals.delete(e),t.elementBindings.delete(e),m.delete(e),c.set(t,(c.get(t)??[]).filter(t=>"element"===t.kind&&t.element!==e))}function D(){for(let e of f){for(let t of[e.root,...e.elementOriginals.keys(),...e.elementBindings.keys()])W(t);c.set(e,[])}}function R(e){let t=y(e);if(!t)return;let r=[];for(let[n,o]of t.elementBindings.get(e)??[]){let e=t.tokens.find(e=>e.path===o.tokenPath&&e.properties.includes(n));if(!e)continue;let i=t.tokens.find(e=>e.path===o.declaredPath),l=i?`var(${i.cssVariable}) [${i.path}]`:o.initialValue||"(unset)";"token"===o.mode?i!==e&&r.push(`Element ${n}: ${l} → var(${e.cssVariable}) [${e.path}]${i?" [rebind]":""}`):r.push(`Element ${n}: ${l} → ${o.customValue||"(unset)"} [${i?"custom override":"custom value"}]`)}for(let n of m.get(e)??[]){if("element"!==n.kind||t.elementBindings.get(e)?.has(n.property))continue;let o=t.tokens.find(e=>n.after===`var(${e.cssVariable})`);o&&r.push(`Element ${n.property}: ${n.before||"(unset)"} → var(${o.cssVariable}) [${o.path}]`)}for(let[e,n]of t.themeEdits){let o=t.tokens.find(t=>t.path===e);o&&r.push(`Shared theme ${e} (${o.cssVariable}): ${n.before} → ${n.after}; preview scope ${o.impactSelector} (${b(t,o)} matching elements)`)}return r.length?["Proposed design-token changes (preview only)",...r,"Token references are preserved for element assignments; refresh resets previews."].join("\n"):void 0}function F(){return{id:"css-variables",list:()=>[...f].flatMap(e=>e.tokens.map(t=>function(e,t){return{path:t.path,type:t.type,value:k(e,t),properties:[...t.properties],group:t.path.split(".")[0],ref:t.cssVariable}}(e,t))),resolve(t){let r=y(t),n={};if(!r||!e(t))return n;let o=t.ownerDocument.defaultView?.getComputedStyle(t);for(let e of new Set(r.tokens.flatMap(e=>e.properties))){let i=A(r,t,e);n[e]=i?{path:i.token.path}:{offToken:o?.getPropertyValue(e).trim()??""}}return n},preview(t,r,n){let o=y(t),i=o?.tokens.find(e=>e.path===n.path);if(!o||!i||!e(t))return()=>{};let l=t.style.getPropertyValue(r),s=t.style.getPropertyPriority(r);return V(o,t,i,r,{recordHistory:!1}),()=>{l?t.style.setProperty(r,l,s):t.style.removeProperty(r),S(o,t,r)}},describe:(e,t,r,n)=>`Set ${t} to var(${n.ref})`}}export{o as a,i as b,s as c,a as d,p as e,u as f,g,y as h,k as i,b as j,P as k,v as l,w as m,V as n,B as o,S as p,$ as q,A as r,T as s,C as t,z as u,j as v,q as w,W as x,D as y,R as z,F as A};
|