@hazem3500/komo 0.9.0 → 0.9.1
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 +52 -0
- package/dist/adapters/class-theme.d.ts +22 -0
- package/dist/adapters/class-theme.js +1 -0
- package/dist/adapters/tailwind.d.ts +62 -0
- package/dist/adapters/tailwind.js +1 -0
- package/dist/chunk-5LHGJFWQ.js +1 -0
- package/dist/chunk-JC6FXUNO.js +1 -0
- package/dist/design-comment-RTVUFVDE.js +1 -0
- package/dist/design-comment.d.ts +8 -0
- package/dist/design-mode-styles.d.ts +1 -1
- package/dist/design-mode.d.ts +2 -0
- package/dist/design-mode.js +1 -1
- package/dist/design-system.d.ts +150 -0
- package/dist/design-tokens.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/inline-text-editor-SWPVB35B.js +1 -0
- package/dist/inline-text-editor.d.ts +3 -0
- package/dist/node.mjs +1 -1
- package/dist/react-inspector.d.ts +9 -1
- package/dist/react-props-panel-XQ4T3RLV.js +1 -0
- package/dist/react-props-panel.d.ts +3 -1
- package/dist/react.js +1 -1
- package/dist/review-layout.d.ts +3 -1
- package/dist/setup.js +1 -1
- package/dist/tag-editor-ZA7NLPOJ.js +1 -0
- package/dist/{toolbar-runtime-2SIUE6SQ.js → toolbar-runtime-2JO6YXD5.js} +1 -1
- package/dist/types.d.ts +7 -0
- package/package.json +11 -2
- package/server/iap.ts +133 -0
- package/server/setup-client.txt +116 -72
- package/src/types.ts +8 -0
- package/dist/chunk-JQVBZ2BB.js +0 -1
- package/dist/chunk-Z2ABBESO.js +0 -1
- package/dist/design-comment-QPTW66JO.js +0 -1
- package/dist/inline-text-editor-F7B6FQQ3.js +0 -1
- package/dist/react-props-panel-XSMDR2CY.js +0 -1
- package/dist/tag-editor-VDPZ6CO3.js +0 -1
package/README.md
CHANGED
|
@@ -115,6 +115,58 @@ Komo adapts those patterns to an embedded live page: direct hover/select, a comp
|
|
|
115
115
|
|
|
116
116
|
Sources: [Figma layer properties and styles](https://help.figma.com/hc/en-us/articles/360039832014-Design-prototype-and-explore-layer-properties-in-the-right-sidebar), [Figma Dev Mode](https://help.figma.com/hc/en-us/articles/15023124644247-Guide-to-Dev-Mode), [pen.dev installation and IDE design mode](https://docs.pen.dev/getting-started/installation), [pen.dev interface and undo/redo](https://docs.pen.dev/core-concepts/pencil-interface), [OpenPencil features and properties panel](https://openpencil.dev/overview/features), [OpenPencil layers and selection sync](https://openpencil.dev/user-guide/layers-and-pages), [Puck component configuration](https://puckeditor.com/docs/integrating-puck/component-configuration), [Puck nested object and array fields](https://puckeditor.com/docs/api-reference/fields/object), [Puck permissions](https://puckeditor.com/docs/api-reference/permissions), [Puck source and MIT license](https://github.com/puckeditor/puck), and the [Design Tokens Format Module 2025.10](https://www.w3.org/community/reports/design-tokens/CG-FINAL-format-20251028/).
|
|
117
117
|
|
|
118
|
+
### Design-system adapters
|
|
119
|
+
|
|
120
|
+
`design: { tokens, themes, components }` tells Design mode about your design system. These are types in `DesignSystem`, and all three are optional. komo never guesses tokens from computed styles or reads framework internals; your adapters answer.
|
|
121
|
+
|
|
122
|
+
- `tokens: TokenAdapter` lists tokens (aliases resolved, per theme). For a picked element, it says which token each CSS property uses, or that the value is off-token. It can also preview a token, for example by swapping a utility class, and describe how to apply the change in source.
|
|
123
|
+
- `themes: ThemeAxis[]` are independent axes reviewers can flip, such as light/dark or a product palette. Proposals record the theme state they were made in.
|
|
124
|
+
- `components: ComponentAdapter` identifies the component behind an element (name, props, source), so Design mode shows "Button (variant=secondary)". It works alongside `useKomoInspectable`.
|
|
125
|
+
|
|
126
|
+
Design proposals also carry a versioned `DesignEdit` record (token swaps, prop changes, text, and a raw CSS fallback) that the CLI and agents can apply.
|
|
127
|
+
|
|
128
|
+
The API is landing in stages, and this section is updated as each part ships. Without `design.tokens`, Design mode uses the CSS custom properties registered with `useKomoDesignTokens`.
|
|
129
|
+
|
|
130
|
+
#### Tailwind and class themes
|
|
131
|
+
|
|
132
|
+
Two optional adapters ship as their own entry points, outside the core bundle. For utility-class design systems, a token is a class: komo previews by swapping classes, not by setting CSS variables.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { tailwindTokens, tailwindSpacing, type TailwindToken } from "@hazem3500/komo/adapters/tailwind";
|
|
136
|
+
import { classTheme } from "@hazem3500/komo/adapters/class-theme";
|
|
137
|
+
|
|
138
|
+
const mode = classTheme({
|
|
139
|
+
id: "mode",
|
|
140
|
+
options: [{ id: "light", class: "light" }, { id: "dark", class: "dark" }],
|
|
141
|
+
colorScheme: true, // also sets color-scheme: light | dark on <html>
|
|
142
|
+
});
|
|
143
|
+
const product = classTheme({
|
|
144
|
+
id: "product",
|
|
145
|
+
options: [{ id: "focus", attribute: { "data-product": "focus" } }, { id: "track", attribute: { "data-product": "track" } }],
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Generate this from your design-system foundations.
|
|
149
|
+
const tokens: TailwindToken[] = [
|
|
150
|
+
{ path: "color.text.primary", type: "color", class: "text-primary", properties: ["color"], group: "Text",
|
|
151
|
+
values: { light: "#1f1f1f", dark: "#f5f5f5", "track+dark": "#fce5d8" } },
|
|
152
|
+
{ path: "color.bg.primary-interactive", type: "color", class: "bg-primary-interactive",
|
|
153
|
+
properties: ["background-color"], value: "#e57cd8", states: ["hover", "active", "disabled"] },
|
|
154
|
+
{ path: "radius.md", type: "dimension", class: "rounded-md", properties: ["border-radius"], value: "6px" },
|
|
155
|
+
{ path: "typography.h1", type: "typography", class: "text-h1",
|
|
156
|
+
properties: ["font-size", "line-height", "font-weight"], value: "32px/40px 600" },
|
|
157
|
+
...tailwindSpacing(), // p-*, px-*, …, m-*, gap-* on the 4px scale
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
initKomo({ project, design: { tokens: tailwindTokens({ tokens }, { themes: [mode, product] }), themes: [mode, product] } });
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
- `class` is the utility class; an array lists aliases, and the first is the one previews add. `properties` are the CSS properties the class sets, as the Design panel names them. A shorthand such as `padding` or `border-radius` also covers its longhands.
|
|
164
|
+
- `values` keys are option ids (`dark`), `axis=option` pairs (`mode=dark`), or combinations joined with `+` (`track+dark`). The most specific match wins, then `value`.
|
|
165
|
+
- `resolve()` reads base-state classes only; variants such as `hover:` or `md:` are ignored. When classes overlap, the narrower class wins, as in Tailwind (`p-4 px-2` reads `padding-left` from `px-2`). Properties with no table class are reported off-token with their computed value; pass `offToken: [...]` to narrow the list or `false` to turn it off.
|
|
166
|
+
- Previews replace table classes the new class fully covers, keep everything else in place, and stack; undoing restores the original `class` exactly. Classes outside the table, such as `text-[14px]`, are left alone.
|
|
167
|
+
- `tailwindSpacing({ prefix, scale, steps })` narrows the families (`p`, `px`, `py`, `pt`, `pr`, `pb`, `pl`, `m`, `mx`, …, `gap`, `gap-x`, `gap-y`), the pixels per step (default 4), and the steps (default Tailwind's 0 to 96). Paths are `spacing.<class>`, for example `spacing.p-4`.
|
|
168
|
+
- `classTheme` options take `class`, `attribute`, or both, on `target()` (default `<html>`). An option with neither is the default. With `colorScheme`, applying an option sets `color-scheme` to its `colorScheme` or id, and returning to the starting option restores the page's own value.
|
|
169
|
+
|
|
118
170
|
## Agent CLI
|
|
119
171
|
|
|
120
172
|
`komo init` adds the default comment workflow to `AGENTS.md`, preserving existing instructions. For an existing project, run `komo agents setup` from its root. Commit the instructions so every agent uses them.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ThemeAxis } from "../design-system.js";
|
|
2
|
+
export interface ClassThemeOption {
|
|
3
|
+
id: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
/** Class(es) present on the target while this option is active, e.g. "dark". */
|
|
6
|
+
class?: string | string[];
|
|
7
|
+
/** Attributes set on the target while this option is active, e.g. { "data-theme": "dark" }. */
|
|
8
|
+
attribute?: Record<string, string>;
|
|
9
|
+
/** `color-scheme` to set when the axis has `colorScheme`; defaults to the option id. */
|
|
10
|
+
colorScheme?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ClassThemeOptions {
|
|
13
|
+
id: string;
|
|
14
|
+
label?: string;
|
|
15
|
+
options: ClassThemeOption[];
|
|
16
|
+
/** Element carrying the classes or attributes; defaults to `<html>`. */
|
|
17
|
+
target?: () => Element;
|
|
18
|
+
/** Also set the target's inline `color-scheme` (e.g. for light/dark). */
|
|
19
|
+
colorScheme?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** A `ThemeAxis` that reads and switches classes or attributes on one element. */
|
|
22
|
+
export declare function classTheme(config: ClassThemeOptions): ThemeAxis;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t=t=>(Array.isArray(t.class)?t.class:[t.class??""]).flatMap(t=>t.split(/\s+/)).filter(Boolean);function e(e){let o,r=e.target??(()=>document.documentElement),i=e=>t(e).length+Object.keys(e.attribute??{}).length,l=(e,o)=>t(o).every(t=>e.classList.contains(t))&&Object.entries(o.attribute??{}).every(([t,o])=>e.getAttribute(t)===o);function s(){let t,o=r();for(let r of e.options)l(o,r)&&(!t||i(r)>i(t))&&(t=r);return(t??e.options[0])?.id??""}return{id:e.id,...e.label?{label:e.label}:{},options:e.options.map(({id:t,label:e})=>({id:t,...e?{label:e}:{}})),current:s,apply(i){let l=e.options.find(t=>t.id===i);if(!l)return;let a=r(),c=a.style;o??={option:s(),colorScheme:c?.colorScheme??""};for(let o of e.options)if(o!==l){a.classList.remove(...t(o));for(let[t,e]of Object.entries(o.attribute??{}))a.getAttribute(t)===e&&!(t in(l.attribute??{}))&&a.removeAttribute(t)}a.classList.add(...t(l));for(let[t,e]of Object.entries(l.attribute??{}))a.setAttribute(t,e);e.colorScheme&&c&&(c.colorScheme=i===o.option?o.colorScheme:l.colorScheme??l.id)}}}export{e as classTheme};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { DesignTokenType, ThemeAxis, ThemeState, TokenAdapter } from "../design-system.js";
|
|
2
|
+
/** One utility class (or a set of equivalent classes) that sets design tokens. */
|
|
3
|
+
export interface TailwindToken {
|
|
4
|
+
/** Stable dot path recorded on proposals, e.g. "color.text.primary". Unique in the table. */
|
|
5
|
+
path: string;
|
|
6
|
+
type: DesignTokenType;
|
|
7
|
+
/**
|
|
8
|
+
* The utility class, e.g. "text-primary". With several, the first is the canonical
|
|
9
|
+
* class komo adds when previewing; the rest are recognised aliases (e.g. "rounded-md").
|
|
10
|
+
*/
|
|
11
|
+
class: string | string[];
|
|
12
|
+
/**
|
|
13
|
+
* CSS properties the class sets, as the Design panel names them: "color",
|
|
14
|
+
* "background-color", "padding", "padding-left", "border-radius", "font-size"...
|
|
15
|
+
* A shorthand also covers its longhands ("padding" covers "padding-top", etc.).
|
|
16
|
+
*/
|
|
17
|
+
properties: string[];
|
|
18
|
+
/** Value when no theme-specific value applies, e.g. "#1f1f1f" or "8px". */
|
|
19
|
+
value?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Values per theme. Keys are option ids ("dark"), "axis=option" pairs ("mode=dark"),
|
|
22
|
+
* or combinations joined with "+" ("track+dark"). The most specific key that
|
|
23
|
+
* fully matches the theme state wins; otherwise `value` is used.
|
|
24
|
+
*/
|
|
25
|
+
values?: Record<string, string>;
|
|
26
|
+
label?: string;
|
|
27
|
+
group?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
/** Interaction states the class carries itself, e.g. ["hover", "active", "disabled"]. */
|
|
30
|
+
states?: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface TailwindTable {
|
|
33
|
+
tokens: TailwindToken[];
|
|
34
|
+
}
|
|
35
|
+
export interface TailwindTokensOptions {
|
|
36
|
+
/** Theme axes used to work out the current theme when `list()` gets none. */
|
|
37
|
+
themes?: ThemeAxis[];
|
|
38
|
+
/**
|
|
39
|
+
* Properties reported as `{ offToken: computed value }` when no table class sets
|
|
40
|
+
* them. Defaults to every property named in the table; `false` reports none.
|
|
41
|
+
*/
|
|
42
|
+
offToken?: string[] | false;
|
|
43
|
+
}
|
|
44
|
+
/** Pick the theme-specific value: the most specific fully-matching key, else `value`. */
|
|
45
|
+
export declare function tokenValue(token: Pick<TailwindToken, "value" | "values">, theme?: ThemeState): string;
|
|
46
|
+
/** A `TokenAdapter` whose tokens are utility classes listed in `table`. */
|
|
47
|
+
export declare function tailwindTokens(table: TailwindTable, options?: TailwindTokensOptions): TokenAdapter;
|
|
48
|
+
/** Tailwind's default spacing steps (multiples of the base unit). */
|
|
49
|
+
export declare const defaultSpacingSteps: number[];
|
|
50
|
+
export interface TailwindSpacingOptions {
|
|
51
|
+
/** Utility families; defaults to every padding, margin and gap family (p, px, ..., m, ..., gap, gap-x, gap-y). */
|
|
52
|
+
prefix?: string[];
|
|
53
|
+
/** Pixels per step; Tailwind's default is 4. */
|
|
54
|
+
scale?: number;
|
|
55
|
+
/** Steps to emit; defaults to Tailwind's spacing scale (0 to 96). */
|
|
56
|
+
steps?: number[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Table entries for spacing utilities, e.g. `p-4` → padding 16px at scale 4.
|
|
60
|
+
* Paths are "spacing.<class>", e.g. "spacing.px-2.5".
|
|
61
|
+
*/
|
|
62
|
+
export declare function tailwindSpacing(options?: TailwindSpacingOptions): TailwindToken[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=["top","right","bottom","left"],t={padding:e.map(e=>`padding-${e}`),margin:e.map(e=>`margin-${e}`),gap:["row-gap","column-gap"],"border-radius":["top-left","top-right","bottom-right","bottom-left"].map(e=>`border-${e}-radius`),"border-width":e.map(e=>`border-${e}-width`),"border-color":e.map(e=>`border-${e}-color`)},r=e=>(Array.isArray(e)?e:[e]).flatMap(e=>e.split(/\s+/)).filter(Boolean),a=e=>e.getAttribute("class"),n=e=>e.includes(":")?null:e.replace(/^!|!$/g,"");function i(e,t={}){let r,a=0;for(let[n,i]of Object.entries(e.values??{})){let e=n.split("+");e.every(e=>{let[r,a]=e.split("=");return void 0===a?Object.values(t).includes(r):t[r]===a})&&e.length>a&&([r,a]=[i,e.length])}return r??e.value??""}function o(e,o={}){let l=e.tokens.map(e=>({token:e,classes:r(e.class),covers:new Set(e.properties.flatMap(e=>[e,...t[e]??[]]))})),s=new Map;for(let e of l)for(let t of e.classes)s.set(t,e);let p=new Map(l.map(e=>[e.token.path,e])),g=!1===o.offToken?[]:o.offToken??[...new Set(e.tokens.flatMap(e=>e.properties))],d=new WeakMap,c=e=>(e??"").split(/\s+/).flatMap(e=>{let t=n(e),r=t?s.get(t):void 0;return r?[{name:e,entry:r}]:[]});function f(e,r){if(!r.stack.length)return null===r.original?e.removeAttribute("class"):e.setAttribute("class",r.original),void d.delete(e);e.setAttribute("class",r.stack.reduce((e,r)=>function(e,r,a){let i=e.split(/\s+/).filter(Boolean),o=a.classes[0],l=-1,p=i.filter((e,i)=>{let o=n(e),p=o?s.get(o):void 0,g=!!p&&(p===a||[...p.covers].every(e=>a.covers.has(e))&&(p.covers.has(r)||(t[r]??[]).some(e=>p.covers.has(e))));return g&&l<0&&(l=i),!g}),g=i.slice(0,l<0?i.length:l).filter(e=>p.includes(e)).length;return p.splice(g,0,o),p.join(" ")}(e,r.property,r.entry),r.original??""))}return{id:"tailwind",list(e){let t=e??Object.fromEntries((o.themes??[]).map(e=>[e.id,e.current()]));return l.map(({token:e,classes:r})=>({path:e.path,type:e.type,value:i(e,t),properties:[...e.properties],ref:r[0],...e.label?{label:e.label}:{},...e.group?{group:e.group}:{},...e.description?{description:e.description}:{},...e.states?{states:[...e.states]}:{}}))},resolve(e){let r,n={},i=function(e){let r=new Map;for(let t of c(e))for(let e of t.entry.covers){let a=r.get(e);(!a||t.entry.covers.size<=a.entry.covers.size)&&r.set(e,t)}for(let[e,a]of r)t[e]?.some(e=>r.get(e)?.entry!==a.entry)&&r.delete(e);return r}(a(e));for(let[e,t]of i)n[e]={path:t.entry.token.path};for(let a of g){if(i.has(a)||t[a]?.some(e=>i.has(e)))continue;r??=getComputedStyle(e);let o=r.getPropertyValue(a);o&&(n[a]={offToken:o})}return n},preview(e,t,r){let n=p.get(r.path);if(!n)return()=>{};let i=d.get(e)??{original:a(e),stack:[]};d.set(e,i);let o={property:t,entry:n};return i.stack.push(o),f(e,i),()=>{let t=i.stack.indexOf(o);t<0||(i.stack.splice(t,1),f(e,i))}},describe(e,t,r,n){let i=p.get(n.path)?.classes[0]??n.ref??n.path;if("path"in r){let t=p.get(r.path),n=d.get(e)?.original??a(e),o=c(n).find(e=>e.entry===t)?.name??t?.classes[0]??r.path;return o===i?`Keep class "${i}"`:`Replace class "${o}" with "${i}"`}return`Add class "${i}"`}}}var l={p:["Padding",["padding"]],px:["Padding",["padding-left","padding-right"]],py:["Padding",["padding-top","padding-bottom"]],pt:["Padding",["padding-top"]],pr:["Padding",["padding-right"]],pb:["Padding",["padding-bottom"]],pl:["Padding",["padding-left"]],m:["Margin",["margin"]],mx:["Margin",["margin-left","margin-right"]],my:["Margin",["margin-top","margin-bottom"]],mt:["Margin",["margin-top"]],mr:["Margin",["margin-right"]],mb:["Margin",["margin-bottom"]],ml:["Margin",["margin-left"]],gap:["Gap",["gap"]],"gap-x":["Gap",["column-gap"]],"gap-y":["Gap",["row-gap"]]},s=[0,.5,1,1.5,2,2.5,3,3.5,4,5,6,7,8,9,10,11,12,14,16,20,24,28,32,36,40,44,48,52,56,60,64,72,80,96];function p(e={}){let t=e.scale??4,r=e.steps??s;return(e.prefix??Object.keys(l)).flatMap(e=>{let a=l[e];if(!a)throw new Error(`komo: unknown spacing prefix "${e}"`);return r.map(r=>{let n=`${e}-${r}`;return{path:`spacing.${n}`,type:"dimension",class:n,properties:a[1],value:r*t+"px",group:a[0],label:n}})})}export{s as defaultSpacingSteps,p as tailwindSpacing,o as tailwindTokens,i as tokenValue};
|