@hazem3500/komo 0.9.26 → 0.9.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +18 -6
  2. package/dist/adapters/react-fiber.d.ts +8 -4
  3. package/dist/adapters/react-fiber.js +1 -1
  4. package/dist/adapters/react-preview.d.ts +16 -0
  5. package/dist/adapters/react-preview.js +1 -0
  6. package/dist/chunk-4KEVPMJJ.js +1 -0
  7. package/dist/{chunk-G2QGDYNV.js → chunk-F57BOPTZ.js} +1 -1
  8. package/dist/chunk-HHG6KWKR.js +1 -0
  9. package/dist/chunk-HTMUFH7I.js +1 -0
  10. package/dist/design-comment-W2OVUWBL.js +1 -0
  11. package/dist/design-export-JEWGQH3R.js +1 -0
  12. package/dist/design-mode-styles.d.ts +1 -1
  13. package/dist/design-mode.js +1 -1
  14. package/dist/{design-panel-3SQFWOPU.js → design-panel-KHZDEA36.js} +1 -1
  15. package/dist/design-popup.d.ts +1 -2
  16. package/dist/design-preview.d.ts +6 -0
  17. package/dist/design-system.d.ts +23 -1
  18. package/dist/index.js +1 -1
  19. package/dist/{inline-text-editor-AMTG5O25.js → inline-text-editor-OMRCO3H3.js} +1 -1
  20. package/dist/node.mjs +1 -1
  21. package/dist/react-inspector.d.ts +7 -6
  22. package/dist/react-props-panel-Y7F2P3AG.js +1 -0
  23. package/dist/react-props-panel.d.ts +4 -4
  24. package/dist/react.js +1 -1
  25. package/dist/select-menu-QH7IVM7P.js +1 -0
  26. package/dist/server.js +1 -1
  27. package/dist/setup.js +1 -1
  28. package/dist/token-picker-RHPT7HCK.js +1 -0
  29. package/package.json +7 -1
  30. package/server/setup-client.txt +45 -46
  31. package/dist/chunk-K6ETEZER.js +0 -1
  32. package/dist/chunk-MZE3O5EH.js +0 -1
  33. package/dist/design-comment-K2JCM7IT.js +0 -1
  34. package/dist/design-export-LA5VVR5Z.js +0 -1
  35. package/dist/react-props-panel-IU7XYCCH.js +0 -1
  36. package/dist/select-menu-QS4CXU6O.js +0 -1
  37. package/dist/token-picker-JANYJIL4.js +0 -1
package/README.md CHANGED
@@ -95,7 +95,7 @@ Design mode also takes interaction cues from established design tools: select a
95
95
 
96
96
  ### Opt-in React prop inspection
97
97
 
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, nullable unions, and any unsupported type remain read-only. This metadata is a safe allowlist, not runtime discovery of every React component; `defaultProps` and every React component form are not inferred.
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, 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
99
 
100
100
  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
101
 
