@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.
Files changed (114) hide show
  1. package/NODE.md +32 -30
  2. package/README.md +36 -28
  3. package/cli/agent.mjs +87 -64
  4. package/cli/config.mjs +17 -1
  5. package/cli/design-edit.mjs +9 -7
  6. package/cli/index.mjs +18 -20
  7. package/cli/snapshots.mjs +3 -3
  8. package/cli/workflow.mjs +15 -7
  9. package/dist/{accent-picker-TTIZ65XF.js → accent-picker-PPVPURA7.js} +1 -1
  10. package/dist/account-tokens-LBRVZAEJ.js +1 -0
  11. package/dist/adapters/css-variables.js +1 -1
  12. package/dist/adapters/tailwind.js +1 -1
  13. package/dist/chunk-2FX2JEMO.js +1 -0
  14. package/dist/chunk-4HBBEVFK.js +1 -0
  15. package/dist/chunk-5HZI7HRR.js +1 -0
  16. package/dist/chunk-DU7H4TEX.js +1 -0
  17. package/dist/chunk-FGZXQUAD.js +1 -0
  18. package/dist/{chunk-AYGLN3MI.js → chunk-HLXSRXTK.js} +1 -1
  19. package/dist/{chunk-DZRM3YUQ.js → chunk-J47R52WX.js} +1 -1
  20. package/dist/chunk-KELFDOEC.js +1 -0
  21. package/dist/{chunk-2J3IID4N.js → chunk-KLPQTFVH.js} +1 -1
  22. package/dist/chunk-ONUORDYE.js +1 -0
  23. package/dist/chunk-PF4NYFZK.js +1 -0
  24. package/dist/chunk-S6NEYT36.js +1 -0
  25. package/dist/chunk-VX6XCU4E.js +1 -0
  26. package/dist/chunk-ZIEPA67C.js +1 -0
  27. package/dist/color-editor-QPJQD36F.js +1 -0
  28. package/dist/design-comment-BF2KGPWU.js +1 -0
  29. package/dist/{design-export-BNNHI4JP.js → design-export-Y2GU3KER.js} +1 -1
  30. package/dist/design-geometry-HJLEXLPO.js +1 -0
  31. package/dist/design-mode-styles.d.ts +1 -1
  32. package/dist/design-mode.js +1 -1
  33. package/dist/design-panel-ZQS4WQCI.js +1 -0
  34. package/dist/design-panel-styles.d.ts +1 -1
  35. package/dist/design-popup.d.ts +1 -1
  36. package/dist/design-system.d.ts +5 -4
  37. package/dist/{field-controls-4ROTPXMO.js → field-controls-4AIIXPNQ.js} +1 -1
  38. package/dist/{frame-iframe-WBEP3R6S.js → frame-iframe-PYLYMCOK.js} +1 -1
  39. package/dist/frame-size-TF6SIUFO.js +1 -0
  40. package/dist/frame-target.d.ts +5 -2
  41. package/dist/host-motion.d.ts +1 -1
  42. package/dist/index.js +1 -1
  43. package/dist/inline-text-editor-MK6FHDAM.js +1 -0
  44. package/dist/live-colors-D426RBEC.js +1 -0
  45. package/dist/live-colors.d.ts +1 -1
  46. package/dist/node.mjs +103 -75
  47. package/dist/onboarding-YZ2MJBS5.js +1 -0
  48. package/dist/{pin-groups-YAYFPJYA.js → pin-groups-GF53RTHP.js} +1 -1
  49. package/dist/{pin-move-PG54WWPU.js → pin-move-G6EWHLDO.js} +1 -1
  50. package/dist/public-env.d.ts +49 -11
  51. package/dist/react-props-panel-ZSKQ44GS.js +1 -0
  52. package/dist/react.d.ts +2 -0
  53. package/dist/react.js +1 -1
  54. package/dist/select-menu-OZVNHZ73.js +1 -0
  55. package/dist/server.js +80 -57
  56. package/dist/setup.js +1 -1
  57. package/dist/shell-mode-PLV6F474.js +1 -0
  58. package/dist/shell-session.d.ts +5 -3
  59. package/dist/shell.d.ts +1 -1
  60. package/dist/shell.js +1 -1
  61. package/dist/shortcut-help-DIMOT2ZK.js +1 -0
  62. package/dist/snapshot-3PSQKXUV.js +1 -0
  63. package/dist/snapshot.d.ts +1 -1
  64. package/dist/source-info.d.ts +1 -1
  65. package/dist/storage-keys.d.ts +5 -0
  66. package/dist/tag-editor-B3I7WD4N.js +1 -0
  67. package/dist/thread-snapshot-ML2RZVID.js +1 -0
  68. package/dist/token-custom-CASAQWYW.js +1 -0
  69. package/dist/token-page-NIB5HAVS.js +1 -0
  70. package/dist/token-picker-AJ5E5IN5.js +1 -0
  71. package/dist/{toolbar-runtime-QCZONSWE.js → toolbar-runtime-TZWY2KH3.js} +1 -1
  72. package/dist/typed-custom.d.ts +1 -1
  73. package/dist/types.d.ts +1 -1
  74. package/package.json +1 -1
  75. package/server/account-page.ts +6 -6
  76. package/server/iap.ts +2 -2
  77. package/server/index.ts +30 -24
  78. package/server/project-management.ts +5 -5
  79. package/server/proxy-auth.ts +17 -16
  80. package/server/public-env.ts +67 -11
  81. package/server/setup-client.txt +173 -173
  82. package/server/setup-page.ts +1 -1
  83. package/server/tokens.ts +9 -6
  84. package/server/webhooks.ts +9 -5
  85. package/src/types.ts +1 -1
  86. package/dist/account-tokens-PINQNSNE.js +0 -1
  87. package/dist/chunk-4KEVPMJJ.js +0 -1
  88. package/dist/chunk-4XQD75A2.js +0 -1
  89. package/dist/chunk-57MG3M5P.js +0 -1
  90. package/dist/chunk-5OVDW2RU.js +0 -1
  91. package/dist/chunk-6HM4JQLV.js +0 -1
  92. package/dist/chunk-DLC3CRFV.js +0 -1
  93. package/dist/chunk-DVYSFT6O.js +0 -1
  94. package/dist/chunk-FD4GACV2.js +0 -1
  95. package/dist/chunk-IQOPM3JF.js +0 -1
  96. package/dist/chunk-UEZCLURX.js +0 -1
  97. package/dist/color-editor-ATWWSENS.js +0 -1
  98. package/dist/design-comment-RXUCDTYA.js +0 -1
  99. package/dist/design-geometry-DPMHGQEK.js +0 -1
  100. package/dist/design-panel-HTN6LR3V.js +0 -1
  101. package/dist/frame-size-MRCN6XYD.js +0 -1
  102. package/dist/inline-text-editor-AMFRKW5Z.js +0 -1
  103. package/dist/live-colors-GWOVVQSO.js +0 -1
  104. package/dist/onboarding-BVTCFEHL.js +0 -1
  105. package/dist/react-props-panel-4XO3NSX3.js +0 -1
  106. package/dist/select-menu-QAYV7NKJ.js +0 -1
  107. package/dist/shell-mode-SUYLWDWW.js +0 -1
  108. package/dist/shortcut-help-XRDNX7MZ.js +0 -1
  109. package/dist/snapshot-V264ZMQG.js +0 -1
  110. package/dist/tag-editor-MMAMOEI4.js +0 -1
  111. package/dist/thread-snapshot-HLTNHS4N.js +0 -1
  112. package/dist/token-custom-UCA6CBOV.js +0 -1
  113. package/dist/token-page-PGPWPUKU.js +0 -1
  114. 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
