@hazem3500/palette 0.9.107 → 0.9.109
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/NODE.md +32 -30
- package/README.md +36 -28
- package/cli/agent.mjs +87 -64
- package/cli/config.mjs +17 -1
- package/cli/design-edit.mjs +9 -7
- package/cli/index.mjs +18 -20
- package/cli/snapshots.mjs +3 -3
- package/cli/workflow.mjs +15 -7
- package/dist/{accent-picker-TTIZ65XF.js → accent-picker-PPVPURA7.js} +1 -1
- package/dist/account-tokens-LBRVZAEJ.js +1 -0
- package/dist/adapters/css-variables.js +1 -1
- package/dist/adapters/tailwind.js +1 -1
- package/dist/chunk-2FX2JEMO.js +1 -0
- package/dist/chunk-4HBBEVFK.js +1 -0
- package/dist/chunk-5HZI7HRR.js +1 -0
- package/dist/chunk-DU7H4TEX.js +1 -0
- package/dist/chunk-FGZXQUAD.js +1 -0
- package/dist/{chunk-AYGLN3MI.js → chunk-HLXSRXTK.js} +1 -1
- package/dist/{chunk-DZRM3YUQ.js → chunk-J47R52WX.js} +1 -1
- package/dist/chunk-KELFDOEC.js +1 -0
- package/dist/{chunk-2J3IID4N.js → chunk-KLPQTFVH.js} +1 -1
- package/dist/chunk-ONUORDYE.js +1 -0
- package/dist/chunk-PF4NYFZK.js +1 -0
- package/dist/chunk-S6NEYT36.js +1 -0
- package/dist/chunk-VX6XCU4E.js +1 -0
- package/dist/chunk-ZIEPA67C.js +1 -0
- package/dist/color-editor-QPJQD36F.js +1 -0
- package/dist/design-comment-BF2KGPWU.js +1 -0
- package/dist/{design-export-BNNHI4JP.js → design-export-Y2GU3KER.js} +1 -1
- package/dist/design-geometry-HJLEXLPO.js +1 -0
- package/dist/design-mode-styles.d.ts +1 -1
- package/dist/design-mode.js +1 -1
- package/dist/design-panel-ZQS4WQCI.js +1 -0
- package/dist/design-panel-styles.d.ts +1 -1
- package/dist/design-popup.d.ts +1 -1
- package/dist/design-system.d.ts +5 -4
- package/dist/{field-controls-4ROTPXMO.js → field-controls-4AIIXPNQ.js} +1 -1
- package/dist/{frame-iframe-WBEP3R6S.js → frame-iframe-PYLYMCOK.js} +1 -1
- package/dist/frame-size-TF6SIUFO.js +1 -0
- package/dist/frame-target.d.ts +5 -2
- package/dist/host-motion.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/inline-text-editor-MK6FHDAM.js +1 -0
- package/dist/live-colors-D426RBEC.js +1 -0
- package/dist/live-colors.d.ts +1 -1
- package/dist/node.mjs +103 -75
- package/dist/onboarding-YZ2MJBS5.js +1 -0
- package/dist/{pin-groups-YAYFPJYA.js → pin-groups-GF53RTHP.js} +1 -1
- package/dist/{pin-move-PG54WWPU.js → pin-move-G6EWHLDO.js} +1 -1
- package/dist/public-env.d.ts +49 -11
- package/dist/react-props-panel-ZSKQ44GS.js +1 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +1 -1
- package/dist/select-menu-OZVNHZ73.js +1 -0
- package/dist/server.js +80 -57
- package/dist/setup.js +1 -1
- package/dist/shell-mode-PLV6F474.js +1 -0
- package/dist/shell-session.d.ts +5 -3
- package/dist/shell.d.ts +1 -1
- package/dist/shell.js +1 -1
- package/dist/shortcut-help-DIMOT2ZK.js +1 -0
- package/dist/snapshot-3PSQKXUV.js +1 -0
- package/dist/snapshot.d.ts +1 -1
- package/dist/source-info.d.ts +1 -1
- package/dist/storage-keys.d.ts +5 -0
- package/dist/tag-editor-B3I7WD4N.js +1 -0
- package/dist/thread-snapshot-ML2RZVID.js +1 -0
- package/dist/token-custom-CASAQWYW.js +1 -0
- package/dist/token-page-NIB5HAVS.js +1 -0
- package/dist/token-picker-AJ5E5IN5.js +1 -0
- package/dist/{toolbar-runtime-QCZONSWE.js → toolbar-runtime-TZWY2KH3.js} +1 -1
- package/dist/typed-custom.d.ts +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/server/account-page.ts +6 -6
- package/server/iap.ts +2 -2
- package/server/index.ts +30 -24
- package/server/project-management.ts +5 -5
- package/server/proxy-auth.ts +17 -16
- package/server/public-env.ts +67 -11
- package/server/setup-client.txt +173 -173
- package/server/setup-page.ts +1 -1
- package/server/tokens.ts +9 -6
- package/server/webhooks.ts +9 -5
- package/src/types.ts +1 -1
- package/dist/account-tokens-PINQNSNE.js +0 -1
- package/dist/chunk-4KEVPMJJ.js +0 -1
- package/dist/chunk-4XQD75A2.js +0 -1
- package/dist/chunk-57MG3M5P.js +0 -1
- package/dist/chunk-5OVDW2RU.js +0 -1
- package/dist/chunk-6HM4JQLV.js +0 -1
- package/dist/chunk-DLC3CRFV.js +0 -1
- package/dist/chunk-DVYSFT6O.js +0 -1
- package/dist/chunk-FD4GACV2.js +0 -1
- package/dist/chunk-IQOPM3JF.js +0 -1
- package/dist/chunk-UEZCLURX.js +0 -1
- package/dist/color-editor-ATWWSENS.js +0 -1
- package/dist/design-comment-RXUCDTYA.js +0 -1
- package/dist/design-geometry-DPMHGQEK.js +0 -1
- package/dist/design-panel-HTN6LR3V.js +0 -1
- package/dist/frame-size-MRCN6XYD.js +0 -1
- package/dist/inline-text-editor-AMFRKW5Z.js +0 -1
- package/dist/live-colors-GWOVVQSO.js +0 -1
- package/dist/onboarding-BVTCFEHL.js +0 -1
- package/dist/react-props-panel-4XO3NSX3.js +0 -1
- package/dist/select-menu-QAYV7NKJ.js +0 -1
- package/dist/shell-mode-SUYLWDWW.js +0 -1
- package/dist/shortcut-help-XRDNX7MZ.js +0 -1
- package/dist/snapshot-V264ZMQG.js +0 -1
- package/dist/tag-editor-MMAMOEI4.js +0 -1
- package/dist/thread-snapshot-HLTNHS4N.js +0 -1
- package/dist/token-custom-UCA6CBOV.js +0 -1
- package/dist/token-page-PGPWPUKU.js +0 -1
- package/dist/token-picker-WMWUKLKJ.js +0 -1
package/cli/agent.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import { homedir } from "node:os";
|
|
|
14
14
|
import { createHash, randomBytes } from "node:crypto";
|
|
15
15
|
import { createServer } from "node:http";
|
|
16
16
|
import { spawn } from "node:child_process";
|
|
17
|
-
import { branchName } from "./config.mjs";
|
|
17
|
+
import { branchName, setting } from "./config.mjs";
|
|
18
18
|
import { agentWorkflow, agentPrompt } from "../dist/agent-prompt.js";
|
|
19
19
|
import { designEditFromComment, formatDesignEdit } from "./design-edit.mjs";
|
|
20
20
|
|
|
@@ -26,7 +26,7 @@ const actions = {
|
|
|
26
26
|
untag: "Remove a group tag: untag THREAD_ID TAG",
|
|
27
27
|
get: "Read one complete thread: get THREAD_ID; --snapshots also saves its element snapshots as files",
|
|
28
28
|
prompt: "Export open feedback as Markdown; --page /path, --json, --snapshots to save element snapshots and list their files",
|
|
29
|
-
snapshots: "Save a thread's element snapshots as files: snapshots THREAD_ID [--out DIR] (default .komo/snapshots)",
|
|
29
|
+
snapshots: "Save a thread's element snapshots as files: snapshots THREAD_ID [--out DIR] (default .palette/snapshots, or .komo/snapshots in an older project)",
|
|
30
30
|
create: "Create a thread: --page /path --anchor-file FILE --body TEXT",
|
|
31
31
|
reply: "Reply to a thread: reply THREAD_ID --body TEXT",
|
|
32
32
|
resolve: "Resolve a thread: resolve THREAD_ID",
|
|
@@ -70,10 +70,10 @@ ${Object.entries(actions)
|
|
|
70
70
|
.map(([name, description]) => ` ${name}: ${description}`)
|
|
71
71
|
.join("\n")}
|
|
72
72
|
|
|
73
|
-
Settings: .komo/project.json (searched upward), or --project KEY.
|
|
73
|
+
Settings: .palette/project.json, or .komo/project.json from before the rename (searched upward), or --project KEY.
|
|
74
74
|
Overrides: --endpoint URL --origin SITE_URL --repo OWNER/REPO --branch NAME
|
|
75
75
|
Bodies: --body TEXT, --body-file FILE, or --body-file - for stdin.
|
|
76
|
-
Credentials: KOMO_TOKEN, then a saved access token, then a Google login session. Never commit tokens.
|
|
76
|
+
Credentials: PALETTE_TOKEN (or the older KOMO_TOKEN), then a saved access token, then a Google login session. Never commit tokens.
|
|
77
77
|
Create access tokens at /account on your Palette server; pass one with: printf %s "$TOKEN" | palette login --token
|
|
78
78
|
Results are JSON except prompt (Markdown unless --json). Errors are JSON on stderr.
|
|
79
79
|
Design mode messages also carry designEdit: a parsed Palette DesignEdit v1 record.
|
|
@@ -143,39 +143,43 @@ function safeUrl(value, originOnly = false) {
|
|
|
143
143
|
async function configuration(flags, cwd, env) {
|
|
144
144
|
let directory = cwd,
|
|
145
145
|
settings = {},
|
|
146
|
-
root = cwd
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
146
|
+
root = cwd,
|
|
147
|
+
settingsDir = ".palette";
|
|
148
|
+
search: while (true) {
|
|
149
|
+
// .komo/ is where a project set up before the rename keeps its settings.
|
|
150
|
+
for (const dir of [".palette", ".komo"])
|
|
151
|
+
try {
|
|
152
|
+
settings = JSON.parse(
|
|
153
|
+
await readFile(join(directory, dir, "project.json"), "utf8")
|
|
154
|
+
);
|
|
155
|
+
root = directory;
|
|
156
|
+
settingsDir = dir;
|
|
157
|
+
break search;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (error.code !== "ENOENT") throw error;
|
|
160
|
+
}
|
|
157
161
|
if (dirname(directory) === directory) break;
|
|
158
162
|
directory = dirname(directory);
|
|
159
163
|
}
|
|
160
|
-
const project = flags.project || env
|
|
164
|
+
const project = flags.project || setting(env, "PROJECT") || settings.project;
|
|
161
165
|
if (!project)
|
|
162
166
|
throw Error("Run palette init in this repository, or pass --project KEY.");
|
|
163
167
|
const endpoint = safeUrl(
|
|
164
168
|
flags.endpoint ||
|
|
165
|
-
env
|
|
169
|
+
setting(env, "ENDPOINT") ||
|
|
166
170
|
settings.endpoint ||
|
|
167
171
|
"https://komo.offbr.co"
|
|
168
172
|
);
|
|
169
173
|
const origin = safeUrl(
|
|
170
174
|
flags.origin ||
|
|
171
|
-
env
|
|
175
|
+
setting(env, "ORIGIN") ||
|
|
172
176
|
settings.origin ||
|
|
173
177
|
"http://localhost:3000",
|
|
174
178
|
true
|
|
175
179
|
);
|
|
176
180
|
const branch =
|
|
177
181
|
flags.branch ||
|
|
178
|
-
env
|
|
182
|
+
setting(env, "BRANCH") ||
|
|
179
183
|
(settings.scope === "branch" ? branchName(env, directory) : "shared");
|
|
180
184
|
if (!branch) throw Error("Cannot detect branch. Pass --branch NAME.");
|
|
181
185
|
return {
|
|
@@ -183,42 +187,55 @@ async function configuration(flags, cwd, env) {
|
|
|
183
187
|
endpoint,
|
|
184
188
|
origin,
|
|
185
189
|
branch,
|
|
186
|
-
repo: flags.repo || env
|
|
190
|
+
repo: flags.repo || setting(env, "REPO") || settings.repo || project,
|
|
187
191
|
root,
|
|
192
|
+
settingsDir,
|
|
188
193
|
};
|
|
189
194
|
}
|
|
190
|
-
|
|
195
|
+
// Credentials are saved under ~/.config/palette (or PALETTE_CONFIG_HOME). Ones
|
|
196
|
+
// saved before the rename, under ~/.config/komo, are still read; logout removes both.
|
|
197
|
+
function credentialFiles(env, name) {
|
|
198
|
+
const home = setting(env, "CONFIG_HOME");
|
|
199
|
+
return (home ? [home] : [join(homedir(), ".config", "palette"), join(homedir(), ".config", "komo")])
|
|
200
|
+
.map((directory) => join(directory, name));
|
|
201
|
+
}
|
|
202
|
+
function credentialPaths(config, env) {
|
|
191
203
|
const key = createHash("sha256")
|
|
192
204
|
.update(`${config.endpoint}\n${config.project}`)
|
|
193
205
|
.digest("hex");
|
|
194
|
-
return
|
|
195
|
-
env.KOMO_CONFIG_HOME || join(homedir(), ".config", "komo"),
|
|
196
|
-
`${key}.json`
|
|
197
|
-
);
|
|
206
|
+
return credentialFiles(env, `${key}.json`);
|
|
198
207
|
}
|
|
199
|
-
const PERSONAL_TOKEN = /^
|
|
208
|
+
const PERSONAL_TOKEN = /^(?:palette|komo)_pat_[a-z0-9]{12}_[A-Za-z0-9_-]{43}$/;
|
|
209
|
+
const isPersonalToken = (token) => /^(?:palette|komo)_pat_/.test(token ?? "");
|
|
200
210
|
// A personal access token works for every project on one server, so it is
|
|
201
211
|
// stored per endpoint, beside the per-project login sessions.
|
|
202
|
-
function
|
|
212
|
+
function personalTokenPaths(config, env) {
|
|
203
213
|
const key = createHash("sha256").update(config.endpoint).digest("hex");
|
|
204
|
-
return
|
|
205
|
-
env.KOMO_CONFIG_HOME || join(homedir(), ".config", "komo"),
|
|
206
|
-
`pat-${key}.json`
|
|
207
|
-
);
|
|
214
|
+
return credentialFiles(env, `pat-${key}.json`);
|
|
208
215
|
}
|
|
209
|
-
async function readSaved(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
216
|
+
async function readSaved(paths) {
|
|
217
|
+
for (const path of paths)
|
|
218
|
+
try {
|
|
219
|
+
return JSON.parse(await readFile(path, "utf8")).token || null;
|
|
220
|
+
} catch (error) {
|
|
221
|
+
if (error.code !== "ENOENT") throw error;
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
async function readEach(paths) {
|
|
226
|
+
const tokens = [];
|
|
227
|
+
for (const path of paths) {
|
|
228
|
+
const token = await readSaved([path]);
|
|
229
|
+
if (token) tokens.push(token);
|
|
215
230
|
}
|
|
231
|
+
return tokens;
|
|
216
232
|
}
|
|
217
|
-
// Precedence: KOMO_TOKEN, then a saved access token, then a login session.
|
|
218
|
-
async function readCredentials(
|
|
219
|
-
const saved = { session: await readSaved(
|
|
220
|
-
const
|
|
221
|
-
|
|
233
|
+
// Precedence: PALETTE_TOKEN (or KOMO_TOKEN), then a saved access token, then a login session.
|
|
234
|
+
async function readCredentials(sessionPaths, patPaths, env) {
|
|
235
|
+
const saved = { session: await readSaved(sessionPaths), pat: await readSaved(patPaths) };
|
|
236
|
+
const variable = setting(env, "TOKEN");
|
|
237
|
+
const [source, token] = variable
|
|
238
|
+
? ["env", variable]
|
|
222
239
|
: saved.pat
|
|
223
240
|
? ["token", saved.pat]
|
|
224
241
|
: saved.session
|
|
@@ -238,7 +255,7 @@ async function readTokenFromStdin() {
|
|
|
238
255
|
}
|
|
239
256
|
const token = Buffer.concat(chunks).toString("utf8").trim();
|
|
240
257
|
if (!PERSONAL_TOKEN.test(token))
|
|
241
|
-
throw Error("Expected a Palette access token (
|
|
258
|
+
throw Error("Expected a Palette access token (palette_pat_…) on stdin.");
|
|
242
259
|
return token;
|
|
243
260
|
}
|
|
244
261
|
async function saveToken(path, token) {
|
|
@@ -280,7 +297,7 @@ export function apiClient(config, token) {
|
|
|
280
297
|
if (!response.ok) {
|
|
281
298
|
const error = Error(
|
|
282
299
|
response.status === 401
|
|
283
|
-
? token
|
|
300
|
+
? isPersonalToken(token)
|
|
284
301
|
? "Access token invalid, expired, or revoked. Create a new one at /account."
|
|
285
302
|
: "Session missing or expired. Run palette login."
|
|
286
303
|
: result.error || `Request failed (${response.status}).`
|
|
@@ -371,7 +388,7 @@ async function login(config, path, flags) {
|
|
|
371
388
|
const safe = (value) => JSON.stringify(value).replace(/</g, "\\u003c");
|
|
372
389
|
return send(
|
|
373
390
|
200,
|
|
374
|
-
`<!doctype html><meta charset="utf-8"><title>Sign in to Palette</title><style>body{background:#191919;color:#eee;font:16px system-ui;max-width:420px;margin:18vh auto;padding:24px}button{font:inherit;padding:14px 20px;border:0;border-radius:12px;background:#c8b5f4}p{line-height:1.5;color:#aaa}</style><h1>Connect your agent</h1><p id="project"></p><p>The CLI can read and update comments as you. Your session stays on this computer.</p><button>Continue with Google</button><p id="status"></p><script nonce="${nonce}">document.querySelector('#project').textContent=${safe(config.project)};let popup;document.querySelector('button').onclick=()=>{popup=window.open(${safe(authUrl)},'
|
|
391
|
+
`<!doctype html><meta charset="utf-8"><title>Sign in to Palette</title><style>body{background:#191919;color:#eee;font:16px system-ui;max-width:420px;margin:18vh auto;padding:24px}button{font:inherit;padding:14px 20px;border:0;border-radius:12px;background:#c8b5f4}p{line-height:1.5;color:#aaa}</style><h1>Connect your agent</h1><p id="project"></p><p>The CLI can read and update comments as you. Your session stays on this computer.</p><button>Continue with Google</button><p id="status"></p><script nonce="${nonce}">document.querySelector('#project').textContent=${safe(config.project)};let popup;document.querySelector('button').onclick=()=>{popup=window.open(${safe(authUrl)},'palette-cli-auth','width=500,height=700')};window.addEventListener('message',async e=>{if(e.origin!==${safe(new URL(config.endpoint).origin)}||e.source!==popup||e.data?.type!=='branch-comments:auth')return;const response=await fetch(location.pathname,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token:e.data.token})});document.querySelector('#status').textContent=await response.text();if(response.ok){document.querySelector('button').disabled=true;setTimeout(()=>window.close(),400)}});</script>`,
|
|
375
392
|
"text/html"
|
|
376
393
|
);
|
|
377
394
|
}
|
|
@@ -452,7 +469,7 @@ export async function runAgent(
|
|
|
452
469
|
args,
|
|
453
470
|
{ cwd = process.cwd(), env = process.env } = {}
|
|
454
471
|
) {
|
|
455
|
-
if (args.some((arg) =>
|
|
472
|
+
if (args.some((arg) => /(?:palette|komo)_pat_/.test(arg) || arg.startsWith("--token=")))
|
|
456
473
|
throw Error(
|
|
457
474
|
"Never pass a token as an argument: it would appear in shell history and process lists. Pipe it on stdin: printf %s \"$TOKEN\" | palette login --token"
|
|
458
475
|
);
|
|
@@ -484,13 +501,13 @@ export async function runAgent(
|
|
|
484
501
|
{
|
|
485
502
|
version: 1,
|
|
486
503
|
commands: actions,
|
|
487
|
-
auth: "KOMO_TOKEN, palette login --token (stdin), or palette login",
|
|
504
|
+
auth: "PALETTE_TOKEN (or KOMO_TOKEN), palette login --token (stdin), or palette login",
|
|
488
505
|
output: "JSON; prompt is Markdown unless --json",
|
|
489
506
|
designEdit:
|
|
490
|
-
"Design mode messages carry designEdit (Palette DesignEdit v1); prompt prints it as a json
|
|
507
|
+
"Design mode messages carry designEdit (Palette DesignEdit v1); prompt prints it as a json palette-design-edit block",
|
|
491
508
|
snapshots:
|
|
492
|
-
"Threads may carry snapshot { image?, html? } URLs. palette comments snapshots ID (or get/prompt --snapshots) saves them under --out DIR, default .komo/snapshots, and reports the file paths",
|
|
493
|
-
context: ".komo/project.json or --project KEY",
|
|
509
|
+
"Threads may carry snapshot { image?, html? } URLs. palette comments snapshots ID (or get/prompt --snapshots) saves them under --out DIR, default .palette/snapshots (.komo/snapshots in an older project), and reports the file paths",
|
|
510
|
+
context: ".palette/project.json (or .komo/project.json) or --project KEY",
|
|
494
511
|
overrides: ["--endpoint", "--origin", "--repo", "--branch"],
|
|
495
512
|
body: ["--body", "--body-file", "--body-file -"],
|
|
496
513
|
setup: "palette agents setup",
|
|
@@ -518,9 +535,11 @@ export async function runAgent(
|
|
|
518
535
|
if (positional.length > expected)
|
|
519
536
|
throw Error("Unexpected positional arguments. Run palette --help.");
|
|
520
537
|
const config = await configuration(flags, cwd, env),
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const
|
|
538
|
+
paths = credentialPaths(config, env),
|
|
539
|
+
path = paths[0];
|
|
540
|
+
const patPaths = personalTokenPaths(config, env),
|
|
541
|
+
patPath = patPaths[0];
|
|
542
|
+
const { source, token, saved } = await readCredentials(paths, patPaths, env),
|
|
524
543
|
request = apiClient(config, token);
|
|
525
544
|
if (command !== "logout" && config.repo === config.project) {
|
|
526
545
|
const metadata = await request("config");
|
|
@@ -528,8 +547,8 @@ export async function runAgent(
|
|
|
528
547
|
}
|
|
529
548
|
if (flags.snapshots && !(command === "comments" && ["get", "prompt"].includes(action)))
|
|
530
549
|
throw Error("Use --snapshots with palette comments get or prompt.");
|
|
531
|
-
// Downloaded snapshots go under --out, or
|
|
532
|
-
const snapshotDirectory = () => (flags.out ? resolve(cwd, flags.out) : join(config.root ?? cwd, "
|
|
550
|
+
// Downloaded snapshots go under --out, or snapshots/ in the project settings directory.
|
|
551
|
+
const snapshotDirectory = () => (flags.out ? resolve(cwd, flags.out) : join(config.root ?? cwd, config.settingsDir, "snapshots"));
|
|
533
552
|
const snapshotDownload = (thread) => saveSnapshots(config, token, thread, snapshotDirectory(), !flags.out);
|
|
534
553
|
let data;
|
|
535
554
|
if (command === "login" && flags.token) {
|
|
@@ -543,7 +562,7 @@ export async function runAgent(
|
|
|
543
562
|
else {
|
|
544
563
|
if (!token)
|
|
545
564
|
throw Error(
|
|
546
|
-
"Not signed in. Run palette login, pipe a token to palette login --token, or set
|
|
565
|
+
"Not signed in. Run palette login, pipe a token to palette login --token, or set PALETTE_TOKEN."
|
|
547
566
|
);
|
|
548
567
|
if (command === "project")
|
|
549
568
|
data = await runProject(action, flags, request, config, cwd);
|
|
@@ -551,19 +570,23 @@ export async function runAgent(
|
|
|
551
570
|
else if (command === "logout") {
|
|
552
571
|
// Only login sessions are revoked here. Access tokens are revoked on
|
|
553
572
|
// the account page, so logout never destroys a token other jobs share.
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
573
|
+
// Every distinct session goes: the environment's, and those saved under
|
|
574
|
+
// ~/.config/palette and, from before the rename, ~/.config/komo.
|
|
575
|
+
const variable = setting(env, "TOKEN");
|
|
576
|
+
const sessions = new Set([
|
|
577
|
+
...(variable && !isPersonalToken(variable) ? [variable] : []),
|
|
578
|
+
...(await readEach(paths)),
|
|
579
|
+
]);
|
|
580
|
+
for (const session of sessions)
|
|
558
581
|
try {
|
|
559
582
|
await apiClient(config, session)("me", "DELETE");
|
|
560
583
|
} catch (error) {
|
|
561
584
|
if (error.status !== 401 && error.status !== 404) throw error;
|
|
562
585
|
}
|
|
563
|
-
await rm(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
586
|
+
for (const file of [...paths, ...patPaths]) await rm(file, { force: true });
|
|
587
|
+
for (const name of ["PALETTE_TOKEN", "KOMO_TOKEN"])
|
|
588
|
+
if (env[name])
|
|
589
|
+
console.error(`${name} is still set in this environment; unset it to stop using it.`);
|
|
567
590
|
data = { signedOut: true };
|
|
568
591
|
} else if (["list", "get", "prompt", "snapshots"].includes(action)) {
|
|
569
592
|
let threads = (
|
package/cli/config.mjs
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
/** The PALETTE_ setting `name`, or its older KOMO_ name. */
|
|
6
|
+
export const setting = (env, name) => env[`PALETTE_${name}`] || env[`KOMO_${name}`] || undefined;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Where a project keeps its settings and generated client module. New projects
|
|
10
|
+
* use .palette/ and palette.config.js. A project set up before the rename keeps
|
|
11
|
+
* .komo/ and komo.config.js, so its imports and ignored files stay valid.
|
|
12
|
+
*/
|
|
13
|
+
export function projectLayout(root) {
|
|
14
|
+
return !existsSync(join(root, ".palette")) && existsSync(join(root, ".komo"))
|
|
15
|
+
? { dir: ".komo", module: "komo.config.js" }
|
|
16
|
+
: { dir: ".palette", module: "palette.config.js" };
|
|
17
|
+
}
|
|
2
18
|
|
|
3
19
|
export function gitValue(args, cwd) {
|
|
4
20
|
try {
|
|
@@ -19,7 +35,7 @@ export function repository(remote) {
|
|
|
19
35
|
}
|
|
20
36
|
export function branchName(env, cwd) {
|
|
21
37
|
return (
|
|
22
|
-
env
|
|
38
|
+
setting(env, "BRANCH") ||
|
|
23
39
|
env.CF_PAGES_BRANCH ||
|
|
24
40
|
env.WORKERS_CI_BRANCH ||
|
|
25
41
|
env.VERCEL_GIT_COMMIT_REF ||
|
package/cli/design-edit.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// CLI only: reads the structured DesignEdit (v1) out of a Design mode comment.
|
|
2
|
-
// Comments store proposals as text. A fenced `
|
|
2
|
+
// Comments store proposals as text. A fenced `palette-design-edit` (or older
|
|
3
|
+
// `komo-design-edit`) JSON block wins
|
|
3
4
|
// when present and valid; otherwise the edit is derived from the "Proposed …
|
|
4
5
|
// changes (preview only)" sections the browser writes, so old comments work too.
|
|
5
6
|
|
|
@@ -7,7 +8,7 @@
|
|
|
7
8
|
export const DESIGN_EDIT_LIMIT = 16000;
|
|
8
9
|
const BODY_LIMIT = 64000;
|
|
9
10
|
const MAX_CHANGES = 100;
|
|
10
|
-
const FENCE = /```(?:json[ \t]+)?komo-design-edit[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*```/;
|
|
11
|
+
const FENCE = /```(?:json[ \t]+)?(?:palette|komo)-design-edit[ \t]*\r?\n([\s\S]*?)\r?\n[ \t]*```/;
|
|
11
12
|
const HEADER = /^Proposed (.+?) changes? \(preview only\)$/;
|
|
12
13
|
|
|
13
14
|
const isObject = (value) =>
|
|
@@ -92,13 +93,14 @@ function place(value, to = false) {
|
|
|
92
93
|
|
|
93
94
|
/**
|
|
94
95
|
* A clean copy of `value` if it is a valid DesignEdit v1, else null. Unknown
|
|
95
|
-
* fields are dropped; one invalid change rejects the whole edit.
|
|
96
|
+
* fields are dropped; one invalid change rejects the whole edit. Records from
|
|
97
|
+
* older releases are marked `komo: "design-edit"`; the copy says `palette`.
|
|
96
98
|
*/
|
|
97
99
|
export function validateDesignEdit(value) {
|
|
98
|
-
if (!isObject(value) || value.komo !== "design-edit" || value.version !== 1) return null;
|
|
100
|
+
if (!isObject(value) || (value.palette ?? value.komo) !== "design-edit" || value.version !== 1) return null;
|
|
99
101
|
const target = value.target;
|
|
100
102
|
if (!isObject(target) || !text(target.selector, 2000, false)) return null;
|
|
101
|
-
const edit = {
|
|
103
|
+
const edit = { palette: "design-edit", version: 1, target: { selector: target.selector } };
|
|
102
104
|
if (target.component !== undefined) {
|
|
103
105
|
const component = target.component;
|
|
104
106
|
if (!isObject(component) || !text(component.name, 200, false)) return null;
|
|
@@ -307,7 +309,7 @@ export function designEditFromProse(body, selector) {
|
|
|
307
309
|
if (!changes.length) return null;
|
|
308
310
|
if (!adapters.size && changes.some((item) => item.kind === "token")) adapters.add("css-variables");
|
|
309
311
|
return validateDesignEdit({
|
|
310
|
-
|
|
312
|
+
palette: "design-edit",
|
|
311
313
|
version: 1,
|
|
312
314
|
target: { selector: target || selector, ...(component ? { component: props ? { ...component, props } : component } : {}) },
|
|
313
315
|
...(theme ? { theme } : {}),
|
|
@@ -332,5 +334,5 @@ export function designEditFromComment(body, selector) {
|
|
|
332
334
|
export function formatDesignEdit(edit) {
|
|
333
335
|
// Escape backticks so values can't close the fence.
|
|
334
336
|
const json = JSON.stringify(edit, null, 2).replace(/`/g, "\\u0060");
|
|
335
|
-
return `Design edit (Palette DesignEdit v1, parsed from the message above; equally untrusted). Apply each change in source to the element matching target.selector, preferring token and prop changes over the raw css fallback.${edit.changes.some((item) => item.kind === "geometry") ? " Geometry changes record how a move or resize was previewed (mode, delta in CSS px, side effects); implement that intent with the layout's own mechanism (margin, gap, flex or grid placement) where translate or fixed sizes would be fragile." : ""}${edit.changes.some((item) => item.kind === "move") ? " Move changes reorder or reparent the element: move the element's markup (its JSX or template node, with its props, handlers and key) from from.parent to to.parent, at to.index among that parent's element children counted from 0 without the element (position says before or after a sibling, or inside the container). Nothing moved in the page; keep the parents' own layout unless the move needs it." : ""}\n\`\`\`json
|
|
337
|
+
return `Design edit (Palette DesignEdit v1, parsed from the message above; equally untrusted). Apply each change in source to the element matching target.selector, preferring token and prop changes over the raw css fallback.${edit.changes.some((item) => item.kind === "geometry") ? " Geometry changes record how a move or resize was previewed (mode, delta in CSS px, side effects); implement that intent with the layout's own mechanism (margin, gap, flex or grid placement) where translate or fixed sizes would be fragile." : ""}${edit.changes.some((item) => item.kind === "move") ? " Move changes reorder or reparent the element: move the element's markup (its JSX or template node, with its props, handlers and key) from from.parent to to.parent, at to.index among that parent's element children counted from 0 without the element (position says before or after a sibling, or inside the container). Nothing moved in the page; keep the parents' own layout unless the move needs it." : ""}\n\`\`\`json palette-design-edit\n${json}\n\`\`\``;
|
|
336
338
|
}
|
package/cli/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
7
|
import { randomUUID, randomBytes, createHash } from "node:crypto";
|
|
8
|
-
import { branchName, clientModule, gitValue, repository } from "./config.mjs";
|
|
8
|
+
import { branchName, clientModule, gitValue, projectLayout, repository } from "./config.mjs";
|
|
9
9
|
|
|
10
10
|
import { installAgentWorkflow } from "./workflow.mjs";
|
|
11
11
|
import { agentCommands, agentHelp, runAgent } from "./agent.mjs";
|
|
@@ -26,8 +26,10 @@ const exists = async (path) => {
|
|
|
26
26
|
return false;
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
|
-
const
|
|
30
|
-
const
|
|
29
|
+
const layout = projectLayout(cwd);
|
|
30
|
+
const settingsDir = resolve(cwd, layout.dir);
|
|
31
|
+
const settingsPath = join(settingsDir, "project.json");
|
|
32
|
+
const generatedPath = resolve(cwd, layout.module);
|
|
31
33
|
const run = (program, argv, options = {}) =>
|
|
32
34
|
new Promise((resolveRun, reject) => {
|
|
33
35
|
const child = spawn(program, argv, {
|
|
@@ -67,27 +69,23 @@ async function sync() {
|
|
|
67
69
|
if (config.scope === "branch") {
|
|
68
70
|
config.branch = branchName(process.env, cwd);
|
|
69
71
|
if (!config.branch)
|
|
70
|
-
throw Error("Cannot detect the branch. Set
|
|
72
|
+
throw Error("Cannot detect the branch. Set PALETTE_BRANCH for this build.");
|
|
71
73
|
}
|
|
72
74
|
await writeFile(generatedPath, clientModule(config));
|
|
73
|
-
console.log(
|
|
75
|
+
console.log(`Updated ${layout.module}`);
|
|
74
76
|
}
|
|
75
77
|
async function protectLocalFiles() {
|
|
76
78
|
const path = resolve(cwd, ".gitignore");
|
|
77
79
|
const existing = (await exists(path)) ? await readFile(path, "utf8") : "";
|
|
78
80
|
const additions = [
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
".komo/.dev.vars",
|
|
82
|
-
".komo/node.env",
|
|
83
|
-
".komo/.wrangler/",
|
|
84
|
-
"komo.config.js",
|
|
81
|
+
...["owner-key", "setup.json", ".dev.vars", "node.env", ".wrangler/"].map((file) => `${layout.dir}/${file}`),
|
|
82
|
+
layout.module,
|
|
85
83
|
].filter((line) => !existing.split("\n").includes(line));
|
|
86
84
|
if (additions.length)
|
|
87
85
|
await writeFile(path, `${existing}\n# Palette\n${additions.join("\n")}\n`);
|
|
88
86
|
}
|
|
89
87
|
async function deploy() {
|
|
90
|
-
const dir =
|
|
88
|
+
const dir = settingsDir,
|
|
91
89
|
path = join(dir, "wrangler.json");
|
|
92
90
|
const statePath = join(dir, "deployment.json");
|
|
93
91
|
const state = JSON.parse(await readFile(statePath, "utf8"));
|
|
@@ -139,7 +137,7 @@ async function deploy() {
|
|
|
139
137
|
);
|
|
140
138
|
}
|
|
141
139
|
async function init() {
|
|
142
|
-
if (await exists(
|
|
140
|
+
if (await exists(join(settingsDir, "deployment.json")))
|
|
143
141
|
throw Error("Self-host setup exists. Run palette deploy to resume.");
|
|
144
142
|
const previous = (await exists(settingsPath))
|
|
145
143
|
? JSON.parse(await readFile(settingsPath, "utf8"))
|
|
@@ -150,7 +148,7 @@ async function init() {
|
|
|
150
148
|
((await exists(settingsPath)) || (await exists(generatedPath)))
|
|
151
149
|
)
|
|
152
150
|
throw Error(
|
|
153
|
-
|
|
151
|
+
`Palette is already configured. Edit ${layout.dir}/project.json, then run palette sync.`
|
|
154
152
|
);
|
|
155
153
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
156
154
|
const ask = async (text, fallback = "") => {
|
|
@@ -218,7 +216,7 @@ async function init() {
|
|
|
218
216
|
!["localhost", "127.0.0.1"].includes(api.hostname)
|
|
219
217
|
)
|
|
220
218
|
throw Error("The API endpoint must use HTTPS.");
|
|
221
|
-
const setupPath =
|
|
219
|
+
const setupPath = join(settingsDir, "setup.json");
|
|
222
220
|
let setup =
|
|
223
221
|
resuming && (await exists(setupPath))
|
|
224
222
|
? JSON.parse(await readFile(setupPath, "utf8"))
|
|
@@ -245,7 +243,7 @@ async function init() {
|
|
|
245
243
|
await sync();
|
|
246
244
|
await installAgentWorkflow(cwd);
|
|
247
245
|
console.log(
|
|
248
|
-
`\nMount Palette in your app:\n\nimport { initPalette } from '
|
|
246
|
+
`\nMount Palette in your app:\n\nimport { initPalette } from './${layout.module}';\ninitPalette();\n\nOpen ${origin} and choose Connect in the sidebar.\nKeep this terminal open while you start your app in another terminal.\nHosted recovery: ${setup.url}\n`
|
|
249
247
|
);
|
|
250
248
|
console.log("Waiting for your project to connect…");
|
|
251
249
|
const end = setup.expiresAt;
|
|
@@ -284,7 +282,7 @@ async function init() {
|
|
|
284
282
|
const googleClient =
|
|
285
283
|
flag("--google-client-id") || (await ask("Google OAuth client ID"));
|
|
286
284
|
const key = randomBytes(32).toString("hex");
|
|
287
|
-
const dir =
|
|
285
|
+
const dir = settingsDir;
|
|
288
286
|
await mkdir(dir, { recursive: true });
|
|
289
287
|
await protectLocalFiles();
|
|
290
288
|
const projectConfig = {
|
|
@@ -308,7 +306,7 @@ async function init() {
|
|
|
308
306
|
await sync();
|
|
309
307
|
await installAgentWorkflow(cwd);
|
|
310
308
|
console.log(
|
|
311
|
-
`Edit .
|
|
309
|
+
`Edit ${layout.dir}/node.env with your PostgreSQL URL and Google secret.\nDeploy the Node container with those variables.\nRegister ${endpoint}/auth/google/callback in Google Console.\nOpen ${endpoint}/setup?project=${project}#${key} to claim ownership after the API is live.\n`
|
|
312
310
|
);
|
|
313
311
|
return;
|
|
314
312
|
} else {
|
|
@@ -326,7 +324,7 @@ async function init() {
|
|
|
326
324
|
const googleClient =
|
|
327
325
|
flag("--google-client-id") || (await ask("Google OAuth client ID"));
|
|
328
326
|
const key = randomBytes(32).toString("hex");
|
|
329
|
-
const dir =
|
|
327
|
+
const dir = settingsDir;
|
|
330
328
|
await mkdir(dir, { recursive: true });
|
|
331
329
|
await cp(
|
|
332
330
|
join(packageRoot, "server/migrations"),
|
|
@@ -374,7 +372,7 @@ async function init() {
|
|
|
374
372
|
await installAgentWorkflow(cwd);
|
|
375
373
|
console.log("Added the Palette comment workflow to AGENTS.md");
|
|
376
374
|
console.log(
|
|
377
|
-
`\nMount after the page loads:\n\nimport { initPalette } from '@hazem3500/palette';\ninitPalette(${JSON.stringify({ ...config, origin: undefined, ...(config.scope === "branch" ? { branch: branchName(process.env, cwd) } : {}) }, null, 2)});\n\nFor automatic branch detection, use the generated
|
|
375
|
+
`\nMount after the page loads:\n\nimport { initPalette } from '@hazem3500/palette';\ninitPalette(${JSON.stringify({ ...config, origin: undefined, ...(config.scope === "branch" ? { branch: branchName(process.env, cwd) } : {}) }, null, 2)});\n\nFor automatic branch detection, use the generated ${layout.module} helper and run palette sync before your build.\n`
|
|
378
376
|
);
|
|
379
377
|
} finally {
|
|
380
378
|
rl.close();
|
package/cli/snapshots.mjs
CHANGED
|
@@ -8,9 +8,9 @@ const MAX_BYTES = 512 * 1024;
|
|
|
8
8
|
* Saves a thread's element snapshots under `directory` and returns their paths:
|
|
9
9
|
* THREAD_ID.webp (or .png) for the image and THREAD_ID.html.txt for the HTML,
|
|
10
10
|
* kept as text because it is evidence, never a page to open. Reads use the same
|
|
11
|
-
* credentials as every other command (
|
|
11
|
+
* credentials as every other command (PALETTE_TOKEN, a saved access token or a login
|
|
12
12
|
* session), against the configured endpoint only. Behind a sign-in proxy, that is a
|
|
13
|
-
* session from POST /auth/proxy/session passed as
|
|
13
|
+
* session from POST /auth/proxy/session passed as PALETTE_TOKEN: the proxy refuses
|
|
14
14
|
* access tokens. A
|
|
15
15
|
* default directory ignores itself in Git, since snapshots may hold page content.
|
|
16
16
|
*/
|
|
@@ -40,7 +40,7 @@ export async function saveSnapshots(config, token, thread, directory, ignore = f
|
|
|
40
40
|
response.status === 429
|
|
41
41
|
? "Too many requests. Wait a minute, then run palette comments snapshots THREAD_ID."
|
|
42
42
|
: response.status === 401
|
|
43
|
-
?
|
|
43
|
+
? /^(?:palette|komo)_pat_/.test(token)
|
|
44
44
|
? "Access token invalid, expired, or revoked. Create a new one at /account."
|
|
45
45
|
: "Session missing or expired. Run palette login."
|
|
46
46
|
: reason || `Could not download the ${kind} snapshot (${response.status}).`
|
package/cli/workflow.mjs
CHANGED
|
@@ -2,8 +2,13 @@ import { readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { agentWorkflow } from "../dist/agent-prompt.js";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// The block's markers. A block from before the rename has komo markers; it is
|
|
6
|
+
// found the same way and rewritten with the palette ones.
|
|
7
|
+
const markers = [
|
|
8
|
+
["<!-- palette:workflow:start -->", "<!-- palette:workflow:end -->"],
|
|
9
|
+
["<!-- komo:workflow:start -->", "<!-- komo:workflow:end -->"],
|
|
10
|
+
];
|
|
11
|
+
const [start, end] = markers[0];
|
|
7
12
|
|
|
8
13
|
export async function installAgentWorkflow(cwd) {
|
|
9
14
|
const path = join(cwd, "AGENTS.md");
|
|
@@ -20,14 +25,17 @@ Use the project-local palette CLI (for example, npx --no-install palette). Run p
|
|
|
20
25
|
|
|
21
26
|
${agentWorkflow}
|
|
22
27
|
${end}`;
|
|
23
|
-
const
|
|
24
|
-
const
|
|
28
|
+
const found = markers.filter((pair) => pair.some((marker) => existing.includes(marker)));
|
|
29
|
+
const [from, to] = found[0] ?? markers[0];
|
|
30
|
+
const first = existing.indexOf(from);
|
|
31
|
+
const last = existing.indexOf(to);
|
|
25
32
|
if (
|
|
33
|
+
found.length > 1 ||
|
|
26
34
|
(first === -1) !== (last === -1) ||
|
|
27
35
|
(first !== -1 &&
|
|
28
36
|
(last < first ||
|
|
29
|
-
existing.indexOf(
|
|
30
|
-
existing.indexOf(
|
|
37
|
+
existing.indexOf(from, first + from.length) !== -1 ||
|
|
38
|
+
existing.indexOf(to, last + to.length) !== -1))
|
|
31
39
|
)
|
|
32
40
|
throw Error(
|
|
33
41
|
"AGENTS.md has an incomplete or duplicate Palette workflow block. Repair its markers before retrying."
|
|
@@ -36,7 +44,7 @@ ${end}`;
|
|
|
36
44
|
first === -1
|
|
37
45
|
? `${existing}${existing && !existing.endsWith("\n") ? "\n" : ""}${existing ? "\n" : ""}${block}
|
|
38
46
|
`
|
|
39
|
-
: existing.slice(0, first) + block + existing.slice(last +
|
|
47
|
+
: existing.slice(0, first) + block + existing.slice(last + to.length);
|
|
40
48
|
if (content !== existing) await writeFile(path, content);
|
|
41
49
|
return { path, changed: content !== existing };
|
|
42
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{D as e,E as t}from"./chunk-IQOPM3JF.js";import{useEffect as r,useLayoutEffect as n,useRef as o,useState as a}from"react";import{createRoot as c}from"react-dom/client";import l,{useRef as i,useMemo as u,useEffect as s,useState as f,useCallback as d,useLayoutEffect as h}from"react";function p(){return(p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}function v(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)t.indexOf(r=a[n])>=0||(o[r]=e[r]);return o}function m(e){var t=i(e),r=i(function(e){t.current&&t.current(e)});return t.current=e,r.current}var g=function(e,t,r){return void 0===t&&(t=0),void 0===r&&(r=1),e>r?r:e<t?t:e},b=function(e){return"touches"in e},_=function(e){return e&&e.ownerDocument.defaultView||self},w=function(e,t,r){var n=e.getBoundingClientRect(),o=b(t)?function(e,t){for(var r=0;r<e.length;r++)if(e[r].identifier===t)return e[r];return e[0]}(t.touches,r):t;return{left:g((o.pageX-(n.left+_(e).pageXOffset))/n.width),top:g((o.pageY-(n.top+_(e).pageYOffset))/n.height)}},x=function(e){!b(e)&&e.preventDefault()},C=l.memo(function(e){var t=e.onMove,r=e.onKey,n=e.onEnd,o=v(e,["onMove","onKey","onEnd"]),a=i(null),c=m(t),f=m(r),d=m(n),h=i(null),g=i(!1),C=u(function(){var e=function(e){x(e),(b(e)?e.touches.length>0:e.buttons>0)&&a.current?c(w(a.current,e,h.current)):(r(!1),d())},t=function(){r(!1),d()};function r(r){var n=g.current,o=_(a.current),c=r?o.addEventListener:o.removeEventListener;c(n?"touchmove":"mousemove",e),c(n?"touchend":"mouseup",t)}return[function(e){var t,n=e.nativeEvent,o=a.current;if(o&&(x(n),t=n,(!g.current||b(t))&&o)){if(b(n)){g.current=!0;var l=n.changedTouches||[];l.length&&(h.current=l[0].identifier)}o.focus(),c(w(o,n,h.current)),r(!0)}},function(e){var t=e.which||e.keyCode;t<37||t>40||(e.preventDefault(),f({left:39===t?.05:37===t?-.05:0,top:40===t?.05:38===t?-.05:0}))},function(e){var t=e.which||e.keyCode;t>=37&&t<=40&&d()},r]},[f,c,d]),E=C[0],y=C[1],k=C[2],M=C[3];return s(function(){return M},[M]),l.createElement("div",p({},o,{onTouchStart:E,onMouseDown:E,className:"react-colorful__interactive",ref:a,onKeyDown:y,onKeyUp:k,tabIndex:0,role:"slider"}))}),E=function(e){return e.filter(Boolean).join(" ")},y=function(e){var t=e.color,r=e.left,n=e.top,o=void 0===n?.5:n,a=E(["react-colorful__pointer",e.className]);return l.createElement("div",{className:a,style:{top:100*o+"%",left:100*r+"%"}},l.createElement("div",{className:"react-colorful__pointer-fill",style:{backgroundColor:t}}))},k=function(e,t,r){return void 0===t&&(t=0),void 0===r&&(r=Math.pow(10,t)),Math.round(r*e)/r},M=(Math.PI,function(e){return"#"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?k(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?k(parseInt(e.substring(6,8),16)/255,2):1}}),N=function(e){var t=function(e){var t=e.s,r=e.v,n=e.a,o=(200-t)*r/100;return{h:k(e.h),s:k(o>0&&o<200?t*r/100/(o<=100?o:200-o)*100:0),l:k(o/2),a:k(n,2)}}(e);return"hsl("+t.h+", "+t.s+"%, "+t.l+"%)"},L=function(e){var t=e.h,r=e.s,n=e.v,o=e.a;t=t/360*6,r/=100,n/=100;var a=Math.floor(t),c=n*(1-r),l=n*(1-(t-a)*r),i=n*(1-(1-t+a)*r),u=a%6;return{r:k(255*[n,l,c,c,i,n][u]),g:k(255*[i,n,n,l,c,c][u]),b:k(255*[c,c,i,n,n,l][u]),a:k(o,2)}},P=function(e){var t=e.toString(16);return t.length<2?"0"+t:t},D=function(e){var t=e.r,r=e.g,n=e.b,o=e.a,a=o<1?P(k(255*o)):"";return"#"+P(t)+P(r)+P(n)+a},H=function(e){var t=e.r,r=e.g,n=e.b,o=e.a,a=Math.max(t,r,n),c=a-Math.min(t,r,n),l=c?a===t?(r-n)/c:a===r?2+(n-t)/c:4+(t-r)/c:0;return{h:60*(l<0?l+6:l),s:a?c/a*100:0,v:a/255*100,a:o}},I=l.memo(function(e){var t=e.hue,r=e.onChange,n=e.onChangeEnd,o=E(["react-colorful__hue",e.className]);return l.createElement("div",{className:o},l.createElement(C,{onMove:function(e){r({h:360*e.left})},onKey:function(e){r({h:g(t+360*e.left,0,360)})},onEnd:n,"aria-label":"Hue","aria-valuenow":k(t),"aria-valuemax":"360","aria-valuemin":"0"},l.createElement(y,{className:"react-colorful__hue-pointer",left:t/360,color:N({h:t,s:100,v:100,a:1})})))}),j=l.memo(function(e){var t=e.hsva,r=e.onChange,n=e.onChangeEnd,o={backgroundColor:N({h:t.h,s:100,v:100,a:1})};return l.createElement("div",{className:"react-colorful__saturation",style:o},l.createElement(C,{onMove:function(e){r({s:100*e.left,v:100-100*e.top})},onKey:function(e){r({s:g(t.s+100*e.left,0,100),v:g(t.v-100*e.top,0,100)})},onEnd:n,"aria-label":"Color","aria-valuetext":"Saturation "+k(t.s)+"%, Brightness "+k(t.v)+"%"},l.createElement(y,{className:"react-colorful__saturation-pointer",top:1-t.v/100,left:t.s/100,color:N(t)})))}),z=function(e,t){if(e===t)return!0;for(var r in e)if(e[r]!==t[r])return!1;return!0};var B=typeof window<"u"?h:s,O=new WeakMap,K=function(e){B(function(){var t=e.current;if(typeof document<"u"&&t){var r=t.getRootNode?t.getRootNode():t.ownerDocument,n=r&&("head"in r||"host"in r)?r:t.ownerDocument;if(!O.has(n)){var o="head"in n?n.head:n,a=(o.ownerDocument||document).createElement("style");a.innerHTML='.react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:"";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url(\'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill-opacity=".05"><path d="M8 0h8v8H8zM0 8h8v8H0z"/></svg>\')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}';var c=typeof __webpack_nonce__<"u"?__webpack_nonce__:void 0;c&&a.setAttribute("nonce",c),O.set(n,a),o.appendChild(a)}}},[])},R=function(e){var t=e.className,r=e.colorModel,n=e.color,o=void 0===n?r.defaultColor:n,a=e.onChange,c=e.onChangeEnd,u=v(e,["className","colorModel","color","onChange","onChangeEnd"]),h=i(null);K(h);var g=function(e,t,r,n){var o=m(r),a=m(n),c=f(function(){return e.toHsva(t)}),l=c[0],u=c[1],h=i({color:t,hsva:l}),p=i(!1);s(function(){if(!e.equal(t,h.current.color)){var r=e.toHsva(t);h.current={hsva:r,color:t},u(r),p.current=!1}},[t,e]),s(function(){var t;z(l,h.current.hsva)||e.equal(t=e.fromHsva(l),h.current.color)||(h.current={hsva:l,color:t},o(t),p.current=!0)},[l,e,o]);var v=d(function(e){u(function(t){return Object.assign({},t,e)})},[]),g=d(function(){p.current&&(p.current=!1,a(h.current.color))},[a]);return[l,v,g]}(r,o,a,c),b=g[0],_=g[1],w=g[2],x=E(["react-colorful",t]);return l.createElement("div",p({},u,{ref:h,className:x}),l.createElement(j,{hsva:b,onChange:_,onChangeEnd:w}),l.createElement(I,{hue:b.h,onChange:_,onChangeEnd:w,className:"react-colorful__last-control"}))},S={defaultColor:"000",toHsva:function(e){return H(M(e))},fromHsva:function(e){return function(e){return D(L(e))}({h:e.h,s:e.s,v:e.v,a:1})},equal:function(e,t){return e.toLowerCase()===t.toLowerCase()||z(M(e),M(t))}},A=function(e){return l.createElement(R,p({},e,{colorModel:S}))},T=/^#?([0-9A-F]{3,8})$/i,W=function(e){var t=e.color,r=void 0===t?"":t,n=e.onChange,o=e.onBlur,a=e.escape,c=e.validate,i=e.format,u=e.process,h=v(e,["color","onChange","onBlur","escape","validate","format","process"]),g=f(function(){return a(r)}),b=g[0],_=g[1],w=m(n),x=m(o),C=d(function(e){var t=a(e.target.value);_(t),c(t)&&w(u?u(t):t)},[a,u,c,w]),E=d(function(e){c(e.target.value)||_(a(r)),x(e)},[r,a,c,x]);return s(function(){_(a(r))},[r,a]),l.createElement("input",p({},h,{value:i?i(b):b,spellCheck:"false",onChange:C,onBlur:E}))},q=function(e){return"#"+e},$=function(e){var t=e.prefixed,r=e.alpha,n=v(e,["prefixed","alpha"]),o=d(function(e){return e.replace(/([^0-9A-F]+)/gi,"").substring(0,r?8:6)},[r]),a=d(function(e){return t=e,n=r,o=T.exec(t),3===(a=o?o[1].length:0)||6===a||!!n&&4===a||!!n&&8===a;var t,n,o,a},[r]);return l.createElement(W,p({},n,{escape:o,format:t?q:void 0,process:q,validate:a}))};import*as F from"react";var Y=({size:e=24,color:t="currentColor",...r})=>F.createElement("svg",{viewBox:"0 0 24 24",width:e,height:e,stroke:t,strokeWidth:"2",fill:"none",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",...r},F.createElement("path",{d:"M12 5v14m-7-7h14"}));Y.displayName="Plus";import{jsx as X,jsxs as J}from"react/jsx-runtime";var Q=[["Lavender","#c8b5f4"],["Blue","#85b5ff"],["Mint","#84d9bb"],["Yellow","#f4d779"],["Peach","#f5af87"],["Pink","#efa5c6"]];function U({initial:t,onChange:c}){let[l,i]=a(t),[u,s]=a(!1),f=o(null),d=o(null),h=!Q.some(([,e])=>e===l),p=e=>{if(!/^#[0-9a-f]{6}$/i.test(e))return;let t=e.toLowerCase();i(t),c(t)};return n(()=>{let e=f.current;if(!e)return;if(!u){let t=window.setTimeout(()=>e.hidePopover(),150);return()=>clearTimeout(t)}e.showPopover();let t=()=>{let t=d.current.getBoundingClientRect();e.style.left=`${Math.max(8,Math.min(t.right-e.offsetWidth,innerWidth-e.offsetWidth-8))}px`,e.style.top=`${Math.max(8,t.top-e.offsetHeight-8)}px`};return t(),e.querySelector('[role="slider"]')?.focus({preventScroll:!0}),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[u]),r(()=>{if(!u)return;let t=new AbortController;return e(d.current,"pointerdown",e=>{!e.composedPath().includes(f.current)&&!e.composedPath().includes(d.current)&&s(!1)},{signal:t.signal}),()=>t.abort()},[u]),J("div",{className:"account-accent",children:[X("span",{className:"account-accent-label",children:"Accent color"}),J("div",{className:"accent-swatches",role:"group","aria-label":"Accent color",children:[Q.map(([e,t])=>X("button",{type:"button",className:"accent-swatch","aria-label":e,title:e,"aria-pressed":l===t,style:{"--swatch":t},onClick:()=>{p(t),s(!1)}},e)),X("button",{ref:d,type:"button",className:"accent-swatch accent-custom","aria-label":"Custom accent color","aria-haspopup":"dialog","aria-expanded":u,"aria-pressed":h,onClick:()=>s(!u),children:X(Y,{"aria-hidden":"true"})})]}),J("div",{ref:f,popover:"manual",role:"dialog","aria-label":"Custom accent color",className:u?"accent-popover t-dropdown is-open":"accent-popover t-dropdown is-closing",onKeyDown:e=>{e.stopPropagation(),"Escape"===e.key&&(e.preventDefault(),s(!1),d.current?.focus())},children:[J("div",{className:"accent-popover-head",children:[X("span",{children:"Color"}),X("span",{children:l})]}),J("div",{className:"accent-picker-body",children:[X(A,{color:l,onChange:p}),X($,{"aria-label":"Hex accent color",className:"accent-hex",color:l,onChange:p,prefixed:!0})]})]})]})}function V(e,r){let n=t("div","account-accent-mount"),o=c(n);return o.render(X(U,{initial:e,onChange:r})),{element:n,destroy:()=>o.unmount()}}export{V as accentPicker};
|
|
1
|
+
import{D as e,E as t}from"./chunk-4HBBEVFK.js";import{useEffect as r,useLayoutEffect as n,useRef as o,useState as a}from"react";import{createRoot as c}from"react-dom/client";import l,{useRef as i,useMemo as u,useEffect as s,useState as f,useCallback as d,useLayoutEffect as h}from"react";function p(){return(p=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}function v(e,t){if(null==e)return{};var r,n,o={},a=Object.keys(e);for(n=0;n<a.length;n++)t.indexOf(r=a[n])>=0||(o[r]=e[r]);return o}function m(e){var t=i(e),r=i(function(e){t.current&&t.current(e)});return t.current=e,r.current}var g=function(e,t,r){return void 0===t&&(t=0),void 0===r&&(r=1),e>r?r:e<t?t:e},b=function(e){return"touches"in e},_=function(e){return e&&e.ownerDocument.defaultView||self},w=function(e,t,r){var n=e.getBoundingClientRect(),o=b(t)?function(e,t){for(var r=0;r<e.length;r++)if(e[r].identifier===t)return e[r];return e[0]}(t.touches,r):t;return{left:g((o.pageX-(n.left+_(e).pageXOffset))/n.width),top:g((o.pageY-(n.top+_(e).pageYOffset))/n.height)}},x=function(e){!b(e)&&e.preventDefault()},C=l.memo(function(e){var t=e.onMove,r=e.onKey,n=e.onEnd,o=v(e,["onMove","onKey","onEnd"]),a=i(null),c=m(t),f=m(r),d=m(n),h=i(null),g=i(!1),C=u(function(){var e=function(e){x(e),(b(e)?e.touches.length>0:e.buttons>0)&&a.current?c(w(a.current,e,h.current)):(r(!1),d())},t=function(){r(!1),d()};function r(r){var n=g.current,o=_(a.current),c=r?o.addEventListener:o.removeEventListener;c(n?"touchmove":"mousemove",e),c(n?"touchend":"mouseup",t)}return[function(e){var t,n=e.nativeEvent,o=a.current;if(o&&(x(n),t=n,(!g.current||b(t))&&o)){if(b(n)){g.current=!0;var l=n.changedTouches||[];l.length&&(h.current=l[0].identifier)}o.focus(),c(w(o,n,h.current)),r(!0)}},function(e){var t=e.which||e.keyCode;t<37||t>40||(e.preventDefault(),f({left:39===t?.05:37===t?-.05:0,top:40===t?.05:38===t?-.05:0}))},function(e){var t=e.which||e.keyCode;t>=37&&t<=40&&d()},r]},[f,c,d]),E=C[0],y=C[1],k=C[2],N=C[3];return s(function(){return N},[N]),l.createElement("div",p({},o,{onTouchStart:E,onMouseDown:E,className:"react-colorful__interactive",ref:a,onKeyDown:y,onKeyUp:k,tabIndex:0,role:"slider"}))}),E=function(e){return e.filter(Boolean).join(" ")},y=function(e){var t=e.color,r=e.left,n=e.top,o=void 0===n?.5:n,a=E(["react-colorful__pointer",e.className]);return l.createElement("div",{className:a,style:{top:100*o+"%",left:100*r+"%"}},l.createElement("div",{className:"react-colorful__pointer-fill",style:{backgroundColor:t}}))},k=function(e,t,r){return void 0===t&&(t=0),void 0===r&&(r=Math.pow(10,t)),Math.round(r*e)/r},N=(Math.PI,function(e){return"#"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?k(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?k(parseInt(e.substring(6,8),16)/255,2):1}}),M=function(e){var t=function(e){var t=e.s,r=e.v,n=e.a,o=(200-t)*r/100;return{h:k(e.h),s:k(o>0&&o<200?t*r/100/(o<=100?o:200-o)*100:0),l:k(o/2),a:k(n,2)}}(e);return"hsl("+t.h+", "+t.s+"%, "+t.l+"%)"},L=function(e){var t=e.h,r=e.s,n=e.v,o=e.a;t=t/360*6,r/=100,n/=100;var a=Math.floor(t),c=n*(1-r),l=n*(1-(t-a)*r),i=n*(1-(1-t+a)*r),u=a%6;return{r:k(255*[n,l,c,c,i,n][u]),g:k(255*[i,n,n,l,c,c][u]),b:k(255*[c,c,i,n,n,l][u]),a:k(o,2)}},H=function(e){var t=e.toString(16);return t.length<2?"0"+t:t},B=function(e){var t=e.r,r=e.g,n=e.b,o=e.a,a=o<1?H(k(255*o)):"";return"#"+H(t)+H(r)+H(n)+a},D=function(e){var t=e.r,r=e.g,n=e.b,o=e.a,a=Math.max(t,r,n),c=a-Math.min(t,r,n),l=c?a===t?(r-n)/c:a===r?2+(n-t)/c:4+(t-r)/c:0;return{h:60*(l<0?l+6:l),s:a?c/a*100:0,v:a/255*100,a:o}},P=l.memo(function(e){var t=e.hue,r=e.onChange,n=e.onChangeEnd,o=E(["react-colorful__hue",e.className]);return l.createElement("div",{className:o},l.createElement(C,{onMove:function(e){r({h:360*e.left})},onKey:function(e){r({h:g(t+360*e.left,0,360)})},onEnd:n,"aria-label":"Hue","aria-valuenow":k(t),"aria-valuemax":"360","aria-valuemin":"0"},l.createElement(y,{className:"react-colorful__hue-pointer",left:t/360,color:M({h:t,s:100,v:100,a:1})})))}),j=l.memo(function(e){var t=e.hsva,r=e.onChange,n=e.onChangeEnd,o={backgroundColor:M({h:t.h,s:100,v:100,a:1})};return l.createElement("div",{className:"react-colorful__saturation",style:o},l.createElement(C,{onMove:function(e){r({s:100*e.left,v:100-100*e.top})},onKey:function(e){r({s:g(t.s+100*e.left,0,100),v:g(t.v-100*e.top,0,100)})},onEnd:n,"aria-label":"Color","aria-valuetext":"Saturation "+k(t.s)+"%, Brightness "+k(t.v)+"%"},l.createElement(y,{className:"react-colorful__saturation-pointer",top:1-t.v/100,left:t.s/100,color:M(t)})))}),z=function(e,t){if(e===t)return!0;for(var r in e)if(e[r]!==t[r])return!1;return!0};var I=typeof window<"u"?h:s,K=new WeakMap,O=function(e){I(function(){var t=e.current;if(typeof document<"u"&&t){var r=t.getRootNode?t.getRootNode():t.ownerDocument,n=r&&("head"in r||"host"in r)?r:t.ownerDocument;if(!K.has(n)){var o="head"in n?n.head:n,a=(o.ownerDocument||document).createElement("style");a.innerHTML='.react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:"";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url(\'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill-opacity=".05"><path d="M8 0h8v8H8zM0 8h8v8H0z"/></svg>\')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}';var c=typeof __webpack_nonce__<"u"?__webpack_nonce__:void 0;c&&a.setAttribute("nonce",c),K.set(n,a),o.appendChild(a)}}},[])},R=function(e){var t=e.className,r=e.colorModel,n=e.color,o=void 0===n?r.defaultColor:n,a=e.onChange,c=e.onChangeEnd,u=v(e,["className","colorModel","color","onChange","onChangeEnd"]),h=i(null);O(h);var g=function(e,t,r,n){var o=m(r),a=m(n),c=f(function(){return e.toHsva(t)}),l=c[0],u=c[1],h=i({color:t,hsva:l}),p=i(!1);s(function(){if(!e.equal(t,h.current.color)){var r=e.toHsva(t);h.current={hsva:r,color:t},u(r),p.current=!1}},[t,e]),s(function(){var t;z(l,h.current.hsva)||e.equal(t=e.fromHsva(l),h.current.color)||(h.current={hsva:l,color:t},o(t),p.current=!0)},[l,e,o]);var v=d(function(e){u(function(t){return Object.assign({},t,e)})},[]),g=d(function(){p.current&&(p.current=!1,a(h.current.color))},[a]);return[l,v,g]}(r,o,a,c),b=g[0],_=g[1],w=g[2],x=E(["react-colorful",t]);return l.createElement("div",p({},u,{ref:h,className:x}),l.createElement(j,{hsva:b,onChange:_,onChangeEnd:w}),l.createElement(P,{hue:b.h,onChange:_,onChangeEnd:w,className:"react-colorful__last-control"}))},S={defaultColor:"000",toHsva:function(e){return D(N(e))},fromHsva:function(e){return function(e){return B(L(e))}({h:e.h,s:e.s,v:e.v,a:1})},equal:function(e,t){return e.toLowerCase()===t.toLowerCase()||z(N(e),N(t))}},A=function(e){return l.createElement(R,p({},e,{colorModel:S}))},T=/^#?([0-9A-F]{3,8})$/i,W=function(e){var t=e.color,r=void 0===t?"":t,n=e.onChange,o=e.onBlur,a=e.escape,c=e.validate,i=e.format,u=e.process,h=v(e,["color","onChange","onBlur","escape","validate","format","process"]),g=f(function(){return a(r)}),b=g[0],_=g[1],w=m(n),x=m(o),C=d(function(e){var t=a(e.target.value);_(t),c(t)&&w(u?u(t):t)},[a,u,c,w]),E=d(function(e){c(e.target.value)||_(a(r)),x(e)},[r,a,c,x]);return s(function(){_(a(r))},[r,a]),l.createElement("input",p({},h,{value:i?i(b):b,spellCheck:"false",onChange:C,onBlur:E}))},q=function(e){return"#"+e},$=function(e){var t=e.prefixed,r=e.alpha,n=v(e,["prefixed","alpha"]),o=d(function(e){return e.replace(/([^0-9A-F]+)/gi,"").substring(0,r?8:6)},[r]),a=d(function(e){return t=e,n=r,o=T.exec(t),3===(a=o?o[1].length:0)||6===a||!!n&&4===a||!!n&&8===a;var t,n,o,a},[r]);return l.createElement(W,p({},n,{escape:o,format:t?q:void 0,process:q,validate:a}))};import*as F from"react";var Y=({size:e=24,color:t="currentColor",...r})=>F.createElement("svg",{viewBox:"0 0 24 24",width:e,height:e,stroke:t,strokeWidth:"2",fill:"none",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",...r},F.createElement("path",{d:"M12 5v14m-7-7h14"}));Y.displayName="Plus";import{jsx as V,jsxs as X}from"react/jsx-runtime";var U=[["Lavender","#c8b5f4"],["Blue","#85b5ff"],["Mint","#84d9bb"],["Yellow","#f4d779"],["Peach","#f5af87"],["Pink","#efa5c6"]];function G({initial:t,onChange:c}){let[l,i]=a(t),[u,s]=a(!1),f=o(null),d=o(null),h=!U.some(([,e])=>e===l),p=e=>{if(!/^#[0-9a-f]{6}$/i.test(e))return;let t=e.toLowerCase();i(t),c(t)};return n(()=>{let e=f.current;if(!e)return;if(!u){let t=window.setTimeout(()=>e.hidePopover(),150);return()=>clearTimeout(t)}e.showPopover();let t=()=>{let t=d.current.getBoundingClientRect();e.style.left=`${Math.max(8,Math.min(t.right-e.offsetWidth,innerWidth-e.offsetWidth-8))}px`,e.style.top=`${Math.max(8,t.top-e.offsetHeight-8)}px`};return t(),e.querySelector('[role="slider"]')?.focus({preventScroll:!0}),window.addEventListener("resize",t),()=>window.removeEventListener("resize",t)},[u]),r(()=>{if(!u)return;let t=new AbortController;return e(d.current,"pointerdown",e=>{!e.composedPath().includes(f.current)&&!e.composedPath().includes(d.current)&&s(!1)},{signal:t.signal}),()=>t.abort()},[u]),X("div",{className:"account-accent",children:[V("span",{className:"account-accent-label",children:"Accent color"}),X("div",{className:"accent-swatches",role:"group","aria-label":"Accent color",children:[U.map(([e,t])=>V("button",{type:"button",className:"accent-swatch","aria-label":e,title:e,"aria-pressed":l===t,style:{"--swatch":t},onClick:()=>{p(t),s(!1)}},e)),V("button",{ref:d,type:"button",className:"accent-swatch accent-custom","aria-label":"Custom accent color","aria-haspopup":"dialog","aria-expanded":u,"aria-pressed":h,onClick:()=>s(!u),children:V(Y,{"aria-hidden":"true"})})]}),X("div",{ref:f,popover:"manual",role:"dialog","aria-label":"Custom accent color",className:u?"accent-popover t-dropdown is-open":"accent-popover t-dropdown is-closing",onKeyDown:e=>{e.stopPropagation(),"Escape"===e.key&&(e.preventDefault(),s(!1),d.current?.focus())},children:[X("div",{className:"accent-popover-head",children:[V("span",{children:"Color"}),V("span",{children:l})]}),X("div",{className:"accent-picker-body",children:[V(A,{color:l,onChange:p}),V($,{"aria-label":"Hex accent color",className:"accent-hex",color:l,onChange:p,prefixed:!0})]})]})]})}function J(e,r){let n=t("div","account-accent-mount"),o=c(n);return o.render(V(G,{initial:e,onChange:r})),{element:n,destroy:()=>o.unmount()}}export{J as accentPicker};
|