@@ -214,9 +214,21 @@ initKomo({ project, design: { components: discoverReactComponents() } });
214
214
  ```
215
215
 
216
216
  - **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
- - **What it shows.** The panel adds a **Discovered props** group labelled "discovered from React, read-only", with the props and "rendered at `file:line`". The location is where the component was written into JSX (the call site), not where it is defined. React 19 records an Error stack of the generated file; a dev server that serves modules unbundled gives real paths, and otherwise pass `resolveSource(file, line, column)` to map positions (for example through a source map). Proposals also name the component with its primitive props, like any component adapter.
218
- - **Props are summarized, never run.** Strings, numbers and booleans are shown; arrays and plain objects are cut off by `maxDepth` (3), `maxItems` (6), `maxString` (80) and `maxValue` (240), and `maxProps` caps the list (24). Functions, React elements, symbols, DOM nodes and class instances are described (`ƒ onSave()`, `<button />`), cycles read `[Circular]`, and getters are never invoked. Props named like secrets (`token`, `password`, `apiKey`, `secret`, `auth`…) and anything `redact(name)` matches show as `[redacted]` and are kept out of proposals.
219
- - **Read-only, and registered components win.** Discovered props are never editable, because komo has no state callback or typed schema for them. A component registered with `useKomoInspectable`, or answered by your own `adapter`, always takes precedence and keeps its editable typed props; around an element inside a registered component the panel keeps showing "Inside *Component*". A component nested inside a registered one that is not registered itself is discovered.
217
+ - **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.
218
+ - **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.
219
+ - **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.
220
+
221
+ ```ts
222
+ // First import in the app's development entry, before its React/router graph.
223
+ import "@hazem3500/komo/adapters/react-preview";
224
+ // In the lazily enabled feedback configuration:
225
+ const components = discoverReactComponents({ edit: true });
226
+ ```
227
+
228
+ 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.
229
+
230
+ 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.
231
+
220
232
  - **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
233
  - **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
234
 
@@ -235,13 +247,13 @@ const mode = classTheme({
235
247
  });
236
248
  const product = classTheme({
237
249
  id: "product",
238
- options: [{ id: "focus", attribute: { "data-product": "focus" } }, { id: "track", attribute: { "data-product": "track" } }],
250
+ options: [{ id: "studio", attribute: { "data-product": "studio" } }, { id: "docs", attribute: { "data-product": "docs" } }],
239
251
  });
240
252
 
241
253
  // Generate this from your design-system foundations.
242
254
  const tokens: TailwindToken[] = [
243
255
  { path: "color.text.primary", type: "color", class: "text-primary", properties: ["color"], group: "Text",
244
- values: { light: "#1f1f1f", dark: "#f5f5f5", "track+dark": "#fce5d8" } },
256
+ values: { light: "#1f1f1f", dark: "#f5f5f5", "docs+dark": "#fce5d8" } },
245
257
  { path: "color.bg.primary-interactive", type: "color", class: "bg-primary-interactive",
246
258
  properties: ["background-color"], value: "#e57cd8", states: ["hover", "active", "disabled"] },
247
259
  { 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
- /** Nesting depth of objects and arrays shown; default 3. */
21
+ /** @deprecated Opaque values are no longer displayed. */
18
22
  maxDepth?: number;
19
- /** Most array items or object keys shown per level; default 6. */
23
+ /** @deprecated Opaque values are no longer displayed. */
20
24
  maxItems?: number;
21
25
  /** Longest string shown; default 80. */
22
26
  maxString?: number;
23
- /** Most characters in one summarized prop value; default 240. */
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=["react.element","react.transitional.element"],n=/pass(word|wd)?|secret|token|auth|api[-_]?key|credential|cookie|session|private/i,r=/^[a-z_$][\w$]?$/i,l=new WeakMap,a=e=>{try{return e()}catch{return}},i=(e,t)=>{let n=String(e).replace(/\s+/g," ");return n.length>t?`${n.slice(0,t)}…`:n},o=e=>!!e&&"object"==typeof e;function s(e){for(let t of Object.keys(e))if(t.startsWith("__reactFiber$")){let n=e[t];if(o(n))return n}let t=a(()=>globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__);for(let n of t?.renderers?.values?.()??[]){let t=a(()=>n.findFiberByHostInstance?.(e));if(o(t))return t}return null}function u(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:u(n.render??n.type,t+1)}}function c(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 d=/jsx[-_](dev[-_])?runtime|react-stack|react[-_.]development|node_modules[\\/](\.[\w-]+[\\/])*(react|react-dom|scheduler)[@\\/]/,p=/(?:\(|@|\bat\s+|^\s*)((?:[a-z][a-z0-9+.-]*:\/\/|\/|[a-z]:\\)[^()]*?):(\d+):(\d+)\)?\s*$/i;function m(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 o=a(()=>r?r(l,t,n):`${l}:${t}`);return"string"==typeof o&&o?i(o,160):void 0}function f(e,t){let n=e._debugSource;if(o(n)&&"string"==typeof n.fileName)return m(n.fileName,Number(n.lineNumber)||0,Number(n.columnNumber)||0,t);let r=a(()=>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=d.test(r)?null:p.exec(r.trim());if(!e||++n>8)continue;let l=m(e[1],Number(e[2]),Number(e[3]),t);if(l&&!d.test(l))return l}}(r,t):void 0}function g(e,n,r=[]){switch(typeof e){case"string":return JSON.stringify(i(e,n.string));case"number":case"boolean":case"undefined":return String(e);case"bigint":return`${e}n`;case"symbol":return a(()=>String(e))??"Symbol()";case"function":return`ƒ ${a(()=>u(e))??"anonymous"}()`}if(null===e)return"null";let l=e;if(r.includes(l))return"[Circular]";if((e=>t.some(t=>e.$$typeof===Symbol.for(t)))(l)){let e=l.type;return`<${"string"==typeof e?e:a(()=>u(e))??"Component"} />`}if(typeof Node<"u"&&l instanceof Node)return`<${l.localName??"node"}>`;if(Array.isArray(l)){if(r.length>=n.depth)return`Array(${l.length})`;let e=[];for(let t=0;t<Math.min(l.length,n.items);t++){let a=Object.getOwnPropertyDescriptor(l,t);e.push(a&&"value"in a?g(a.value,n,[...r,l]):"[getter]")}return`[${e.join(", ")}${l.length>n.items?", … +"+(l.length-n.items):""}]`}let o=Object.getPrototypeOf(l);if(o!==Object.prototype&&null!==o){let e=a(()=>u(o.constructor))??"Object";return"Date"===e?a(()=>l.toISOString())??"Date":"Map"===e||"Set"===e?`${e}(${a(()=>l.size)??"?"})`:"RegExp"===e?i(a(()=>String(l))??"RegExp",n.string):`${e} {…}`}let s=a(()=>Object.keys(l))??[];return s.length?r.length>=n.depth?"{…}":`{ ${s.slice(0,n.items).map(e=>{let t=Object.getOwnPropertyDescriptor(l,e);return`${i(e,40)}: ${t&&"value"in t?g(t.value,n,[...r,l]):"[getter]"}`}).join(", ")}${s.length>n.items?", … +"+(s.length-n.items):""} }`:"{}"}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.disabled=!0,l.setAttribute("aria-label",`${e} (discovered, read-only)`),n.append(r,l),n}function h(t={}){let d={depth:Math.max(0,t.maxDepth??3),items:Math.max(1,t.maxItems??6),string:Math.max(8,t.maxString??80),value:Math.max(40,t.maxValue??240)},p=Math.max(1,t.maxProps??24),m=e=>n.test(e)||!!a(()=>t.redact?.(e));function h(n){let y=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}(n);if(!y)return null;let h=y;for(let t=0;h&&t<5e3&&(void 0===h.tag||!e.has(h.tag));t++)h=h.return;if(!h||!e.has(h.tag))return null;h=function(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&&o(n.stateNode)?n.stateNode.current:void 0;if(!o(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}(h);let b=u(h.type);if(!b||r.test(b)||t.include&&!t.include(b))return null;let $=o(h.memoizedProps)?h.memoizedProps:{},N=a(()=>Object.keys($))??[],v=[],x={};for(let e of N.slice(0,p)){let t=Object.getOwnPropertyDescriptor($,e);if(!t||!("value"in t))continue;let n=t.value;m(e)?v.push([e,"[redacted]"]):(v.push([e,i(a(()=>g(n,d))??"[unreadable]",d.value)]),(null===n||["string","number","boolean"].includes(typeof n))&&(x[e]=n))}let O=f(h,t.resolveSource),_={name:i(b,80),props:x,element:c(h)??n,...O?{source:O}:{}};return l.set(_,{props:v,hidden:Math.max(0,N.length-p),location:O}),_}return{identify(e){try{let n=a(()=>t.adapter?.identify(e));return n?.name?n:h(e)}catch{return null}},panel(e){let n=l.get(e);if(!n)return a(()=>t.adapter?.panel?.(e))??null;let r=document.createElement("details");r.className="design-group design-react-group design-react-discovered",r.open=!0;let i=document.createElement("summary");i.textContent="Discovered props";let o=document.createElement("small");if(o.className="design-react-source",o.textContent=`${e.name} · discovered from React, read-only${n.location?` · rendered at ${n.location}`:""}`,r.append(i,o),!n.props.length){let e=document.createElement("small");e.className="design-react-source",e.textContent="No props.",r.append(e)}for(let[e,t]of n.props)r.append(y(e,t));if(n.hidden){let e=document.createElement("small");e.className="design-react-source",e.textContent=`+${n.hidden} more props not shown`,r.append(e)}return r}}}export{h as discoverReactComponents};
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
+ var t=".komo-select,.komo-tokens{position:absolute;z-index:20;box-sizing:border-box;border-radius:10px;background:#232323;box-shadow:0 0 0 1px #ffffff14,0 12px 32px #0008;color:#d9d6d1;font-size:11px;font-weight:400;line-height:1.25;text-align:left;cursor:default;transform-origin:top;animation:komo-popup-in var(--duration-fast,250ms) var(--ease-smooth-out,cubic-bezier(.22,1,.36,1)) backwards}.komo-select[data-up],.komo-tokens[data-up]{transform-origin:bottom}@keyframes komo-popup-in{from{opacity:0;transform:scale(.97)}}@media (prefers-reduced-motion:reduce){.komo-select,.komo-tokens{animation:none}}";function o(t){let o={top:0,left:0,bottom:innerHeight,right:innerWidth};for(let e=t.parentElement;e;e=e.parentElement)if(/auto|scroll|hidden/.test(getComputedStyle(e).overflowY)){let t=e.getBoundingClientRect();return{top:Math.max(t.top,0),left:Math.max(t.left,0),bottom:Math.min(t.bottom,o.bottom),right:Math.min(t.right,o.right)}}return o}function e(t,o,e){let n=t.getRootNode();n.addEventListener("komo-preview-cancel",o,{signal:e});let i=new MutationObserver(()=>{t.isConnected||o()});i.observe(document,{childList:!0,subtree:!0}),n instanceof ShadowRoot&&i.observe(n,{childList:!0,subtree:!0}),e.addEventListener("abort",()=>i.disconnect(),{once:!0})}export{t as a,o as b,e as c};