@hazem3500/komo 0.0.0-stage → 0.9.0
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/LICENSE +21 -0
- package/NODE.md +80 -0
- package/NOTICE.md +45 -0
- package/README.md +411 -2
- package/cli/agent.mjs +615 -0
- package/cli/config.mjs +34 -0
- package/cli/index.mjs +405 -0
- package/cli/project.mjs +136 -0
- package/cli/workflow.mjs +42 -0
- package/dist/MorphingMenu.d.ts +30 -0
- package/dist/PointerIcon.d.ts +2 -0
- package/dist/SmileIcon.d.ts +2 -0
- package/dist/THIRD_PARTY_NOTICES.txt +387 -0
- package/dist/accent-picker-F5UI2NP7.js +1 -0
- package/dist/accent-picker.d.ts +4 -0
- package/dist/accent.d.ts +2 -0
- package/dist/account-usage.d.ts +2 -0
- package/dist/action-menu.d.ts +10 -0
- package/dist/agent-prompt.d.ts +6 -0
- package/dist/agent-prompt.js +1 -0
- package/dist/anchors.d.ts +48 -0
- package/dist/api.d.ts +39 -0
- package/dist/approved-sites.d.ts +9 -0
- package/dist/card-motion.d.ts +8 -0
- package/dist/chunk-7YUXYVQA.js +1 -0
- package/dist/chunk-I7AUKTXE.js +1 -0
- package/dist/chunk-JQVBZ2BB.js +1 -0
- package/dist/chunk-Q7WSWLMV.js +1 -0
- package/dist/chunk-Y2GRLW4Q.js +1 -0
- package/dist/chunk-YZP3KX4Y.js +1 -0
- package/dist/chunk-Z2ABBESO.js +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/connect-project.d.ts +14 -0
- package/dist/connection-issue.d.ts +7 -0
- package/dist/design-comment-QPTW66JO.js +1 -0
- package/dist/design-comment.d.ts +42 -0
- package/dist/design-export-BRBI7S3V.js +1 -0
- package/dist/design-export.d.ts +8 -0
- package/dist/design-mode-styles.d.ts +1 -0
- package/dist/design-mode.d.ts +19 -0
- package/dist/design-mode.js +1 -0
- package/dist/design-panel-BPVXFERR.js +1 -0
- package/dist/design-panel-styles.d.ts +1 -0
- package/dist/design-panel.d.ts +33 -0
- package/dist/design-tokens.d.ts +76 -0
- package/dist/dom.d.ts +20 -0
- package/dist/drawer-expand-motion.d.ts +46 -0
- package/dist/drawer-presence.d.ts +4 -0
- package/dist/edge-sidebar.d.ts +39 -0
- package/dist/emoji-history.d.ts +8 -0
- package/dist/emoji.d.ts +1 -0
- package/dist/floating-drag.d.ts +9 -0
- package/dist/icon-markup.d.ts +4 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1 -0
- package/dist/inline-text-editor-F7B6FQQ3.js +1 -0
- package/dist/inline-text-editor.d.ts +70 -0
- package/dist/lazy-accent-picker.d.ts +4 -0
- package/dist/lazy-toolbar.d.ts +19 -0
- package/dist/message-links.d.ts +2 -0
- package/dist/morphing-menu-styles.d.ts +1 -0
- package/dist/node.mjs +2607 -0
- package/dist/onboarding-NO3RQWR7.js +1 -0
- package/dist/onboarding.d.ts +6 -0
- package/dist/optimistic.d.ts +26 -0
- package/dist/page.d.ts +2 -0
- package/dist/picker-WQN53YJ5.js +1 -0
- package/dist/pin-direction.d.ts +12 -0
- package/dist/pin-stacks.d.ts +3 -0
- package/dist/polling.d.ts +10 -0
- package/dist/postgres/001_initial.sql +128 -0
- package/dist/postgres/002_thread_tags.sql +1 -0
- package/dist/postgres/003_project_webhooks.sql +4 -0
- package/dist/project-management.d.ts +2 -0
- package/dist/react-inspector.d.ts +43 -0
- package/dist/react-props-panel-XSMDR2CY.js +1 -0
- package/dist/react-props-panel.d.ts +39 -0
- package/dist/react.d.ts +38 -0
- package/dist/react.js +1 -0
- package/dist/reaction-picker.d.ts +1 -0
- package/dist/review-layout.d.ts +23 -0
- package/dist/setup-browser.d.ts +1 -0
- package/dist/setup.d.ts +4 -0
- package/dist/setup.js +1 -0
- package/dist/shortcuts.d.ts +15 -0
- package/dist/static-svg.d.ts +3 -0
- package/dist/styles.d.ts +1 -0
- package/dist/tag-editor-VDPZ6CO3.js +1 -0
- package/dist/tag-editor.d.ts +12 -0
- package/dist/toolbar-runtime-2SIUE6SQ.js +1 -0
- package/dist/toolbar-runtime.d.ts +5 -0
- package/dist/types.d.ts +163 -0
- package/package.json +114 -4
- package/server/digest.ts +8 -0
- package/server/import-project.ts +164 -0
- package/server/index.ts +1656 -0
- package/server/migrations/0001_comments.sql +54 -0
- package/server/migrations/0002_identity.sql +2 -0
- package/server/migrations/0003_accent_color.sql +1 -0
- package/server/migrations/0004_workspaces.sql +46 -0
- package/server/migrations/0005_domains.sql +6 -0
- package/server/migrations/0006_member_budget.sql +16 -0
- package/server/migrations/0007_revisions.sql +17 -0
- package/server/migrations/0008_starter_comments.sql +1 -0
- package/server/migrations/0009_retention.sql +19 -0
- package/server/migrations/0010_reviewer_history.sql +1 -0
- package/server/migrations/0011_project_management.sql +52 -0
- package/server/migrations/0012_setup_sites.sql +3 -0
- package/server/migrations/0013_project_sites.sql +8 -0
- package/server/migrations/0014_project_site_removals.sql +3 -0
- package/server/migrations/0015_query_efficiency.sql +6 -0
- package/server/migrations/0016_thread_tags.sql +1 -0
- package/server/migrations/0017_project_webhooks.sql +4 -0
- package/server/node-webhooks.ts +126 -0
- package/server/project-management.ts +387 -0
- package/server/project-sites.ts +117 -0
- package/server/secrets.d.ts +24 -0
- package/server/setup-client.txt +2932 -0
- package/server/setup-page.ts +14 -0
- package/server/tsconfig.json +12 -0
- package/server/validation.ts +220 -0
- package/server/webhooks.ts +206 -0
- package/server/workspaces.ts +168 -0
- package/src/emoji.ts +7 -0
- package/src/page.ts +4 -0
- package/src/types.ts +166 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CommentsOptions, Identity } from "./types.js";
|
|
2
|
+
type SetupResult = {
|
|
3
|
+
project: string;
|
|
4
|
+
repo: string;
|
|
5
|
+
token: string;
|
|
6
|
+
user: Identity;
|
|
7
|
+
};
|
|
8
|
+
/** Retain only public settings so a reload before CLI sync can resume commenting. */
|
|
9
|
+
export declare function rememberProject(options: CommentsOptions, result: SetupResult): void;
|
|
10
|
+
export declare function resumeProject(options: CommentsOptions): CommentsOptions;
|
|
11
|
+
/** Normalize pasted page URLs into exact site origins before owner approval. */
|
|
12
|
+
export declare function setupSites(value: string, currentOrigin: string): string[];
|
|
13
|
+
export declare function connectProject(options: CommentsOptions, signal: AbortSignal, sites?: string[]): Promise<SetupResult>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ConnectionIssue = {
|
|
2
|
+
kind: "site" | "offline" | "unreachable" | "server";
|
|
3
|
+
title: string;
|
|
4
|
+
detail: string;
|
|
5
|
+
};
|
|
6
|
+
/** Say why comments didn't load, in words a visitor can act on. */
|
|
7
|
+
export declare function connectionIssue(reason: unknown): ConnectionIssue;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-I7AUKTXE.js";var e=/^Proposed (.+?) changes? \(preview only\)$/,t={style:"Style changes","inline text":"Text change","design-token":"Token changes","React prop":"Prop changes"};function n(t){return t.split("\n").some(t=>e.test(t))}function r(e){try{return e.startsWith('"')?JSON.parse(e):e}catch{return e}}function a(e,t){let n=/^Shared theme (\S+) \((--[\w-]+)\): (.*?) → (.*?)(?:; preview scope .*)?$/.exec(e);if(n)return{label:n[1],token:n[1],before:n[3],after:n[4],apply:{kind:"variable",property:n[2]}};if(n=/^Element ([\w-]+): (.*?) → (.*?)(?: \[([^\]]+)\])*$/.exec(e),n){let t=/\[([\w.-]+)\]/.exec(e.slice(e.indexOf("→")))?.[1];return{label:n[1],before:n[2],after:n[3],...t&&!t.includes(" ")?{token:t}:{},apply:{kind:"style",property:n[1]}}}if(n=/^- (.+?): (.*) → (.*?)(?: \[([^\]]+)\])?$/.exec(e),!n)return null;let[,a,o,s,i]=n;return"inline text"===t?{label:"Text",before:r(o),after:r(s),apply:{kind:"text",property:"text"}}:"React prop"===t?{label:a,before:o,after:s,...i&&"custom value"!==i?{token:i}:{}}:{label:a,before:o,after:s,apply:{kind:"style",property:a}}}function o(n){let r=[];for(let o of n.split(/\n{2,}/)){let n=o.split("\n"),s=e.exec(n[0]??"");if(!s){o.trim()&&r.push({text:o.trim()});continue}let i=s[1],l={title:t[i]??`${i[0].toUpperCase()}${i.slice(1)} changes`,changes:[]};for(let e of n.slice(1))if(e.startsWith("Target: "))l.target=e.slice(8);else if(e.startsWith("Component: "))l.component=e.slice(11);else if(e.startsWith("Source: "))l.source=e.slice(8);else{let t=e.includes("→")?a(e,i):null;t&&t.before!==t.after&&l.changes.push(t)}l.changes.length?r.push(l):r.push({text:o.trim()})}return r}function s(e){let t=o(e),n=t.filter(e=>"changes"in e),r=t.find(e=>"text"in e)?.text,a=n.reduce((e,t)=>e+t.changes.length,0),s=n.find(e=>e.target)?.target,l=`Design change · ${a} ${1===a?"edit":"edits"}${s?` on ${i(s)}`:""}`;return r?`${r}\n${l}`:l}function i(e){return(e.split(">").at(-1)??e).trim().replace(/:nth-of-type\(\d+\)/g,"")||e}var l=/^(#[0-9a-f]{3,8}|rgba?\([^)]*\)|hsla?\([^)]*\)|oklch\([^)]*\))$/i,p=new Map;function d(e,t,n){let r=[];for(let e of t){let t=n(e.target);for(let n of e.changes)if(n.apply&&"(unset)"!==n.after)if("variable"===n.apply.kind){let e=document.documentElement,t=e.style.getPropertyValue(n.apply.property);e.style.setProperty(n.apply.property,n.after),r.push(()=>t?e.style.setProperty(n.apply.property,t):e.style.removeProperty(n.apply.property))}else if(t instanceof HTMLElement&&"style"===n.apply.kind){let e=t.style.getPropertyValue(n.apply.property),a=t.style.getPropertyPriority(n.apply.property);t.style.setProperty(n.apply.property,n.after,"important"),r.push(()=>e?t.style.setProperty(n.apply.property,e,a):t.style.removeProperty(n.apply.property))}else if(t instanceof HTMLElement&&"text"===n.apply.kind&&!t.childElementCount){let e=t.firstChild;if(e instanceof Text){let t=e.data;e.data=n.after,r.push(()=>{e.data=t})}}}return p.set(e,{restore:r}),r.length>0}function c(e){let t=p.get(e);if(t){for(let e of t.restore.reverse())e();p.delete(e)}}function f(e=new Set){for(let t of[...p.keys()])e.has(t)||c(t)}function g(e,t){let n=document.createElement("span");n.className="design-value";let r=/^var\((--[\w-]+)\)$/.exec(e);if(t&&r)return n.append(Object.assign(document.createElement("span"),{className:"design-token",textContent:t})),n;if(l.test(e)){let t=document.createElement("span");t.className="design-swatch",t.style.background=e,n.append(t)}return n.append(e),n}function m(e,t,n){let r=o(t),a=r.filter(e=>"changes"in e),s=document.createElement("div");s.className="design-comment",s.append(Object.assign(document.createElement("style"),{textContent:'\n.design-comment { display: grid; gap: 8px; margin: 2px 0 6px; }\n.design-note { margin: 0; white-space: pre-wrap; }\n.design-card { border-radius: 10px; background: #ffffff08; box-shadow: inset 0 0 0 1px #ffffff0d; overflow: hidden; font-size: 12px; }\n.design-card-head { display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 7px 8px 7px 12px; }\n.design-card-label { display: grid; min-width: 0; gap: 1px; }\n.design-card-title { font-weight: 600; color: #eee; white-space: nowrap; }\n.design-card-target { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #8a8a8a; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10.5px; }\n.design-toggle { margin-left: auto; display: inline-flex; padding: 2px; border-radius: 7px; background: #ffffff0a; flex: none; }\n.design-toggle button { border: 0; padding: 0 8px; height: 22px; border-radius: 5px; font: inherit; font-size: 11px; color: #9a9a9a; background: none; cursor: pointer; }\n.design-toggle button[aria-pressed="true"] { color: #fff; background: #ffffff1a; }\n.design-rows { display: grid; border-top: 1px solid #ffffff0a; }\n.design-row { display: grid; grid-template-columns: minmax(64px, 30%) minmax(0, 1fr); gap: 10px; align-items: center; padding: 6px 12px; }\n.design-row + .design-row { border-top: 1px solid #ffffff06; }\n.design-row[hidden] { display: none; }\n.design-prop { color: #9a9a9a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.design-values { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; min-width: 0; color: #eee; }\n.design-before { color: #858585; text-decoration: line-through; text-decoration-color: #85858599; }\n.design-arrow { color: #666; }\n.design-value { display: inline-flex; align-items: center; gap: 5px; min-width: 0; overflow-wrap: anywhere; }\n.design-swatch { width: 12px; height: 12px; flex: none; border-radius: 3px; box-shadow: inset 0 0 0 1px #ffffff26; }\n.design-token { padding: 1px 6px; border-radius: 5px; color: var(--accent, #bda6ef); background: color-mix(in srgb, var(--accent, #bda6ef) 14%, transparent); }\n.design-more { border: 0; width: 100%; padding: 7px 12px; text-align: left; font: inherit; font-size: 11px; color: #9a9a9a; background: none; border-top: 1px solid #ffffff06; cursor: pointer; }\n.design-more:hover, .design-toggle button:hover { color: #fff; }\n.design-source { padding: 0 12px 8px; color: #777; font-size: 11px; }\n'}));let l=a.some(e=>e.changes.some(e=>e.apply)),f=[],m=()=>{let e=p.has(n.key);for(let t of f)t.querySelectorAll("button").forEach((t,n)=>t.setAttribute("aria-pressed",String(1===n?e:!e)))};for(let e of r){if("text"in e){let t=document.createElement("p");t.className="design-note",n.note(t,e.text),s.append(t);continue}let t=document.createElement("section");t.className="design-card";let r=document.createElement("div");r.className="design-card-head";let o=document.createElement("div");o.className="design-card-label",o.append(Object.assign(document.createElement("span"),{className:"design-card-title",textContent:e.title}));let u=e.target?i(e.target):e.component;if(u){let t=Object.assign(document.createElement("span"),{className:"design-card-target",textContent:u});e.target&&(t.title=e.target),o.append(t)}if(r.append(o),l&&!f.length&&e.changes.some(e=>e.apply)){let e=document.createElement("div");e.className="design-toggle",e.setAttribute("role","group"),e.setAttribute("aria-label","Preview on page");for(let[t,r]of["Before","After"].entries()){let o=Object.assign(document.createElement("button"),{type:"button",textContent:r});o.addEventListener("click",()=>{let e=1===t;if(e===p.has(n.key))return;let r=n.resolve(a.find(e=>e.target)?.target);e&&r?.scrollIntoView({block:"center",behavior:"smooth"});let o=()=>{e?d(n.key,a,n.resolve):c(n.key),m()},s=document.startViewTransition;s&&!matchMedia("(prefers-reduced-motion: reduce)").matches?s.call(document,o):o()}),e.append(o)}f.push(e),r.append(e)}t.append(r);let h=document.createElement("div");h.className="design-rows";let x=4;e.changes.forEach((t,n)=>{let r=document.createElement("div");r.className="design-row",r.hidden=n>=x&&e.changes.length>x+1;let a=Object.assign(document.createElement("span"),{className:"design-prop",textContent:t.label});a.title=t.label;let o=document.createElement("span");o.className="design-values";let s=g(t.before);s.classList.add("design-before"),o.append(s,Object.assign(document.createElement("span"),{className:"design-arrow",textContent:"→"}),g(t.after,t.token)),r.append(a,o),h.append(r)}),t.append(h);let y=h.querySelectorAll("[hidden]").length;if(y){let e=Object.assign(document.createElement("button"),{type:"button",className:"design-more",textContent:`Show ${y} more`});e.addEventListener("click",()=>{h.querySelectorAll("[hidden]").forEach(e=>e.hidden=!1),e.remove()}),t.append(e)}e.source&&t.append(Object.assign(document.createElement("div"),{className:"design-source",textContent:e.source})),s.append(t)}m(),e.replaceChildren(s)}export{n as isDesignComment,o as parseDesignComment,m as renderDesignComment,f as resetDesignPreviews,i as shortTarget,s as summarizeDesignComment};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface DesignChange {
|
|
2
|
+
label: string;
|
|
3
|
+
before: string;
|
|
4
|
+
after: string;
|
|
5
|
+
/** Token path such as color.brand, when the change binds a design token. */
|
|
6
|
+
token?: string;
|
|
7
|
+
/** How to preview it on the page; absent when only the app can apply it. */
|
|
8
|
+
apply?: {
|
|
9
|
+
kind: "style" | "variable" | "text";
|
|
10
|
+
property: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface DesignSection {
|
|
14
|
+
title: string;
|
|
15
|
+
target?: string;
|
|
16
|
+
component?: string;
|
|
17
|
+
source?: string;
|
|
18
|
+
changes: DesignChange[];
|
|
19
|
+
}
|
|
20
|
+
export type DesignBlock = {
|
|
21
|
+
text: string;
|
|
22
|
+
} | DesignSection;
|
|
23
|
+
/** True when a comment body contains at least one Design mode proposal. */
|
|
24
|
+
export declare function isDesignComment(body: string): boolean;
|
|
25
|
+
/** Split a comment body into plain notes and recognised proposal sections. */
|
|
26
|
+
export declare function parseDesignComment(body: string): DesignBlock[];
|
|
27
|
+
/** One-line summary for the sidebar, e.g. "Design change · 2 edits on h2". */
|
|
28
|
+
export declare function summarizeDesignComment(body: string): string;
|
|
29
|
+
/** The last step of a generated selector, without :nth-of-type noise. */
|
|
30
|
+
export declare function shortTarget(selector: string): string;
|
|
31
|
+
/** Undo every live preview except those whose cards are still on screen. */
|
|
32
|
+
export declare function resetDesignPreviews(keep?: ReadonlySet<string>): void;
|
|
33
|
+
export interface DesignCommentOptions {
|
|
34
|
+
/** Stable id for this comment, used to keep its preview state across redraws. */
|
|
35
|
+
key: string;
|
|
36
|
+
/** Element the change applies to; falls back to the comment's anchor. */
|
|
37
|
+
resolve(selector?: string): Element | null;
|
|
38
|
+
/** Render plain notes with the widget's normal link handling. */
|
|
39
|
+
note(element: HTMLElement, text: string): void;
|
|
40
|
+
}
|
|
41
|
+
/** Replace `container`'s content with a change card for each proposal. */
|
|
42
|
+
export declare function renderDesignComment(container: HTMLElement, body: string, options: DesignCommentOptions): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-I7AUKTXE.js";function e(e){if(e.id)return`#${CSS.escape(e.id)}`;let n=[],t=e;for(;t&&t!==document.body&&n.length<6;){let e=[...t.classList].slice(0,2).map(e=>`.${CSS.escape(e)}`).join(""),a=t.parentElement?[...t.parentElement.children].filter(e=>e.tagName===t.tagName):[];if(n.unshift(`${t.tagName.toLowerCase()}${e}:nth-of-type(${a.indexOf(t)+1})`),t.parentElement?.id){n.unshift(`#${CSS.escape(t.parentElement.id)}`);break}t=t.parentElement}return n.join(" > ")}function n(n,t){return`${e(n)} {\n${[...t].map(([e,n])=>` ${e}: ${n};`).join("\n")}\n}`}function t(n,t,a,i,r){let o=[...t??[]].filter(([e])=>!i?.has(e)).map(([e,n])=>`- ${e}: ${a(e)||"(unset)"} → ${n}`);return[o.length?`Proposed style changes (preview only)\nTarget: ${e(n)}\n${o.join("\n")}`:"",...r].filter(Boolean).join("\n\n")||void 0}export{e as cssSelector,n as cssText,t as designProposal};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** On-demand formatting for Design mode's Copy CSS and comment proposal actions. */
|
|
2
|
+
export declare function cssSelector(element: Element): string;
|
|
3
|
+
export declare function cssText(element: Element, values: Map<string, string>): string;
|
|
4
|
+
/**
|
|
5
|
+
* One proposal for everything previewed on the element. Token-bound properties
|
|
6
|
+
* are described by the token section, so they are not repeated as raw CSS.
|
|
7
|
+
*/
|
|
8
|
+
export declare function designProposal(element: Element, values: Map<string, string> | undefined, before: (property: string) => string | undefined, bound: Set<string> | undefined, sections: Array<string | undefined>): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const designModeStyles = "\n/* Design mode is deliberately an in-page preview: all controls remain in the\n widget shadow root and never become site styles. */\n.design-outline {\n position:fixed; z-index:1; pointer-events:none; box-sizing:border-box;\n border:2px solid var(--accent,#bda6ef); border-radius:8px;\n box-shadow:0 0 0 3px color-mix(in srgb,var(--accent,#bda6ef) 22%,transparent), 0 2px 12px #0003;\n transition:all 80ms ease;\n}\n.design-outline[data-kind=\"hover\"] { border-style:dashed; opacity:.8; }\n/* The inspector replaces the Comments view inside Komo's shared sidebar surface. */\n.design-inspector {\n position:absolute; inset:0; z-index:9;\n display:flex; flex-direction:column; overflow:hidden; color:#e9e6e1;\n background:#0d0d0d; border-radius:inherit;\n font:12px/1.4 -apple-system,BlinkMacSystemFont,\"Inter\",\"Segoe UI\",sans-serif; color-scheme:dark;\n opacity:0; translate:0 6px; pointer-events:none;\n transition:opacity .15s var(--ease-smooth-out),translate .25s var(--ease-smooth-out);\n}\n.design-inspector[hidden] { display:none; }\n.design-inspector[data-state=\"active\"] { opacity:1; translate:0 0; pointer-events:auto; }\n.design-inspector[data-state=\"closing\"] { opacity:0; translate:0 4px; }\n.design-inspector button { cursor:pointer; }\n.design-inspector__heading { flex:none; display:flex; align-items:center; gap:2px; height:44px; padding:0 6px 0 12px; border-bottom:1px solid #ffffff12; }\n.design-inspector__identity { min-width:0; flex:1; display:flex; align-items:baseline; gap:4px; white-space:nowrap; }\n.design-inspector__parent { flex:none; max-width:30%; overflow:hidden; text-overflow:ellipsis; margin-left:-4px; padding:2px 4px; border-radius:4px; color:#77736f; font-size:12px; }\n.design-inspector__parent::after { content:'/'; margin-left:4px; color:#4a4845; }\n.design-inspector__parent:hover { color:#e9e6e1; background:#ffffff0d; }\n.design-inspector__target { flex:none; margin-right:2px; max-width:60%; overflow:hidden; text-overflow:ellipsis; font-weight:600; font-size:12px; }\n.design-inspector__heading small { min-width:0; overflow:hidden; text-overflow:ellipsis; color:#77736f; font-size:11px; }\n.design-inspector__close,.design-inspector__fold { display:grid; place-items:center; width:28px; height:28px; flex:none; border-radius:6px; color:#898680; }\n.design-inspector__close svg,.design-inspector__fold svg { width:14px; height:14px; }\n.design-inspector__close:hover,.design-inspector__fold:hover { background:#ffffff12; color:#fff; }\n.design-inspector__fold { display:none; }\n.design-inspector__fold svg { transition:rotate .25s var(--ease-smooth-out); }\n.design-inspector[data-folded] .design-inspector__fold svg { rotate:180deg; }\n.design-inspector[data-folded] > :not(.design-inspector__heading) { display:none; }\n.design-inspector[data-folded] .design-inspector__heading { border:0; }\n.design-inspector__controls { flex:1; min-height:0; overflow:auto; overscroll-behavior:contain; scrollbar-width:thin; }\n/* Empty state: the floating sidebar fits a compact, centered hint instead of an empty column. */\n:host([data-sidebar=\"edge\"]) .edge-sidebar[data-design-empty]:not([data-morphing]) { height:auto !important; }\n:host([data-sidebar=\"edge\"]) [data-design-empty] > .design-inspector { position:relative; inset:auto; }\n/* The hidden toolbar docked in the sidebar would otherwise add its height. */\n:host([data-sidebar=\"edge\"]) [data-design-empty]:not([data-morphing]) > .toolbar { position:absolute; }\n.design-inspector[data-empty] .design-inspector__heading { border:0; }\n.design-inspector[data-empty] .design-inspector__identity { visibility:hidden; }\n.design-inspector[data-empty] .design-inspector__controls { display:grid; place-items:center; }\n.design-inspector[data-empty] .design-inspector__bar:not([data-changes],[data-message]) { display:none; }\n.design-inspector__empty { display:flex; flex-direction:column; align-items:center; gap:4px; padding:0 24px 28px; color:#898680; font-size:11px; text-align:center; }\n.design-inspector__empty > svg { box-sizing:content-box; width:20px; height:20px; margin-bottom:8px; padding:8px; border-radius:10px; background:#ffffff0a; color:#77736f; }\n.design-inspector__empty strong { color:#e9e6e1; font-size:12px; font-weight:600; }\n.design-inspector__empty ul { display:grid; gap:6px; margin:8px 0 0; padding:0; list-style:none; }\n.design-inspector__empty kbd { display:inline-block; min-width:8px; padding:0 5px; border-radius:4px; background:#ffffff0f; box-shadow:inset 0 0 0 1px #ffffff12,inset 0 -1px 0 #ffffff12; color:#c9c5bf; font:inherit; font-size:10px; font-weight:500; line-height:17px; }\n/* One slim bar: a quiet Comment action, plus a change count and tools once something changed. */\n.design-inspector__bar { flex:none; display:flex; align-items:center; gap:8px; min-height:44px; padding:0 8px 0 12px; border-top:1px solid #ffffff12; color:#898680; font-size:11px; }\n.design-inspector__count { white-space:nowrap; font-variant-numeric:tabular-nums; }\n.design-inspector__status { display:none; min-width:0; margin:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; animation:design-status .2s var(--ease-smooth-out); }\n.design-inspector__bar[data-message] .design-inspector__status { display:block; }\n.design-inspector__bar[data-message] .design-inspector__count,.design-inspector__bar:not([data-changes]) .design-inspector__tool { display:none; }\n.design-inspector__actions { display:flex; align-items:center; gap:2px; margin-left:auto; }\n.design-inspector__actions button { display:grid; place-items:center; min-width:28px; height:28px; border-radius:6px; color:#aaa6a0; }\n.design-inspector__actions button:hover:not(:disabled) { background:#ffffff12; color:#fff; }\n.design-inspector__actions button:disabled { cursor:default; opacity:.35; }\n.design-inspector__actions svg { width:14px; height:14px; }\n.design-inspector__actions button:last-child { padding:0 10px; color:#e9e6e1; font-size:11px; font-weight:550; }\n.design-inspector__bar[data-changes] .design-inspector__actions button:last-child { margin-left:4px; background:#bda6ef; color:#211b2d; }\n.design-inspector__bar[data-changes] .design-inspector__actions button:last-child:hover { background:#c8b5f4; }\n.design-inspector :focus-visible { outline:2px solid #bda6ef; outline-offset:2px; }\n@keyframes design-status { from { opacity:0; translate:0 2px; } }\n@media (max-width:520px) {\n /* A content-sized bottom sheet; folding it leaves only the heading over the page. */\n .design-inspector {\n position:fixed; inset:auto 12px calc(12px + env(safe-area-inset-bottom,0px));\n max-height:min(58dvh,560px);\n border-radius:24px; box-shadow:0 -1px 0 #ffffff24,0 16px 48px #0005;\n transition:translate 320ms cubic-bezier(.22,1,.36,1),scale 320ms cubic-bezier(.22,1,.36,1),opacity 150ms ease;\n transform-origin:bottom center;\n }\n .design-inspector__heading { height:52px; padding-left:18px; }\n .design-inspector__fold { display:grid; }\n .design-inspector[data-empty] .design-inspector__identity { visibility:visible; }\n .design-field { height:34px; }\n}\n@media (prefers-reduced-motion:reduce) {\n .design-outline,.design-inspector,.design-inspector__fold svg,.design-inspector__status { transition:none; animation:none; }\n}\n";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface DesignModeOptions {
|
|
2
|
+
root: ShadowRoot;
|
|
3
|
+
/** Shared Komo sidebar surface; the inspector rides its morph. Tests may omit it. */
|
|
4
|
+
panelRoot?: HTMLElement;
|
|
5
|
+
host: HTMLElement;
|
|
6
|
+
targetAt(x: number, y: number): Element | null;
|
|
7
|
+
onComment(element: Element, proposal?: string): void;
|
|
8
|
+
onExit(): void;
|
|
9
|
+
/** Label of the shortcut that toggles Design mode, shown in the empty state. */
|
|
10
|
+
exitKey?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createDesignMode(options: DesignModeOptions): {
|
|
13
|
+
setActive: (value: boolean) => void;
|
|
14
|
+
mountPanel(parent: HTMLElement): void;
|
|
15
|
+
readonly active: boolean;
|
|
16
|
+
/** Resolves once the property controls have loaded. */
|
|
17
|
+
ready: Promise<void>;
|
|
18
|
+
destroy(): void;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as e}from"./chunk-YZP3KX4Y.js";import"./chunk-I7AUKTXE.js";var t=e=>`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="${e}"/></svg>`;function n(n){let i=document.createElement("style");i.textContent='.design-outline{position:fixed;z-index:1;pointer-events:none;box-sizing:border-box;border:2px solid var(--accent,#bda6ef);border-radius:8px;box-shadow:0 0 0 3px color-mix(in srgb,var(--accent,#bda6ef) 22%,transparent),0 2px 12px #0003;transition:all 80ms ease}.design-outline[data-kind=hover]{border-style:dashed;opacity:.8}.design-inspector{position:absolute;inset:0;z-index:9;display:flex;flex-direction:column;overflow:hidden;color:#e9e6e1;background:#0d0d0d;border-radius:inherit;font:12px/1.4 -apple-system,BlinkMacSystemFont,Inter,Segoe UI,sans-serif;color-scheme:dark;opacity:0;translate:0 6px;pointer-events:none;transition:opacity .15s var(--ease-smooth-out),translate .25s var(--ease-smooth-out)}.design-inspector[hidden]{display:none}.design-inspector[data-state=active]{opacity:1;translate:0 0;pointer-events:auto}.design-inspector[data-state=closing]{opacity:0;translate:0 4px}.design-inspector button{cursor:pointer}.design-inspector__heading{flex:none;display:flex;align-items:center;gap:2px;height:44px;padding:0 6px 0 12px;border-bottom:1px solid #ffffff12}.design-inspector__identity{min-width:0;flex:1;display:flex;align-items:baseline;gap:4px;white-space:nowrap}.design-inspector__parent{flex:none;max-width:30%;overflow:hidden;text-overflow:ellipsis;margin-left:-4px;padding:2px 4px;border-radius:4px;color:#77736f;font-size:12px}.design-inspector__parent:after{content:"/";margin-left:4px;color:#4a4845}.design-inspector__parent:hover{color:#e9e6e1;background:#ffffff0d}.design-inspector__target{flex:none;margin-right:2px;max-width:60%;overflow:hidden;text-overflow:ellipsis;font-weight:600;font-size:12px}.design-inspector__heading small{min-width:0;overflow:hidden;text-overflow:ellipsis;color:#77736f;font-size:11px}.design-inspector__close,.design-inspector__fold{display:grid;place-items:center;width:28px;height:28px;flex:none;border-radius:6px;color:#898680}.design-inspector__close svg,.design-inspector__fold svg{width:14px;height:14px}.design-inspector__close:hover,.design-inspector__fold:hover{background:#ffffff12;color:#fff}.design-inspector__fold{display:none}.design-inspector__fold svg{transition:rotate .25s var(--ease-smooth-out)}.design-inspector[data-folded] .design-inspector__fold svg{rotate:180deg}.design-inspector[data-folded]>:not(.design-inspector__heading){display:none}.design-inspector[data-folded] .design-inspector__heading{border:0}.design-inspector__controls{flex:1;min-height:0;overflow:auto;overscroll-behavior:contain;scrollbar-width:thin}:host([data-sidebar="edge"]) .edge-sidebar[data-design-empty]:not([data-morphing]){height:auto!important}:host([data-sidebar="edge"]) [data-design-empty]>.design-inspector{position:relative;inset:auto}:host([data-sidebar="edge"]) [data-design-empty]:not([data-morphing])>.toolbar{position:absolute}.design-inspector[data-empty] .design-inspector__heading{border:0}.design-inspector[data-empty] .design-inspector__identity{visibility:hidden}.design-inspector[data-empty] .design-inspector__controls{display:grid;place-items:center}.design-inspector[data-empty] .design-inspector__bar:not([data-changes],[data-message]){display:none}.design-inspector__empty{display:flex;flex-direction:column;align-items:center;gap:4px;padding:0 24px 28px;color:#898680;font-size:11px;text-align:center}.design-inspector__empty>svg{box-sizing:content-box;width:20px;height:20px;margin-bottom:8px;padding:8px;border-radius:10px;background:#ffffff0a;color:#77736f}.design-inspector__empty strong{color:#e9e6e1;font-size:12px;font-weight:600}.design-inspector__empty ul{display:grid;gap:6px;margin:8px 0 0;padding:0;list-style:none}.design-inspector__empty kbd{display:inline-block;min-width:8px;padding:0 5px;border-radius:4px;background:#ffffff0f;box-shadow:inset 0 0 0 1px #ffffff12,inset 0 -1px #ffffff12;color:#c9c5bf;font:inherit;font-size:10px;font-weight:500;line-height:17px}.design-inspector__bar{flex:none;display:flex;align-items:center;gap:8px;min-height:44px;padding:0 8px 0 12px;border-top:1px solid #ffffff12;color:#898680;font-size:11px}.design-inspector__count{white-space:nowrap;font-variant-numeric:tabular-nums}.design-inspector__status{display:none;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;animation:design-status .2s var(--ease-smooth-out)}.design-inspector__bar[data-message] .design-inspector__status{display:block}.design-inspector__bar[data-message] .design-inspector__count,.design-inspector__bar:not([data-changes]) .design-inspector__tool{display:none}.design-inspector__actions{display:flex;align-items:center;gap:2px;margin-left:auto}.design-inspector__actions button{display:grid;place-items:center;min-width:28px;height:28px;border-radius:6px;color:#aaa6a0}.design-inspector__actions button:hover:not(:disabled){background:#ffffff12;color:#fff}.design-inspector__actions button:disabled{cursor:default;opacity:.35}.design-inspector__actions svg{width:14px;height:14px}.design-inspector__actions button:last-child{padding:0 10px;color:#e9e6e1;font-size:11px;font-weight:550}.design-inspector__bar[data-changes] .design-inspector__actions button:last-child{margin-left:4px;background:#bda6ef;color:#211b2d}.design-inspector__bar[data-changes] .design-inspector__actions button:last-child:hover{background:#c8b5f4}.design-inspector :focus-visible{outline:2px solid #bda6ef;outline-offset:2px}@keyframes design-status{0%{opacity:0;translate:0 2px}}@media(max-width:520px){.design-inspector{position:fixed;inset:auto 12px calc(12px + env(safe-area-inset-bottom,0px));max-height:min(58dvh,560px);border-radius:24px;box-shadow:0 -1px #ffffff24,0 16px 48px #0005;transition:translate .32s cubic-bezier(.22,1,.36,1),scale .32s cubic-bezier(.22,1,.36,1),opacity .15s ease;transform-origin:bottom center}.design-inspector__heading{height:52px;padding-left:18px}.design-inspector__fold{display:grid}.design-inspector[data-empty] .design-inspector__identity{visibility:visible}.design-field{height:34px}}@media(prefers-reduced-motion:reduce){.design-outline,.design-inspector,.design-inspector__fold svg,.design-inspector__status{transition:none;animation:none}}\n';let o=null,s=import("./design-panel-BPVXFERR.js").then(e=>{i.textContent+=e.designPanelStyles,o=e},()=>{b.textContent="Design controls unavailable · try again"}),a=document.createElement("aside");a.className="design-inspector",a.setAttribute("role","dialog"),a.setAttribute("aria-label","Design mode inspector"),a.setAttribute("aria-hidden","true"),a.hidden=!0;let r=document.createElement("div");r.className="design-outline",r.setAttribute("aria-hidden","true");let d=document.createElement("div");d.className="design-inspector__heading";let l=document.createElement("button");l.type="button",l.className="design-inspector__parent",l.hidden=!0;let c=document.createElement("span");c.className="design-inspector__target";let p=document.createElement("small"),g=document.createElement("button");g.type="button",g.className="design-inspector__close",g.setAttribute("aria-label","Exit design mode"),g.append(e("close"));let m=document.createElement("button");m.type="button",m.className="design-inspector__fold",m.append(e("chevron"));let u=document.createElement("div");u.className="design-inspector__identity",u.append(l,c,p),d.append(u,m,g);let f=document.createElement("div");f.className="design-inspector__controls";let h=document.createElement("div");h.className="design-inspector__bar";let x=document.createElement("span");x.className="design-inspector__count",x.title="Preview only · resets on refresh";let b=document.createElement("p");b.className="design-inspector__status",b.setAttribute("role","status");let y=document.createElement("div");y.className="design-inspector__actions";let _=(e,t)=>{let n=document.createElement("button");return n.type="button",n.className="design-inspector__tool",n.title=e,n.setAttribute("aria-label",e),n.innerHTML=t,n},v=_("Undo",t("M5.5 3.5 2.5 6.5l3 3m-3-3h7a4 4 0 0 1 0 8h-2")),w=_("Reset",t("M2.5 2.5v3h3M3 5.5a5.5 5.5 0 1 1-.5 2.5")),E=_("Copy CSS","");E.append(e("copy"));let k=document.createElement("button");k.type="button",k.textContent="Comment";let C=document.createElement("button");C.type="button",C.className="design-text-edit",C.title="Edit text",C.textContent="Edit text",C.setAttribute("aria-label","Edit selected text inline"),y.append(v,w,E,k),h.append(x,b,y),a.append(d,f,h),n.root.append(i,r),(n.panelRoot??n.root).append(a);let P=!1,A=0,T=null,L=null,M=null,D=0,S=null,z=null,R=new Map,N=new Map,B=new WeakMap,F=new WeakMap,$=new AbortController,I=new Set,j=[];function H(e,t,n=e.style.getPropertyValue(t),i=e.style.getPropertyPriority(t)){let o=R.get(e);o||R.set(e,o=new Map),o.has(t)||o.set(t,{value:n,priority:i,computed:getComputedStyle(e).getPropertyValue(t).trim()})}function U(e,t){let n=N.get(e);n||N.set(e,n=new Map);let i=e.style.getPropertyValue(t);i===(R.get(e)?.get(t)?.value??"")?n.delete(t):n.set(t,i),n.size||N.delete(e),Q(T,"selected")}let V=0;function X(e,t,n){n?.value?e.style.setProperty(t,n.value,n.priority):e.style.removeProperty(t)}function K(e,t,n){T&&(e.setAttribute("aria-invalid",String(null===n)),null!==n&&(H(T,t),S?.noteDesignTokenOverride(T,t,n),T.style.setProperty(t,n,R.get(T)?.get(t)?.priority),U(T,t),te()))}function O(e,t,n=!0){if(!T)return;let i={value:T.style.getPropertyValue(t),priority:T.style.getPropertyPriority(t)},o=F.get(e),s=o?.before??B.get(e)??{value:"",priority:""};if(i.value===s.value&&i.priority===s.priority)o&&j.splice(j.indexOf(o),1),F.delete(e);else if(o)o.after=i;else{let n={kind:"style",element:T,property:t,before:s,after:i};j.push(n),F.set(e,n)}n&&(B.set(e,i),F.delete(e)),te()}function Y(){if(f.replaceChildren(),q(),!T){let t=document.createElement("div");t.className="design-inspector__empty";let i=document.createElement("strong");i.textContent="Select an element";let o=document.createElement("ul"),s=(...e)=>{let t=document.createElement("li");e.forEach((e,n)=>{n%2==0?t.append(e):t.append(Object.assign(document.createElement("kbd"),{textContent:e}))}),o.append(t)};return s("","Click"," to inspect"),s("","Double-click"," text to edit"),n.exitKey?s("","Esc"," or ",n.exitKey," to exit"):s("","Esc"," to exit"),t.append(e("design"),i,o),f.append(t),c.textContent="Select an element",p.textContent="",void(l.hidden=!0)}let t=`${T.tagName.toLowerCase()}${T.id?`#${T.id}`:""}`;c.textContent=t,p.textContent=T instanceof HTMLIFrameElement?"Frame only · contents are isolated":T.classList.length?`.${[...T.classList].slice(0,2).join(".")}`:"";let i=T.parentElement;l.hidden=!i||i===document.body||i===document.documentElement,l.textContent=i?.tagName.toLowerCase()??"",l.setAttribute("aria-label",`Select parent ${l.textContent}`);let a=T,r=o;r?(r.renderPanel(f,{element:a,changed:N.get(a),collapsed:I,editText:C,begin:(e,t)=>B.set(e,{value:a.style.getPropertyValue(t),priority:a.style.getPropertyPriority(t)}),apply:K,commit:O,rerender:Y}),a.closest("[data-komo-inspectable], [data-komo-design-tokens]")&&(z??=import("./react-props-panel-XSMDR2CY.js").then(e=>S=e).catch(e=>{throw z=null,e}),z.then(e=>{if(!P||T!==a||f.querySelector(".design-react-group, .design-theme-group"))return;let t=n.root,i=e.createReactPropsPanel(a,()=>{b.textContent="React state preview · resets on refresh",te()},t);i&&f.append(i),e.attachStyleTokenControls(a,r.fields,f,(e,t,n)=>{H(a,e.property,n),U(a,e.property),B.set(t,{value:n,priority:a.style.getPropertyPriority(e.property)}),O(t,e.property)},t,r.valueFor,r.toHex);let o=e.createDesignThemePanel(a,r,te,t);o&&f.append(o)}).catch(()=>{}))):s.then(()=>{P&&T===a&&Y()})}function q(){a.toggleAttribute("data-empty",k.hidden=!T),a.parentElement?.toggleAttribute("data-design-empty",P&&!T)}function Q(e,t){if(!P||!e?.isConnected)return void(r.hidden=!0);let n=e.getBoundingClientRect();n.width&&n.height?(r.hidden=!1,r.dataset.kind=t,Object.assign(r.style,{left:`${n.left}px`,top:`${n.top}px`,width:`${n.width}px`,height:`${n.height}px`})):r.hidden=!0}function W(){D||(D=requestAnimationFrame(()=>{D=0,Q(T??L,T?"selected":"hover")}))}function Z(e){!(e instanceof HTMLElement)||n.host.contains(e)||(M?.element&&M.element!==e&&ne(),T=e,L=e,Y(),Q(e,"selected"),te())}function G(){return"function"==typeof matchMedia&&matchMedia("(max-width:520px)").matches}function J(e){a.toggleAttribute("data-folded",e&&G()),m.setAttribute("aria-expanded",String(!a.hasAttribute("data-folded"))),m.setAttribute("aria-label",a.hasAttribute("data-folded")?"Expand inspector":"Collapse inspector")}function ee(e){J(!1),G()&&requestAnimationFrame(()=>{let t=e.getBoundingClientRect(),n=a.getBoundingClientRect().top-12;t.top>=12&&t.bottom<=n||window.scrollBy({top:t.top-Math.max(12,(n-t.height)/2),behavior:matchMedia("(prefers-reduced-motion: reduce)").matches?"auto":"smooth"})})}function te(){(function(){let e=T,t=e?(N.get(e)?.size??0)+ +!!M?.hasChanges(e)+ +!!S?.hasReactPropChanges(e)||+!!S?.hasDesignTokenEdit(e):0;x.textContent=t?`${t} change${t>1?"s":""}`:"",h.toggleAttribute("data-changes",t>0||j.length>0||!(!e||!S?.canUndoReactProp(e)&&!S?.canUndoDesignTokenEdit(e)))})(),v.disabled=!(0!==j.length||T&&S?.canUndoReactProp(T)||T&&S?.canUndoDesignTokenEdit(T)),w.disabled=!T||!N.get(T)?.size&&!M?.hasChanges(T)&&!S?.hasReactPropChanges(T)&&!S?.hasDesignTokenEdit(T),E.disabled=!T||!N.get(T)?.size,k.disabled=!T,C.disabled=!!M?.busy||!T?.isConnected,C.textContent=M?.isEditing(T)?"Done editing":"Edit text",C.setAttribute("aria-label",M?.isEditing(T)?"Finish inline text editing":"Edit selected text inline")}function ne(e=!1){M?.finish(e),te()}function ie(e){!e&&M?.element&&ne(),window.clearTimeout(A),A=0,P=e,q(),e?(a.hidden=!1,a.setAttribute("aria-hidden","false"),requestAnimationFrame(()=>{P&&(a.dataset.state="active")}),r.hidden=!T,Y(),J(!T),Q(T,"selected"),g.focus({preventScroll:!0})):(r.hidden=!0,a.setAttribute("aria-hidden","true"),a.dataset.state="closing","function"==typeof matchMedia&&matchMedia("(prefers-reduced-motion: reduce)").matches?(a.hidden=!0,delete a.dataset.state):A=window.setTimeout(()=>{A=0,P||(a.hidden=!0,delete a.dataset.state)},250))}new MutationObserver(()=>{let e=b.textContent??"";b.title=e,h.toggleAttribute("data-message",!!e),window.clearTimeout(V),e&&(V=window.setTimeout(function e(){M?.element?V=window.setTimeout(e,2600):b.textContent=""},2600))}).observe(b,{childList:!0,characterData:!0,subtree:!0}),C.addEventListener("click",e=>{M||T&&(b.textContent="Loading inline text editor…",import("./inline-text-editor-F7B6FQQ3.js").then(t=>{M||!T||!P||(M=t.bindInlineTextTools({button:C,status:b,selected:()=>T,active:()=>P,onChange:te,onCommit(e){j.push({kind:"text",element:e})}}),M.toggle(e))}).catch(()=>{b.textContent="Inline text editing is unavailable."}))}),m.addEventListener("click",()=>J(!a.hasAttribute("data-folded"))),l.addEventListener("click",()=>Z(T?.parentElement??null)),g.addEventListener("click",()=>{M?.element&&ne(),ie(!1),n.onExit()}),v.addEventListener("click",()=>{let e=j.pop();e?"text"===e.kind?T===(M?.undo()??e.element)&&Y():(X(e.element,e.property,e.before),S?.syncDesignTokenBinding(e.element,e.property),U(e.element,e.property),T===e.element&&Y(),Q(T??L,T?"selected":"hover")):(T&&(S?.undoDesignTokenEdit(T),S?.undoReactProp(T),Y()),b.textContent="React state preview · resets on refresh"),te(),(v.disabled?g:v).focus({preventScroll:!0})}),w.addEventListener("click",()=>{if(!T)return;M?.isEditing(T)&&ne(!0);let e=N.get(T),t=M?.hasChanges(T)??!1,n=S?.hasReactPropChanges(T)??!1,i=S?.hasDesignTokenEdit(T)??!1;if(e?.size||t||n||i){t&&M?.reset(T);for(let t of e?.keys()??[])X(T,t,R.get(T)?.get(t));N.delete(T),n&&S?.resetReactProps(T),i&&S?.resetDesignTokenEdits(T);for(let e=j.length-1;e>=0;e--)j[e].element===T&&j.splice(e,1);Y(),Q(T,"selected"),te(),g.focus({preventScroll:!0})}});let oe=()=>import("./design-export-BRBI7S3V.js");return E.addEventListener("click",()=>{let e=T,t=e?N.get(e):void 0;!e||!t?.size||oe().then(async({cssText:n})=>{let i=n(e,t);try{await navigator.clipboard.writeText(i),b.textContent="CSS copied"}catch{b.textContent=i}})}),k.addEventListener("click",()=>{let e=T;e&&(M?.isEditing(e)&&ne(),oe().then(({designProposal:t})=>n.onComment(e,t(e,N.get(e),t=>R.get(e)?.get(t)?.computed,S?.tokenBoundProperties(e),[M?.proposal(e),S?.proposedDesignChanges(e)])),()=>{b.textContent="Comment unavailable · try again"}))}),document.addEventListener("pointermove",function(e){if(!P||e.composedPath().includes(n.host))return;let t=n.targetAt(e.clientX,e.clientY);!(t instanceof HTMLElement)||n.host.contains(t)||(L=t,T||Q(L,"hover"))},{capture:!0,signal:$.signal}),document.addEventListener("pointerdown",function(e){if(!P||e.composedPath().includes(n.host))return;let t=n.targetAt(e.clientX,e.clientY);!(t instanceof HTMLElement)||n.host.contains(t)||M?.element&&(t===M.element||M.element.contains(t))||(M?.element&&ne(),e.preventDefault(),e.stopImmediatePropagation(),Z(t))},{capture:!0,signal:$.signal}),document.addEventListener("click",function(e){!P||e.composedPath().includes(n.host)||(e.preventDefault(),e.stopImmediatePropagation(),T&&ee(T),2===e.detail&&T?.contains(e.target)&&!C.disabled&&!M?.element&&C.dispatchEvent(new MouseEvent("click",e)))},{capture:!0,signal:$.signal}),document.addEventListener("keydown",function(e){if(M?.handleKey(e))C.focus({preventScroll:!0});else{if(P&&!M?.element&&("Enter"===e.key||" "===e.key)&&!e.composedPath().includes(n.host)){let t=document.activeElement;if(t instanceof HTMLElement&&t!==document.body&&t!==document.documentElement)return e.preventDefault(),e.stopImmediatePropagation(),Z(t),void ee(t)}P&&"Escape"===e.key&&(e.preventDefault(),e.stopImmediatePropagation(),ie(!1),n.onExit())}},{capture:!0,signal:$.signal}),window.addEventListener("scroll",W,{capture:!0,passive:!0,signal:$.signal}),window.addEventListener("resize",W,{passive:!0,signal:$.signal}),{setActive:ie,mountPanel(e){a.parentElement!==e&&(a.parentElement?.removeAttribute("data-design-empty"),e.append(a),q())},get active(){return P},ready:s,destroy(){M?.element&&ne(!0),window.clearTimeout(A),window.clearTimeout(V),$.abort(),cancelAnimationFrame(D);for(let[e,t]of R)for(let[n,i]of t)X(e,n,i);M?.restoreAll(),a.remove(),r.remove(),i.remove()}}}export{n as createDesignMode};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-I7AUKTXE.js";var e=".design-inspector__controls>*+*{border-top:1px solid #ffffff0d}.design-group{padding:0 12px 10px}.design-section>.design-group{padding-bottom:12px}.design-group summary{cursor:pointer;display:flex;align-items:center;gap:4px;height:36px;color:#e9e6e1;font-size:11px;font-weight:600;list-style:none}.design-group summary::-webkit-details-marker{display:none}.design-group summary:after{content:\"\";width:5px;height:5px;margin:-2px 0 0 3px;border:solid #77736f;border-width:0 1.2px 1.2px 0;rotate:45deg;opacity:0;transition:opacity .12s,rotate .2s var(--ease-smooth-out)}.design-group:not([open]) summary:after{rotate:-45deg;margin:0 0 0 2px}.design-group summary:is(:hover,:focus-visible):after,.design-group:not([open]) summary:after{opacity:1}.design-group summary:focus-visible{outline-offset:-2px;border-radius:6px}.design-section{position:relative}.design-section__title{display:flex;align-items:center;height:36px;padding:0 12px;color:#898680;font-size:11px;font-weight:600}.design-section__tools{position:absolute;z-index:1;top:6px;right:8px;display:flex;gap:2px}.design-section__tools button{display:grid;place-items:center;width:24px;height:24px;border-radius:6px;color:#898680;font-size:16px;line-height:1}.design-section__tools button:hover{background:#ffffff12;color:#f1efeb}.design-text-edit{font-size:0!important}.design-text-edit:before{content:\"T\";font:600 13px/1 Georgia,Times New Roman,serif}.design-text-edit[aria-label^=Finish]{background:#bda6ef33;color:#e6dcfb!important}.design-text-edit:disabled{opacity:.35;cursor:default}.design-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:6px 8px}.design-field{position:relative;--lead:4px;min-width:0;height:28px;display:flex;align-items:center;border-radius:6px;background:#ffffff0a;color:#898680;transition:box-shadow .12s var(--ease-smooth-out)}.design-field:hover{box-shadow:inset 0 0 0 1px #ffffff1c}.design-field:focus-within{box-shadow:inset 0 0 0 1px #bda6ef}.design-field:has([aria-invalid=true]){box-shadow:inset 0 0 0 1px #fda29b}.design-field[data-wide]{grid-column:1/-1}.design-field:has(.design-field__glyph){--lead:22px}.design-field--color{--lead:26px}.design-field>input:not([type=color]),.design-field>select{flex:1;box-sizing:border-box;width:100%;min-width:0;height:100%;margin:0;padding:0 8px;border:0;border-radius:6px;outline:0;box-shadow:none;background:none;color:#f1efeb;font:inherit;font-size:11px;font-variant-numeric:tabular-nums;text-overflow:ellipsis}.design-field>:is(input,select):focus-visible{outline:0}.design-field>select{appearance:none;padding-right:20px;cursor:pointer;background:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 3 4 5.5 6.5 3' fill='none' stroke='%23898680' stroke-width='1.2'/%3E%3C/svg%3E\") right 7px center/8px no-repeat}.design-field>select option{background:#191919}.design-field input[type=number]{appearance:textfield;-moz-appearance:textfield}.design-field input::-webkit-inner-spin-button{appearance:none}.design-field__glyph{flex:none;display:grid;place-items:center;width:22px;height:100%;margin-right:-6px;color:#77736f;font-size:10px;font-weight:600;cursor:ew-resize;user-select:none;touch-action:none}.design-field__glyph:hover{color:#e9e6e1}.design-field__glyph svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:1.1}.design-field input[type=color]{flex:none;width:16px;height:16px;margin:0 -2px 0 6px;padding:0;border:0;border-radius:4px;box-shadow:inset 0 0 0 1px #ffffff26;background:none;cursor:pointer}.design-field input[type=color]::-webkit-color-swatch-wrapper{padding:0}.design-field input[type=color]::-webkit-color-swatch{border:0;border-radius:4px;box-shadow:inset 0 0 0 1px #ffffff26}.design-field input[type=color]::-moz-color-swatch{border:0;border-radius:4px}\n",t=[{property:"width",label:"Width",kind:"size",glyph:"W"},{property:"height",label:"Height",kind:"size",glyph:"H"},{property:"padding",label:"Padding",kind:"length",glyph:"M1.5 1.5h9v9h-9zM4.5 4.5h3v3h-3z",max:200},{property:"gap",label:"Gap",kind:"length",glyph:"M1.5 1.5h3v9h-3zM7.5 1.5h3v9h-3z",max:200},{property:"margin",label:"Margin",kind:"length",glyph:"M4 4h4v4H4zM1 3V1h2m6 0h2v2m0 6v2H9m-6 0H1V9",max:200},{property:"border-radius",label:"Corner radius",kind:"length",glyph:"M1.5 10.5V6A4.5 4.5 0 0 1 6 1.5h4.5",max:96},{property:"display",label:"Layout",kind:"select",values:["block","flex","grid","inline-flex","inline-grid"]},{property:"font-family",label:"Font family",kind:"text",wide:!0,placeholder:"system-ui, sans-serif"},{property:"font-size",label:"Font size",kind:"length",glyph:"M2 3V1.5h8V3M6 1.5v9m-1.5 0h3",min:1,max:160},{property:"line-height",label:"Line height",kind:"text",glyph:"M1 1.5h10M1 10.5h10M3.5 8.5 6 3l2.5 5.5",placeholder:"1.4 or 24px"},{property:"font-weight",label:"Weight",kind:"select",values:["300","400","500","600","700","800"]},{property:"text-align",label:"Alignment",kind:"select",values:["left","center","right","justify"]},{property:"color",label:"Text color",kind:"color",wide:!0},{property:"background-color",label:"Fill",kind:"color",wide:!0},{property:"border-width",label:"Border width",kind:"length",glyph:"M1 2.5h10M1 6h10M1 9.5h10",max:24},{property:"border-style",label:"Border style",kind:"select",values:["none","solid","dashed","dotted"]},{property:"border-color",label:"Border color",kind:"color"}],n=["font-family","font-size","line-height","font-weight","text-align","color"];function i(e){if(/^#[\da-f]{6}$/i.test(e))return e;if(/^#[\da-f]{3}$/i.test(e))return`#${[...e.slice(1)].map(e=>e+e).join("")}`;let t=e.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);return t?`#${t.slice(1,4).map(e=>Number(e).toString(16).padStart(2,"0")).join("")}`:"#000000"}function r(e){let t=e.match(/^rgba\(.*,\s*([\d.]+)\)$/)?.[1];return void 0===t?/^rgb\(/.test(e)?i(e):e||"transparent":Number(t)?e:"transparent"}function o(e,t){let n=getComputedStyle(t).getPropertyValue(e.property).trim();if("color"===e.kind)return r(n);if("length"===e.kind||"size"===e.kind){let t=n.match(/^(-?\d+(?:\.\d+)?)px$/);return t?String(Math.round(10*Number(t[1]))/10):"size"===e.kind?n||"auto":"0"}return n}function l(e,t){let{element:n}=t,r=document.createElement("div");r.className=`design-field design-field--${e.kind}`,r.dataset.fieldProperty=e.property,r.toggleAttribute("data-wide",!!e.wide);let l="select"===e.kind?document.createElement("select"):document.createElement("input");if(l instanceof HTMLSelectElement)for(let t of e.values??[]){let e=document.createElement("option");e.value=e.textContent=t,l.append(e)}else l.type="length"===e.kind?"number":"text",l.autocomplete="off",l.spellcheck=!1,l.placeholder=e.placeholder??"","length"===e.kind&&(l.min=String(e.min??0),l.max=String(e.max??1e3),l.setAttribute("inputmode","decimal"));if(l.dataset.property=e.property,l.setAttribute("aria-label",e.label),l.title=e.label,l.value=o(e,n),l instanceof HTMLSelectElement&&!l.value){let t=document.createElement("option");t.value=t.textContent=o(e,n),l.prepend(t),l.value=t.value}let d=()=>t.begin(l,e.property),a=()=>{t.apply(l,e.property,function(e,t){let n=t.value.trim();if("color"===e.kind){let e=document.createElement("span").style;return e.color=n,e.color?n:null}if("length"===e.kind){if(!n)return null;let t=Number(n);return!Number.isFinite(t)||t<(e.min??-200)||t>(e.max??1e3)?null:`${t}px`}return"size"===e.kind||"line-height"===e.property?/^(auto|normal|(?:\d+(?:\.\d+)?)(?:px|%|vw|vh|rem|em)?)$/.test(n)?"size"===e.kind&&/^[\d.]+$/.test(n)?`${n}px`:n:null:n}(e,l)),t.commit(l,e.property,!1)},p=()=>t.commit(l,e.property);if(l.addEventListener("focus",d),l.addEventListener("input",a),l.addEventListener("change",p),l.addEventListener("blur",p),"color"===e.kind){let t=document.createElement("input");t.type="color",t.setAttribute("aria-label",`${e.label} picker`);let n=()=>{t.value=i(l.value)};n(),t.addEventListener("pointerdown",d),t.addEventListener("focus",d),t.addEventListener("input",()=>{l.value=t.value,a()}),t.addEventListener("change",p),l.addEventListener("input",n),r.append(t)}if(e.glyph){let t=t=>{let i=l.value.trim().match(/^(-?\d*\.?\d+)([a-z%]*)$/i),r=i?i[2]:"text"===e.kind?"px":"",o=i?Number(i[1]):parseFloat(getComputedStyle(n).getPropertyValue(e.property))||0,d=Math.round(10*(o+t*("text"!==e.kind||r?1:.1)))/10;"text"!==e.kind&&(d=Math.min(e.max??1e4,Math.max(e.min??0,d))),l.value=`${d}${r}`,a()},i=document.createElement("span");i.className="design-field__glyph",i.setAttribute("aria-hidden","true"),i.title=`${e.label} · drag to adjust`,e.glyph.length>1?i.innerHTML=`<svg viewBox="0 0 12 12"><path d="${e.glyph}"/></svg>`:i.textContent=e.glyph,i.addEventListener("pointerdown",e=>{e.preventDefault(),d(),i.setPointerCapture?.(e.pointerId);let n=e.clientX,r=e=>{let i=Math.trunc((e.clientX-n)/2);i&&(n+=2*i,t(i*(e.shiftKey?10:1)))},o=()=>{i.removeEventListener("pointermove",r),p()};i.addEventListener("pointermove",r),i.addEventListener("pointerup",o,{once:!0}),i.addEventListener("pointercancel",o,{once:!0})}),l.addEventListener("keydown",e=>{"ArrowUp"!==e.key&&"ArrowDown"!==e.key||(e.preventDefault(),t(("ArrowUp"===e.key?1:-1)*(e.shiftKey?10:1)))}),r.append(i)}return l instanceof HTMLInputElement&&l.addEventListener("keydown",e=>{"Enter"===e.key&&l.blur()}),r.append(l),r}function d(e,n,i,r=[]){let o=document.createElement("section");o.className="design-section";let d=document.createElement("div");if(d.className="design-section__tools",d.append(...r),!i){let e=document.createElement("span");return e.className="design-section__title",e.textContent=n,o.append(e,d),o}let a=document.createElement("details");a.className="design-group",a.open=!e.collapsed.has(n);let p=document.createElement("summary");p.textContent=n;let s=document.createElement("div");s.className="design-grid";for(let n of i)s.append(l(t.find(e=>e.property===n),e));return a.append(p,s),a.addEventListener("toggle",()=>{a.isConnected&&(a.open?e.collapsed.delete(n):e.collapsed.add(n))}),o.append(d,a),o}function a(e,t){let{element:i,changed:o}=t,l=getComputedStyle(i),a=e=>e.some(e=>o?.has(e)),p=[...i.childNodes].some(e=>e.nodeType===Node.TEXT_NODE&&e.textContent?.trim())||/(?:^|;)\s*(?:color|font|line-height|text-align)/.test(i.getAttribute("style")??"")||a(n),s=/flex|grid/.test(l.display)||a(["gap"]),g="transparent"!==r(l.backgroundColor)||a(["background-color"]),c=["top","right","bottom","left"].some(e=>parseFloat(l.getPropertyValue(`border-${e}-width`))>0&&"none"!==l.getPropertyValue(`border-${e}-style`))||a(["border","border-width","border-style","border-color"]),u=(n,i,r,o)=>function(e,t,n){let i=document.createElement("button");return i.type="button",i.title=e,i.setAttribute("aria-label",e),i.textContent=t,i.addEventListener("click",n),i}(`Add ${n}`,"+",()=>{let n=document.createElement("input");t.begin(n,i),t.apply(n,i,r),t.commit(n,i),t.rerender(),e.querySelector(`[data-property="${o}"]`)?.focus()});e.append(d(t,"Layout",["width","height","padding",...s?["gap"]:[],"margin",...c?[]:["border-radius"],"display"])),p&&e.append(d(t,"Typography",n,[t.editText])),e.append(g?d(t,"Fill",["background-color"]):d(t,"Fill",null,[u("fill","background-color","#ffffff","background-color")]),c?d(t,"Border",["border-width","border-radius","border-style","border-color"]):d(t,"Border",null,[u("border","border","1px solid","border-width")]))}export{e as designPanelStyles,l as fieldControl,t as fields,a as renderPanel,i as toHex,o as valueFor};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const designPanelStyles = "\n/* Property controls: compact 28px fields in a two-column grid, icon or letter\n glyphs instead of a label column, and quiet section headers. */\n.design-inspector__controls > * + * { border-top:1px solid #ffffff0d; }\n.design-group { padding:0 12px 10px; }\n.design-section > .design-group { padding-bottom:12px; }\n.design-group summary { cursor:pointer; display:flex; align-items:center; gap:4px; height:36px; color:#e9e6e1; font-size:11px; font-weight:600; list-style:none; }\n.design-group summary::-webkit-details-marker { display:none; }\n.design-group summary::after { content:''; width:5px; height:5px; margin:-2px 0 0 3px; border:solid #77736f; border-width:0 1.2px 1.2px 0; rotate:45deg; opacity:0; transition:opacity .12s,rotate .2s var(--ease-smooth-out); }\n.design-group:not([open]) summary::after { rotate:-45deg; margin:0 0 0 2px; }\n.design-group summary:is(:hover,:focus-visible)::after,.design-group:not([open]) summary::after { opacity:1; }\n.design-group summary:focus-visible { outline-offset:-2px; border-radius:6px; }\n.design-section { position:relative; }\n.design-section__title { display:flex; align-items:center; height:36px; padding:0 12px; color:#898680; font-size:11px; font-weight:600; }\n.design-section__tools { position:absolute; z-index:1; top:6px; right:8px; display:flex; gap:2px; }\n.design-section__tools button { display:grid; place-items:center; width:24px; height:24px; border-radius:6px; color:#898680; font-size:16px; line-height:1; }\n.design-section__tools button:hover { background:#ffffff12; color:#f1efeb; }\n.design-text-edit { font-size:0 !important; }\n.design-text-edit::before { content:'T'; font:600 13px/1 Georgia,\"Times New Roman\",serif; }\n.design-text-edit[aria-label^=\"Finish\"] { background:#bda6ef33; color:#e6dcfb !important; }\n.design-text-edit:disabled { opacity:.35; cursor:default; }\n.design-grid { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:6px 8px; }\n.design-field { position:relative; --lead:4px; min-width:0; height:28px; display:flex; align-items:center; border-radius:6px; background:#ffffff0a; color:#898680; transition:box-shadow .12s var(--ease-smooth-out); }\n.design-field:hover { box-shadow:inset 0 0 0 1px #ffffff1c; }\n.design-field:focus-within { box-shadow:inset 0 0 0 1px #bda6ef; }\n.design-field:has([aria-invalid=\"true\"]) { box-shadow:inset 0 0 0 1px #fda29b; }\n.design-field[data-wide] { grid-column:1/-1; }\n.design-field:has(.design-field__glyph) { --lead:22px; }\n.design-field--color { --lead:26px; }\n.design-field > input:not([type=\"color\"]),.design-field > select { flex:1; box-sizing:border-box; width:100%; min-width:0; height:100%; margin:0; padding:0 8px; border:0; border-radius:6px; outline:0; box-shadow:none; background:none; color:#f1efeb; font:inherit; font-size:11px; font-variant-numeric:tabular-nums; text-overflow:ellipsis; }\n.design-field > :is(input,select):focus-visible { outline:0; }\n.design-field > select { appearance:none; padding-right:20px; cursor:pointer; background:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath d='M1.5 3 4 5.5 6.5 3' fill='none' stroke='%23898680' stroke-width='1.2'/%3E%3C/svg%3E\") right 7px center/8px no-repeat; }\n.design-field > select option { background:#191919; }\n.design-field input[type=\"number\"] { appearance:textfield; -moz-appearance:textfield; }\n.design-field input::-webkit-inner-spin-button { appearance:none; }\n.design-field__glyph { flex:none; display:grid; place-items:center; width:22px; height:100%; margin-right:-6px; color:#77736f; font-size:10px; font-weight:600; cursor:ew-resize; user-select:none; touch-action:none; }\n.design-field__glyph:hover { color:#e9e6e1; }\n.design-field__glyph svg { width:12px; height:12px; fill:none; stroke:currentColor; stroke-width:1.1; }\n.design-field input[type=\"color\"] { flex:none; width:16px; height:16px; margin:0 -2px 0 6px; padding:0; border:0; border-radius:4px; box-shadow:inset 0 0 0 1px #ffffff26; background:none; cursor:pointer; }\n.design-field input[type=\"color\"]::-webkit-color-swatch-wrapper { padding:0; }\n.design-field input[type=\"color\"]::-webkit-color-swatch { border:0; border-radius:4px; box-shadow:inset 0 0 0 1px #ffffff26; }\n.design-field input[type=\"color\"]::-moz-color-swatch { border:0; border-radius:4px; }\n";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { designPanelStyles } from "./design-panel-styles.js";
|
|
2
|
+
/** The property controls load as their own chunk, so the Design mode entry stays small. */
|
|
3
|
+
export { designPanelStyles };
|
|
4
|
+
export type Control = HTMLInputElement | HTMLSelectElement;
|
|
5
|
+
export type Field = {
|
|
6
|
+
property: string;
|
|
7
|
+
label: string;
|
|
8
|
+
kind: "color" | "length" | "size" | "select" | "text";
|
|
9
|
+
/** Short letter or icon path; numeric fields scrub when it is dragged. */
|
|
10
|
+
glyph?: string;
|
|
11
|
+
wide?: boolean;
|
|
12
|
+
values?: string[];
|
|
13
|
+
min?: number;
|
|
14
|
+
max?: number;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
};
|
|
17
|
+
export interface PanelContext {
|
|
18
|
+
element: HTMLElement;
|
|
19
|
+
changed?: ReadonlyMap<string, string>;
|
|
20
|
+
collapsed: Set<string>;
|
|
21
|
+
editText: HTMLButtonElement;
|
|
22
|
+
begin(control: Control, property: string): void;
|
|
23
|
+
apply(control: Control, property: string, value: string | null): void;
|
|
24
|
+
commit(control: Control, property: string, final?: boolean): void;
|
|
25
|
+
rerender(): void;
|
|
26
|
+
}
|
|
27
|
+
export declare const fields: Field[];
|
|
28
|
+
export declare function toHex(value: string): string;
|
|
29
|
+
export declare function valueFor(field: Field, element: HTMLElement): string;
|
|
30
|
+
/** Shared by every section, including the shared theme tokens. */
|
|
31
|
+
export declare function fieldControl(field: Field, context: Pick<PanelContext, "element" | "begin" | "apply" | "commit">): HTMLDivElement;
|
|
32
|
+
/** Render only the sections that apply to the element; empty Fill and Border offer a quiet add. */
|
|
33
|
+
export declare function renderPanel(container: HTMLElement, context: PanelContext): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Explicit bridge from a site's named CSS custom properties into Design mode. */
|
|
2
|
+
export type KomoDesignTokenType = "color" | "dimension" | "fontFamily" | "fontWeight" | "lineHeight";
|
|
3
|
+
export interface KomoDesignToken {
|
|
4
|
+
/** Stable DTCG-style token path, e.g. "color.brand.primary". */
|
|
5
|
+
path: string;
|
|
6
|
+
/** Existing CSS custom property that supplies this token. */
|
|
7
|
+
cssVariable: string;
|
|
8
|
+
/** DTCG scalar type; composite types remain unsupported. */
|
|
9
|
+
type: KomoDesignTokenType;
|
|
10
|
+
/** Explicit CSS properties that may use this token on the selected element. */
|
|
11
|
+
properties: string[];
|
|
12
|
+
/** Explicit scope used only to estimate global theme impact. */
|
|
13
|
+
impactSelector: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RegisteredDesignTokenSource {
|
|
16
|
+
root: HTMLElement;
|
|
17
|
+
tokens: KomoDesignToken[];
|
|
18
|
+
themeEdits: Map<string, {
|
|
19
|
+
before: string;
|
|
20
|
+
after: string;
|
|
21
|
+
inlineBefore: string;
|
|
22
|
+
}>;
|
|
23
|
+
elementOriginals: Map<HTMLElement, Map<string, {
|
|
24
|
+
value: string;
|
|
25
|
+
priority: string;
|
|
26
|
+
}>>;
|
|
27
|
+
elementBindings: Map<HTMLElement, Map<string, ElementTokenBinding>>;
|
|
28
|
+
previousMarker: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface ElementTokenBinding {
|
|
31
|
+
tokenPath: string;
|
|
32
|
+
initialValue: string;
|
|
33
|
+
initialPriority: string;
|
|
34
|
+
mode: "token" | "custom";
|
|
35
|
+
customValue?: string;
|
|
36
|
+
/** Token the element used before Komo changed it, from its inline style or stylesheet. */
|
|
37
|
+
declaredPath?: string;
|
|
38
|
+
}
|
|
39
|
+
/** A token reference the page itself declares for one element property. */
|
|
40
|
+
export interface DeclaredTokenReference {
|
|
41
|
+
token: KomoDesignToken;
|
|
42
|
+
origin: "inline" | "stylesheet";
|
|
43
|
+
}
|
|
44
|
+
export declare function registerDesignTokenSource(root: HTMLElement, tokens: readonly KomoDesignToken[]): () => void;
|
|
45
|
+
export declare function tokenSourceFor(target: Element | null): RegisteredDesignTokenSource | null;
|
|
46
|
+
export declare function tokenValue(source: RegisteredDesignTokenSource, token: KomoDesignToken): string;
|
|
47
|
+
export declare function tokenImpactCount(source: RegisteredDesignTokenSource, token: KomoDesignToken): number;
|
|
48
|
+
/**
|
|
49
|
+
* Preview a shared theme value. With `merge`, a live edit (typing, scrubbing, picking)
|
|
50
|
+
* extends the last undo step for the same token instead of adding one per keystroke.
|
|
51
|
+
*/
|
|
52
|
+
export declare function previewThemeToken(source: RegisteredDesignTokenSource, token: KomoDesignToken, value: string, merge?: boolean): boolean;
|
|
53
|
+
/** Return one shared token to the page's value; like Reset, it leaves no undo step. */
|
|
54
|
+
export declare function resetThemeToken(source: RegisteredDesignTokenSource, token: KomoDesignToken): void;
|
|
55
|
+
export declare function applyTokenToElement(source: RegisteredDesignTokenSource, element: HTMLElement, token: KomoDesignToken, property: string, options?: {
|
|
56
|
+
recordHistory?: boolean;
|
|
57
|
+
}): boolean;
|
|
58
|
+
/** Keep the token reference as provenance when the user types a custom override. */
|
|
59
|
+
export declare function noteElementTokenOverride(source: RegisteredDesignTokenSource, element: HTMLElement, property: string, value: string): void;
|
|
60
|
+
/** Reconcile token provenance after the style editor's undo restores a declaration. */
|
|
61
|
+
export declare function syncElementTokenBinding(source: RegisteredDesignTokenSource, element: HTMLElement, property: string): void;
|
|
62
|
+
export declare function elementTokenBindingFor(source: RegisteredDesignTokenSource, element: HTMLElement, property: string): ElementTokenBinding | null;
|
|
63
|
+
/**
|
|
64
|
+
* Report the token a property is connected to only when the winning declared
|
|
65
|
+
* value references it. Equal computed values are never treated as a token.
|
|
66
|
+
* Cross-origin sheets are skipped; cascade layers and scoping are not ranked.
|
|
67
|
+
*/
|
|
68
|
+
export declare function declaredTokenFor(source: RegisteredDesignTokenSource, element: HTMLElement, property: string, inline?: string, inlinePriority?: string): DeclaredTokenReference | null;
|
|
69
|
+
/** Drop Komo's element preview for one property and return to the page's own value. */
|
|
70
|
+
export declare function restoreElementProperty(source: RegisteredDesignTokenSource, element: HTMLElement, property: string): void;
|
|
71
|
+
export declare function compatibleTokens(source: RegisteredDesignTokenSource, property: string): KomoDesignToken[];
|
|
72
|
+
export declare function hasDesignTokenChanges(element: HTMLElement): boolean;
|
|
73
|
+
export declare function canUndoDesignToken(element: HTMLElement | null): boolean;
|
|
74
|
+
export declare function undoDesignToken(element: HTMLElement): void;
|
|
75
|
+
export declare function resetDesignTokens(element: HTMLElement): void;
|
|
76
|
+
export declare function proposedDesignTokenChanges(element: HTMLElement): string | undefined;
|
package/dist/dom.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Identity } from "./types.js";
|
|
2
|
+
import { iconMarkup as icons } from "./icon-markup.js";
|
|
3
|
+
export { icons };
|
|
4
|
+
export declare const editable: (node?: EventTarget) => boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Events komo stops at its shadow host (isolateEvents), so host shortcut
|
|
7
|
+
* libraries and modal "outside interaction" listeners never see komo's UI.
|
|
8
|
+
* Key events are stopped only while typing in a komo field.
|
|
9
|
+
*/
|
|
10
|
+
export declare const isolatedEvents: string[];
|
|
11
|
+
export declare const isolated: (event: Event, root: Node) => boolean;
|
|
12
|
+
/** Listen on document, plus komo's shadow root for the events stopped at its host. */
|
|
13
|
+
export declare function onPage<E extends Event>(node: Node, type: string, listener: (event: E) => void, options?: AddEventListenerOptions): void;
|
|
14
|
+
export declare function el<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string, text?: string): HTMLElementTagNameMap[K];
|
|
15
|
+
export declare function icon(name: keyof typeof icons): SVGSVGElement;
|
|
16
|
+
export declare function button(label: string, action: () => void, className?: string, glyph?: keyof typeof icons): HTMLButtonElement;
|
|
17
|
+
export declare const initials: (name: string) => string;
|
|
18
|
+
export declare function age(time: number): string;
|
|
19
|
+
export declare function avatar(user: Identity): HTMLSpanElement;
|
|
20
|
+
export declare function googleLogo(): HTMLImageElement;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Motion shared by the drawer menu expand and the drawer → edge sidebar hand-off. */
|
|
2
|
+
export declare const drawerExpandSpring: {
|
|
3
|
+
readonly type: "spring";
|
|
4
|
+
readonly duration: 0.4;
|
|
5
|
+
readonly bounce: 0.24;
|
|
6
|
+
};
|
|
7
|
+
export declare const drawerExpandCompress: {
|
|
8
|
+
readonly duration: 0.1;
|
|
9
|
+
readonly ease: readonly [0.4, 0, 0.2, 1];
|
|
10
|
+
};
|
|
11
|
+
export declare const drawerCollapse: {
|
|
12
|
+
readonly duration: 0.25;
|
|
13
|
+
readonly ease: readonly [0.22, 1, 0.36, 1];
|
|
14
|
+
};
|
|
15
|
+
export declare const drawerBarExit: {
|
|
16
|
+
readonly duration: 0.15;
|
|
17
|
+
};
|
|
18
|
+
export declare const drawerBarEnter: {
|
|
19
|
+
readonly duration: 0.22;
|
|
20
|
+
readonly delay: 0.08;
|
|
21
|
+
readonly ease: "easeOut";
|
|
22
|
+
};
|
|
23
|
+
export declare const drawerRowEnter: {
|
|
24
|
+
readonly type: "spring";
|
|
25
|
+
readonly duration: 0.4;
|
|
26
|
+
readonly bounce: 0.3;
|
|
27
|
+
};
|
|
28
|
+
export declare const drawerRowExit: {
|
|
29
|
+
readonly type: "spring";
|
|
30
|
+
readonly duration: 0.12;
|
|
31
|
+
readonly bounce: 0.3;
|
|
32
|
+
};
|
|
33
|
+
export declare const drawerRowEnterDelay = 0.2;
|
|
34
|
+
export declare const drawerRowStagger = 0.02;
|
|
35
|
+
/** Same squish the drawer shell uses before it springs open. */
|
|
36
|
+
export declare function compressedDrawerSize(barWidth: number, barHeight: number): {
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
};
|
|
40
|
+
/** Bottom-center anchor, matching `.morphing-menu__shell`. */
|
|
41
|
+
export declare function boxFromAnchor(anchorX: number, anchorBottom: number, width: number, height: number): {
|
|
42
|
+
left: number;
|
|
43
|
+
top: number;
|
|
44
|
+
width: number;
|
|
45
|
+
height: number;
|
|
46
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type Placement } from "./floating-drag.js";
|
|
2
|
+
export declare const EDGE_SIDEBAR_WIDTH = 380;
|
|
3
|
+
export declare const EDGE_MARGIN = 16;
|
|
4
|
+
/** How many pixels of the closed sidebar stay visible while peeking. */
|
|
5
|
+
export declare const EDGE_PEEK_SLIVER = 76;
|
|
6
|
+
/** Clearance the closed sidebar parks beyond the viewport edge. */
|
|
7
|
+
export declare const EDGE_PARK_CLEARANCE = 24;
|
|
8
|
+
/** Panel height cap; a taller viewport still parks flush against the edge. */
|
|
9
|
+
export declare const EDGE_SIDEBAR_MAX_HEIGHT = 680;
|
|
10
|
+
export declare const EDGE_SIDEBAR_MIN_WIDTH = 240;
|
|
11
|
+
export declare const EDGE_SIDEBAR_MIN_HEIGHT = 200;
|
|
12
|
+
export type EdgeResizeDir = "n" | "s" | "e" | "w" | "ne" | "nw" | "se" | "sw";
|
|
13
|
+
export interface EdgeBox {
|
|
14
|
+
left: number;
|
|
15
|
+
top: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
}
|
|
19
|
+
/** Resize from an edge or corner. Same screen-space math as panels. */
|
|
20
|
+
export declare function resizeEdgeBox(dir: EdgeResizeDir, start: EdgeBox, dx: number, dy: number, vw: number, vh: number): EdgeBox;
|
|
21
|
+
export type EdgeSide = "left" | "right";
|
|
22
|
+
export interface EdgeSidebarGeometry {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
side: EdgeSide;
|
|
28
|
+
}
|
|
29
|
+
/** The sidebar's on-screen placement, docked to the right by default. */
|
|
30
|
+
export declare function edgeSidebarPlacement(placement: Placement | undefined, width: number, height: number, vw: number, vh: number): EdgeSidebarGeometry;
|
|
31
|
+
/**
|
|
32
|
+
* Horizontal translates (style px) that park the sidebar off its docked edge
|
|
33
|
+
* and reveal it as a peek sliver. Applied on top of the placed position, so a
|
|
34
|
+
* dragged placement keeps its park direction consistent with its dock.
|
|
35
|
+
*/
|
|
36
|
+
export declare function edgeSidebarOffsets(g: EdgeSidebarGeometry, vw: number): {
|
|
37
|
+
parked: number;
|
|
38
|
+
peek: number;
|
|
39
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const DEFAULT_EMOJI: string[];
|
|
2
|
+
export type EmojiHistory = {
|
|
3
|
+
counts: Record<string, number>;
|
|
4
|
+
recent?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function rankedEmoji(history: EmojiHistory, selected?: string): string[];
|
|
7
|
+
export declare function emojiHistory(key: string): EmojiHistory;
|
|
8
|
+
export declare function recordEmoji(key: string, emoji: string): void;
|
package/dist/emoji.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isEmoji(value: unknown): value is string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface Placement {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
edgeX?: "left" | "right";
|
|
5
|
+
edgeY?: "top" | "bottom";
|
|
6
|
+
}
|
|
7
|
+
export declare function constrain(p: Placement, width: number, height: number, vw: number, vh: number): Placement;
|
|
8
|
+
export declare function settle(p: Placement, width: number, height: number, vw: number, vh: number): Placement;
|
|
9
|
+
export declare function floatingDrag(element: HTMLElement, handle: HTMLElement, save: (p: Placement) => void, signal: AbortSignal, beforeDrag?: () => void, onSettled?: () => void, enabled?: () => boolean, allowInteractiveStart?: (target: Element) => boolean): void;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ComponentType, type SVGProps } from "react";
|
|
2
|
+
export type IconName = "chevron" | "drawer" | "edit" | "trash" | "info" | "more" | "person" | "search" | "plus" | "comment" | "copy" | "pointer" | "expand" | "close" | "check" | "arrow" | "link" | "code" | "smile" | "tag" | "design";
|
|
3
|
+
export declare const components: Record<IconName, ComponentType<SVGProps<SVGSVGElement>>>;
|
|
4
|
+
export declare const iconMarkup: Record<IconName, string>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type KomoConfig } from "./config.js";
|
|
2
|
+
export type { KomoConfig } from "./config.js";
|
|
3
|
+
import type { CommentsController, CommentsOptions } from "./types.js";
|
|
4
|
+
export type * from "./types.js";
|
|
5
|
+
/** Initialize from inline public project settings. */
|
|
6
|
+
export declare function initKomo(config: KomoConfig): CommentsController;
|
|
7
|
+
/** Mount once on the client. The returned destroy() restores the host page. */
|
|
8
|
+
export declare function initComments(options: CommentsOptions): CommentsController;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as o,c as s}from"./chunk-JQVBZ2BB.js";import"./chunk-Q7WSWLMV.js";import"./chunk-Y2GRLW4Q.js";import"./chunk-7YUXYVQA.js";import"./chunk-YZP3KX4Y.js";import"./chunk-I7AUKTXE.js";export{s as initComments,o as initKomo};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./chunk-I7AUKTXE.js";var e="script,style,svg,input,textarea,select,[data-private],[data-sensitive]";function t(e){let t=document.createTreeWalker(e,NodeFilter.SHOW_TEXT),n=[];for(;t.nextNode();)n.push(t.currentNode);return n}function n(e,t,n){if(n&&e.childElementCount)for(let[e,t]of n)e.data=t;else e.textContent=t}function a(){let e=new Map,t=new Map,a=[];return{record(n){!n.reactProp&&n.before!==n.after&&(e.has(n.element)||(e.set(n.element,n.before),t.set(n.element,n.nodes)),a.push(n))},remember(t,n){e.has(t)||e.set(t,n)},original:t=>e.get(t),reconcile(t,n){e.get(t)===n&&e.delete(t)},reset(r){let i=e.get(r);void 0!==i&&n(r,i,t.get(r)),e.delete(r);for(let e=a.length-1;e>=0;e--)a[e].element===r&&a.splice(e,1)},proposal(t){let n=e.get(t),a=t.textContent??"";return void 0!==n&&n!==a?`Proposed inline text change (preview only)\n- Text: ${JSON.stringify(n)} → ${JSON.stringify(a)}\n- Source markup is unchanged; refresh resets this preview.`:void 0},restoreAll(){for(let[a,r]of e)n(a,r,t.get(a))},undo(){let t=a.pop();return t?(n(t.element,t.before,t.nodes),e.get(t.element)===t.before&&e.delete(t.element),t.element):null}}}function r(e){let t=a(),n=null,r=!1;function i(t=!1){let a=n;a&&(n=null,a.finish(t),e.onChange())}return{get element(){return n?.element??null},get busy(){return r},isEditing:e=>!!n&&n.element===e,toggle:async function(a){let l=e.selected();if(n&&n.element===l)return void i();if(!l||!e.active()||r||n)return;let s=o(l);if(s)e.status.textContent=s;else{r=!0,e.status.textContent="Loading inline text editor…",e.onChange();try{let r=await d(l,{loadReactBridge:async()=>await import("./react-props-panel-XSMDR2CY.js"),onFinish(n,a){a||n.reactProp||n.before===n.after?n.reactProp&&(e.status.textContent="React state preview · resets on refresh"):(t.record(n),e.onCommit(l),e.status.textContent="Text preview · resets on refresh")}});r?e.active()&&e.selected()===l?(n=r,a&&function(e,t,n){let a=document.caretPositionFromPoint?.(t,n),r=a?document.createRange():document.caretRangeFromPoint?.(t,n);if(a&&r&&r.setStart(a.offsetNode,a.offset),!r||!e.contains(r.startContainer))return;r.collapse(!0);let i=document.getSelection();i?.removeAllRanges(),i?.addRange(r)}(l,a.clientX,a.clientY),e.status.textContent=l.hasAttribute("data-komo-text-prop")?"React state preview · resets on refresh":"Editing text · preview only"):r.finish(!0):e.status.textContent="This text couldn't be connected to its component prop."}catch{e.status.textContent="Inline text editing is unavailable."}finally{r=!1,e.onChange()}}},finish:i,handleKey(e){if(!n||!e.composedPath().includes(n.element)||!n.handleKey(e))return!1;let t=n.element;return i("Escape"===e.key),t.blur(),!0},hasChanges:e=>void 0!==t.original(e),undo(){let n=t.undo();return e.onChange(),n},reset(n){t.reset(n),e.onChange()},reconcile(n,a){t.reconcile(n,a),e.onChange()},proposal:e=>t.proposal(e),restoreAll(){t.restoreAll()}}}function i(e){let t=r(e);return e.button.addEventListener("click",e=>{t.toggle(e)}),t}function o(n){return n.matches("input,textarea,select")?"Form fields can't be edited as text.":n.matches("script,style,svg,canvas,video,audio,iframe")?"Graphics, media, and frames can't be edited.":n.closest("[data-private],[data-sensitive]")?"This text is marked private, so it stays read-only.":n.closest("[contenteditable]")?"This text is already editable on the page.":t(n).some(t=>t.data.trim()&&!t.parentElement?.closest(e))?null:"No text here. Double-click the text itself."}function l(e){return!o(e)}function s(e){let t=e.textContent??"",n=document.getSelection(),a=n?.rangeCount?n.getRangeAt(0):null;return a&&e.contains(a.commonAncestorContainer)?a.startContainer===e?Math.min([...e.childNodes].slice(0,a.startOffset).reduce((e,t)=>e+(t.textContent?.length??0),0),t.length):a.startContainer.nodeType===Node.TEXT_NODE?Math.min(a.startOffset,t.length):t.length:-1}function c(e,t){let n=e.firstChild,a=document.getSelection();if(!n||!a)return;let r=document.createRange();r.setStart(n,Math.min(t,n.textContent?.length??0)),r.collapse(!0),a.removeAllRanges(),a.addRange(r)}async function d(a,r){if(!l(a))return null;let i=null,o=null;if(a.dataset.komoTextProp&&(i=await r.loadReactBridge(),o=i.beginReactTextEdit(a),!o))return null;let d=o?.before??(a.textContent??"").slice(0,500),u=!o&&a.childElementCount>0,g=u?t(a).map(e=>[e,e.data]):void 0,p=a.getAttribute("role"),f=a.getAttribute("aria-label"),m=a.getAttribute("aria-multiline"),h=a.getAttribute("spellcheck"),x=new AbortController,C=!1;let v=-1,b=new MutationObserver(()=>{v>=0&&c(a,v)}),T=()=>{u||(a.childElementCount&&(a.textContent=a.textContent??""),(a.textContent??"").length>500&&(a.textContent=(a.textContent??"").slice(0,500)),o&&i&&(v=s(a),i.previewReactTextEdit(a,o.propName,a.textContent??"")||(a.textContent=d)))},E=(t,n)=>{let r=t.startContainer;if(r!==t.endContainer||!(r instanceof Text)||!a.contains(r)||r.parentElement?.closest(e))return;let i=t.endOffset-t.startOffset,o=n.replace(/[\r\n]+/g," ").slice(0,Math.max(0,500-(a.textContent??"").length+i));r.replaceData(t.startOffset,i,o);let l=document.createRange();l.setStart(r,t.startOffset+o.length);let s=document.getSelection();s?.removeAllRanges(),s?.addRange(l)};a.addEventListener("beforeinput",e=>{if(v=-1,!u||"insertCompositionText"===e.inputType)return;e.preventDefault();let t=e.getTargetRanges()[0],n=e.inputType;t&&(n.startsWith("delete")||"insertText"===n||"insertReplacementText"===n)&&E(t,n.startsWith("delete")?"":e.data??e.dataTransfer?.getData("text/plain")??"")},{signal:x.signal}),a.addEventListener("input",T,{signal:x.signal}),o&&b.observe(a,{childList:!0,characterData:!0,subtree:!0}),a.addEventListener("paste",e=>{e.preventDefault();let t=e.clipboardData?.getData("text/plain")??"",n=document.getSelection();u?n?.rangeCount&&E(n.getRangeAt(0),t):(function(e,t){let n=s(e);if(n<0)return;let a=e.textContent??"",r=t.slice(0,Math.max(0,500-a.length));e.textContent=a.slice(0,n)+r+a.slice(n),c(e,n+r.length)}(a,t.replace(/[\r\n]+/g," ").slice(0,500)),T())},{signal:x.signal}),a.addEventListener("drop",e=>e.preventDefault(),{signal:x.signal}),a.setAttribute("contenteditable","true"),a.setAttribute("role","textbox"),a.setAttribute("aria-label","Inline text preview"),a.setAttribute("aria-multiline","false"),a.dataset.komoInlineEditing="true",a.spellcheck=!1,a.focus({preventScroll:!0});let R=document.getSelection(),y=document.createRange();return y.selectNodeContents(a),y.collapse(!1),R?.removeAllRanges(),R?.addRange(y),{element:a,finish(e=!1){if(C)return;C=!0,x.abort(),b.disconnect(),!u&&a.childElementCount&&(a.textContent=a.textContent??"");let t=(a.textContent??"").slice(0,500);(function(){a.removeAttribute("contenteditable"),a.removeAttribute("data-komo-inline-editing");for(let[e,t]of[["role",p],["aria-label",f],["aria-multiline",m],["spellcheck",h]])null===t?a.removeAttribute(e):a.setAttribute(e,t)})(),e?(o&&i&&i.cancelReactTextEdit(a,o.propName,d),n(a,d,g)):o&&i&&i.finishReactTextEdit(a,o.propName,d,t),r.onFinish({element:a,before:d,after:t,nodes:g,...o?{reactProp:o.propName}:{}},e)},handleKey:e=>!e.isComposing&&(("Enter"===e.key||"Escape"===e.key)&&(e.preventDefault(),e.stopImmediatePropagation(),!0))}}export{i as bindInlineTextTools,l as canEditText,r as createInlineTextTools,a as createTextPreviewHistory,d as startInlineTextEditor,o as textEditBlocker};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface ReactTextBridge {
|
|
2
|
+
beginReactTextEdit(element: HTMLElement): {
|
|
3
|
+
propName: string;
|
|
4
|
+
before: string;
|
|
5
|
+
} | null;
|
|
6
|
+
previewReactTextEdit(element: HTMLElement, propName: string, value: string): boolean;
|
|
7
|
+
finishReactTextEdit(element: HTMLElement, propName: string, before: string, after: string): void;
|
|
8
|
+
cancelReactTextEdit(element: HTMLElement, propName: string, before: string): void;
|
|
9
|
+
}
|
|
10
|
+
export interface InlineTextEditResult {
|
|
11
|
+
element: HTMLElement;
|
|
12
|
+
before: string;
|
|
13
|
+
after: string;
|
|
14
|
+
reactProp?: string;
|
|
15
|
+
/** Text node values before the edit, for elements with nested markup. */
|
|
16
|
+
nodes?: TextSnapshot;
|
|
17
|
+
}
|
|
18
|
+
export type TextSnapshot = Array<[Text, string]>;
|
|
19
|
+
export interface InlineTextEditor {
|
|
20
|
+
readonly element: HTMLElement;
|
|
21
|
+
finish(cancel?: boolean): void;
|
|
22
|
+
handleKey(event: KeyboardEvent): boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface InlineTextEditorOptions {
|
|
25
|
+
loadReactBridge(): Promise<ReactTextBridge>;
|
|
26
|
+
onFinish(result: InlineTextEditResult, cancel: boolean): void;
|
|
27
|
+
}
|
|
28
|
+
export interface InlineTextToolsOptions {
|
|
29
|
+
button: HTMLButtonElement;
|
|
30
|
+
status: HTMLElement;
|
|
31
|
+
selected(): HTMLElement | null;
|
|
32
|
+
active(): boolean;
|
|
33
|
+
onChange(): void;
|
|
34
|
+
onCommit(element: HTMLElement): void;
|
|
35
|
+
}
|
|
36
|
+
export interface InlineTextTools {
|
|
37
|
+
readonly element: HTMLElement | null;
|
|
38
|
+
readonly busy: boolean;
|
|
39
|
+
isEditing(element: HTMLElement | null): boolean;
|
|
40
|
+
/** Start or finish editing; a point inside the text places the caret there. */
|
|
41
|
+
toggle(point?: {
|
|
42
|
+
clientX: number;
|
|
43
|
+
clientY: number;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
finish(cancel?: boolean): void;
|
|
46
|
+
handleKey(event: KeyboardEvent): boolean;
|
|
47
|
+
hasChanges(element: HTMLElement): boolean;
|
|
48
|
+
undo(): HTMLElement | null;
|
|
49
|
+
reset(element: HTMLElement): void;
|
|
50
|
+
reconcile(element: HTMLElement, text: string): void;
|
|
51
|
+
proposal(element: HTMLElement): string | undefined;
|
|
52
|
+
restoreAll(): void;
|
|
53
|
+
}
|
|
54
|
+
export interface TextPreviewHistory {
|
|
55
|
+
record(result: InlineTextEditResult): void;
|
|
56
|
+
remember(element: HTMLElement, before: string): void;
|
|
57
|
+
original(element: HTMLElement): string | undefined;
|
|
58
|
+
reconcile(element: HTMLElement, text: string): void;
|
|
59
|
+
reset(element: HTMLElement): void;
|
|
60
|
+
proposal(element: HTMLElement): string | undefined;
|
|
61
|
+
restoreAll(): void;
|
|
62
|
+
undo(): HTMLElement | null;
|
|
63
|
+
}
|
|
64
|
+
export declare function createTextPreviewHistory(): TextPreviewHistory;
|
|
65
|
+
export declare function createInlineTextTools(options: InlineTextToolsOptions): InlineTextTools;
|
|
66
|
+
export declare function bindInlineTextTools(options: InlineTextToolsOptions): InlineTextTools;
|
|
67
|
+
/** Why an element's text can't be edited inline, or null when it can. */
|
|
68
|
+
export declare function textEditBlocker(element: HTMLElement): string | null;
|
|
69
|
+
export declare function canEditText(element: HTMLElement): boolean;
|
|
70
|
+
export declare function startInlineTextEditor(element: HTMLElement, options: InlineTextEditorOptions): Promise<InlineTextEditor | null>;
|