- while (true) {
148
- try {
149
- settings = JSON.parse(
150
- await readFile(join(directory, ".komo/project.json"), "utf8")
151
- );
152
- root = directory;
153
- break;
154
- } catch (error) {
155
- if (error.code !== "ENOENT") throw error;
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.KOMO_PROJECT || settings.project;
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.KOMO_ENDPOINT ||
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.KOMO_ORIGIN ||
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.KOMO_BRANCH ||
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.KOMO_REPO || settings.repo || project,
190
+ repo: flags.repo || setting(env, "REPO") || settings.repo || project,
187
191
  root,
192
+ settingsDir,
188
193
  };
189
194
  }
190
- function credentialPath(config, env) {
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 join(
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 = /^komo_pat_[a-z0-9]{12}_[A-Za-z0-9_-]{43}$/;
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 personalTokenPath(config, env) {
212
+ function personalTokenPaths(config, env) {
203
213
  const key = createHash("sha256").update(config.endpoint).digest("hex");
204
- return join(
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(path) {
210
- try {
211
- return JSON.parse(await readFile(path, "utf8")).token || null;
212
- } catch (error) {
213
- if (error.code !== "ENOENT") throw error;
214
- return null;
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(sessionPath, patPath, env) {
219
- const saved = { session: await readSaved(sessionPath), pat: await readSaved(patPath) };
220
- const [source, token] = env.KOMO_TOKEN
221
- ? ["env", env.KOMO_TOKEN]
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 (komo_pat_…) on stdin.");
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?.startsWith("komo_pat_")
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)},'komo-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>`,
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) => arg.includes("komo_pat_") || arg.startsWith("--token=")))
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 komo-design-edit block",
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
- path = credentialPath(config, env);
522
- const patPath = personalTokenPath(config, env);
523
- const { source, token, saved } = await readCredentials(path, patPath, env),
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 .komo/snapshots beside the project settings.
532
- const snapshotDirectory = () => (flags.out ? resolve(cwd, flags.out) : join(config.root ?? cwd, ".komo/snapshots"));
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 KOMO_TOKEN."
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
- const session = env.KOMO_TOKEN && !env.KOMO_TOKEN.startsWith("komo_pat_")
555
- ? env.KOMO_TOKEN
556
- : saved.session;
557
- if (session)
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(path, { force: true });
564
- await rm(patPath, { force: true });
565
- if (env.KOMO_TOKEN)
566
- console.error("KOMO_TOKEN is still set in this environment; unset it to stop using it.");
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.KOMO_BRANCH ||
38
+ setting(env, "BRANCH") ||
23
39
  env.CF_PAGES_BRANCH ||
24
40
  env.WORKERS_CI_BRANCH ||
25
41
  env.VERCEL_GIT_COMMIT_REF ||
@@ -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 `komo-design-edit` JSON block wins
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 = { komo: "design-edit", version: 1, target: { selector: target.selector } };
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
- komo: "design-edit",
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 komo-design-edit\n${json}\n\`\`\``;
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 settingsPath = resolve(cwd, ".komo/project.json");
30
- const generatedPath = resolve(cwd, "komo.config.js");
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 KOMO_BRANCH for this build.");
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("Updated komo.config.js");
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
- ".komo/owner-key",
80
- ".komo/setup.json",
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 = resolve(cwd, ".komo"),
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(resolve(cwd, ".komo/deployment.json")))
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
- "Palette is already configured. Edit .komo/project.json, then run palette sync."
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 = resolve(cwd, ".komo/setup.json");
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 './komo.config.js';\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`
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 = resolve(cwd, ".komo");
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 .komo/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`
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 = resolve(cwd, ".komo");
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 komo.config.js helper and run palette sync before your build.\n`
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 (KOMO_TOKEN, a saved access token or a login
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 KOMO_TOKEN: the proxy refuses
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
- ? token.startsWith("komo_pat_")
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
- const start = "<!-- komo:workflow:start -->";
6
- const end = "<!-- komo:workflow:end -->";
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 first = existing.indexOf(start);
24
- const last = existing.indexOf(end);
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(start, first + start.length) !== -1 ||
30
- existing.indexOf(end, last + end.length) !== -1))
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 + end.length);
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};