@dheme/react 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -259,12 +259,15 @@ function DhemeProvider({
259
259
  baseUrl,
260
260
  persist = true,
261
261
  autoApply = true,
262
+ onGenerateTheme: customGenerateTheme,
262
263
  onThemeChange,
263
264
  onModeChange,
264
265
  onError,
265
266
  children
266
267
  }) {
267
268
  const client = (0, import_react3.useMemo)(() => new import_sdk.DhemeClient({ apiKey, baseUrl }), [apiKey, baseUrl]);
269
+ const customGenerateThemeRef = (0, import_react3.useRef)(customGenerateTheme);
270
+ customGenerateThemeRef.current = customGenerateTheme;
268
271
  const [theme, setTheme] = (0, import_react3.useState)(null);
269
272
  const [mode, setModeState] = (0, import_react3.useState)(() => {
270
273
  if (typeof window === "undefined") return defaultMode;
@@ -303,14 +306,23 @@ function DhemeProvider({
303
306
  }
304
307
  }
305
308
  }, [theme, mode, autoApply]);
309
+ const fetchTheme = (0, import_react3.useCallback)(
310
+ async (params) => {
311
+ if (customGenerateThemeRef.current) {
312
+ return customGenerateThemeRef.current(params);
313
+ }
314
+ const response = await client.generateTheme(params);
315
+ return response.data;
316
+ },
317
+ [client]
318
+ );
306
319
  const generateTheme = (0, import_react3.useCallback)(
307
320
  async (params) => {
308
321
  abortRef.current?.abort();
309
322
  setIsLoading(true);
310
323
  setError(null);
311
324
  try {
312
- const response = await client.generateTheme(params);
313
- const data = response.data;
325
+ const data = await fetchTheme(params);
314
326
  setTheme(data);
315
327
  setIsReady(true);
316
328
  if (autoApplyRef.current) {
@@ -330,7 +342,7 @@ function DhemeProvider({
330
342
  setIsLoading(false);
331
343
  }
332
344
  },
333
- [client]
345
+ [fetchTheme]
334
346
  );
335
347
  const clearTheme = (0, import_react3.useCallback)(() => {
336
348
  setTheme(null);
@@ -353,9 +365,8 @@ function DhemeProvider({
353
365
  if (autoApply) applyThemeCSSVariables(cached, mode);
354
366
  const controller = new AbortController();
355
367
  abortRef.current = controller;
356
- client.generateTheme(params).then((response) => {
368
+ fetchTheme(params).then((data) => {
357
369
  if (controller.signal.aborted) return;
358
- const data = response.data;
359
370
  const cachedLight = JSON.stringify(cached.colors.light);
360
371
  const freshLight = JSON.stringify(data.colors.light);
361
372
  if (cachedLight !== freshLight) {
@@ -1137,394 +1148,379 @@ function ThemeGenerator({
1137
1148
  `;
1138
1149
  document.head.appendChild(style);
1139
1150
  }
1140
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1141
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1142
- "div",
1143
- {
1144
- onClick: () => setIsOpen(false),
1145
- style: {
1146
- position: "fixed",
1147
- inset: 0,
1148
- background: "rgba(0,0,0,0.2)",
1149
- backdropFilter: "blur(1px)",
1150
- zIndex: 40
1151
- }
1152
- }
1153
- ),
1154
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1155
- "div",
1156
- {
1157
- className: cn(className),
1158
- style: {
1159
- position: "fixed",
1160
- zIndex: 50,
1161
- display: "flex",
1162
- flexDirection: "column",
1163
- gap: "16px",
1164
- ...positionStyle
1165
- },
1166
- children: [
1167
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1168
- "div",
1169
- {
1170
- style: {
1171
- position: "absolute",
1172
- ...panelPosition,
1173
- width: isOpen ? "340px" : "180px",
1174
- height: isOpen ? "auto" : "56px",
1175
- opacity: isOpen ? 1 : 0,
1176
- transform: isOpen ? "scale(1) translateY(0)" : "scale(0.9) translateY(32px)",
1177
- pointerEvents: isOpen ? "auto" : "none",
1178
- transformOrigin: panelOrigin,
1179
- transition: "all 500ms cubic-bezier(0.32, 0.72, 0, 1)",
1180
- borderRadius: "12px",
1181
- border: "1px solid hsl(var(--border))",
1182
- background: "hsl(var(--card))",
1183
- boxShadow: "0 25px 50px rgba(0,0,0,0.15)",
1184
- overflow: "hidden"
1185
- },
1186
- children: [
1187
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1188
- "div",
1189
- {
1190
- style: {
1191
- display: "flex",
1192
- alignItems: "center",
1193
- justifyContent: "space-between",
1194
- padding: "14px 16px",
1195
- borderBottom: "1px solid hsl(var(--border))",
1196
- background: "hsl(var(--muted) / 0.3)"
1197
- },
1198
- children: [
1199
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1200
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SparklesIcon, { className: "dheme-sparkles" }),
1201
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "13px", fontWeight: 600, color: "hsl(var(--foreground))" }, children: labels.title })
1202
- ] }),
1203
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1204
- "button",
1205
- {
1206
- onClick: () => setIsOpen(false),
1207
- style: {
1208
- background: "none",
1209
- border: "none",
1210
- cursor: "pointer",
1211
- padding: "2px",
1212
- color: "hsl(var(--muted-foreground))",
1213
- display: "flex",
1214
- alignItems: "center",
1215
- justifyContent: "center",
1216
- borderRadius: "4px"
1217
- },
1218
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XIcon, {})
1219
- }
1220
- )
1221
- ]
1222
- }
1223
- ),
1224
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1225
- "div",
1226
- {
1227
- style: {
1228
- maxHeight: "calc(100vh - 200px)",
1229
- overflowY: "auto",
1230
- background: "hsl(var(--background))"
1231
- },
1232
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "16px", display: "flex", flexDirection: "column", gap: "24px" }, children: [
1233
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1234
- "p",
1235
- {
1236
- style: {
1237
- fontSize: "11px",
1238
- color: "hsl(var(--muted-foreground))",
1239
- margin: 0,
1240
- lineHeight: 1.5
1241
- },
1242
- children: labels.description
1243
- }
1244
- ),
1245
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1246
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionHeading, { children: labels.baseColors }),
1247
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1248
- ColorRow,
1249
- {
1250
- label: labels.primary,
1251
- color: localPrimary,
1252
- onColorChange: setLocalPrimary,
1253
- onInputChange: (v) => {
1254
- if (v.length === 6) setLocalPrimary(`#${v}`);
1255
- }
1256
- }
1257
- ),
1258
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1259
- ColorRow,
1260
- {
1261
- label: labels.secondary,
1262
- badge: labels.optional,
1263
- color: localSecondary,
1264
- disabled: !isSecondaryEnabled,
1265
- onColorChange: (c) => {
1266
- if (isSecondaryEnabled) setLocalSecondary(c);
1267
- },
1268
- onInputChange: (v) => {
1269
- if (isSecondaryEnabled && v.length === 6) setLocalSecondary(`#${v}`);
1270
- },
1271
- actionButton: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1272
- "button",
1273
- {
1274
- onClick: isSecondaryEnabled ? handleDisableSecondary : handleEnableSecondary,
1275
- style: {
1276
- background: "none",
1277
- border: "none",
1278
- cursor: "pointer",
1279
- padding: "2px",
1280
- color: "hsl(var(--muted-foreground))",
1281
- display: "flex",
1282
- alignItems: "center",
1283
- justifyContent: "center",
1284
- borderRadius: "4px"
1285
- },
1286
- children: isSecondaryEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {})
1287
- }
1288
- )
1289
- }
1290
- )
1291
- ] }),
1292
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1293
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionHeading, { children: labels.fineTuning }),
1294
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1295
- SliderRow,
1296
- {
1297
- label: labels.saturation,
1298
- value: localSaturation,
1299
- onChange: setLocalSaturation,
1300
- min: -100,
1301
- max: 100,
1302
- step: 1,
1303
- display: (v) => `${v > 0 ? "+" : ""}${v}%`
1304
- }
1305
- ),
1306
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1307
- SliderRow,
1308
- {
1309
- label: labels.lightness,
1310
- value: localLightness,
1311
- onChange: setLocalLightness,
1312
- min: -100,
1313
- max: 100,
1314
- step: 1,
1315
- display: (v) => `${v > 0 ? "+" : ""}${v}%`
1316
- }
1317
- ),
1318
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1319
- SliderRow,
1320
- {
1321
- label: labels.borderRadius,
1322
- value: localRadius,
1323
- onChange: setLocalRadius,
1324
- min: 0,
1325
- max: 2,
1326
- step: 0.1,
1327
- display: (v) => `${v.toFixed(1)}rem`
1328
- }
1329
- )
1330
- ] }),
1331
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1332
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionHeading, { children: labels.advancedOptions }),
1333
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1334
- ToggleRow,
1335
- {
1336
- label: labels.colorfulCard,
1337
- checked: localCardIsColored,
1338
- onChange: (v) => handleToggle("cardIsColored", v)
1339
- }
1340
- ),
1341
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1342
- ToggleRow,
1343
- {
1344
- label: labels.colorfulBackground,
1345
- checked: localBackgroundIsColored,
1346
- onChange: (v) => handleToggle("backgroundIsColored", v)
1347
- }
1348
- ),
1349
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1350
- ToggleRow,
1351
- {
1352
- label: labels.colorfulBorder,
1353
- checked: localBorderIsColored,
1354
- onChange: (v) => handleToggle("borderIsColored", v)
1355
- }
1356
- )
1357
- ] })
1358
- ] })
1359
- }
1360
- ),
1361
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1362
- "div",
1363
- {
1364
- style: {
1365
- padding: "10px 12px",
1366
- borderTop: "1px solid hsl(var(--border))",
1367
- background: "hsl(var(--muted) / 0.2)"
1368
- },
1369
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1151
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1152
+ "div",
1153
+ {
1154
+ className: cn(className),
1155
+ style: {
1156
+ position: "fixed",
1157
+ zIndex: 50,
1158
+ display: "flex",
1159
+ flexDirection: "column",
1160
+ gap: "16px",
1161
+ ...positionStyle
1162
+ },
1163
+ children: [
1164
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1165
+ "div",
1166
+ {
1167
+ style: {
1168
+ position: "absolute",
1169
+ ...panelPosition,
1170
+ width: isOpen ? "340px" : "180px",
1171
+ height: isOpen ? "auto" : "56px",
1172
+ opacity: isOpen ? 1 : 0,
1173
+ transform: isOpen ? "scale(1) translateY(0)" : "scale(0.9) translateY(32px)",
1174
+ pointerEvents: isOpen ? "auto" : "none",
1175
+ transformOrigin: panelOrigin,
1176
+ transition: "all 500ms cubic-bezier(0.32, 0.72, 0, 1)",
1177
+ borderRadius: "12px",
1178
+ border: "1px solid hsl(var(--border))",
1179
+ background: "hsl(var(--card))",
1180
+ boxShadow: "0 25px 50px rgba(0,0,0,0.15)",
1181
+ overflow: "hidden"
1182
+ },
1183
+ children: [
1184
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1185
+ "div",
1186
+ {
1187
+ style: {
1188
+ display: "flex",
1189
+ alignItems: "center",
1190
+ justifyContent: "space-between",
1191
+ padding: "14px 16px",
1192
+ borderBottom: "1px solid hsl(var(--border))",
1193
+ background: "hsl(var(--muted) / 0.3)"
1194
+ },
1195
+ children: [
1196
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1197
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SparklesIcon, { className: "dheme-sparkles" }),
1198
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "13px", fontWeight: 600, color: "hsl(var(--foreground))" }, children: labels.title })
1199
+ ] }),
1200
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1370
1201
  "button",
1371
1202
  {
1372
- onClick: handleReset,
1203
+ onClick: () => setIsOpen(false),
1373
1204
  style: {
1374
- width: "100%",
1375
- height: "32px",
1376
1205
  background: "none",
1377
- border: "1px solid hsl(var(--border))",
1378
- borderRadius: "6px",
1206
+ border: "none",
1379
1207
  cursor: "pointer",
1208
+ padding: "2px",
1209
+ color: "hsl(var(--muted-foreground))",
1380
1210
  display: "flex",
1381
1211
  alignItems: "center",
1382
1212
  justifyContent: "center",
1383
- gap: "6px",
1384
- fontSize: "12px",
1385
- color: "hsl(var(--muted-foreground))",
1386
- transition: "background 0.15s"
1387
- },
1388
- onMouseEnter: (e) => {
1389
- e.currentTarget.style.background = "hsl(var(--muted))";
1213
+ borderRadius: "4px"
1390
1214
  },
1391
- onMouseLeave: (e) => {
1392
- e.currentTarget.style.background = "none";
1393
- },
1394
- children: [
1395
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCcwIcon, {}),
1396
- labels.reset
1397
- ]
1215
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XIcon, {})
1398
1216
  }
1399
1217
  )
1400
- }
1401
- )
1402
- ]
1403
- }
1404
- ),
1405
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1406
- "div",
1407
- {
1408
- onClick: () => setIsOpen(true),
1409
- style: {
1410
- width: isOpen ? "56px" : "180px",
1411
- height: "56px",
1412
- borderRadius: "99px",
1413
- border: "1px solid hsl(var(--border))",
1414
- background: "hsl(var(--card))",
1415
- boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
1416
- cursor: isOpen ? "default" : "pointer",
1417
- position: "relative",
1418
- overflow: "hidden",
1419
- opacity: isOpen ? 0 : 1,
1420
- transform: isOpen ? "scale(0.5) translateY(16px)" : "scale(1) translateY(0)",
1421
- pointerEvents: isOpen ? "none" : "auto",
1422
- transition: "all 500ms cubic-bezier(0.32, 0.72, 0, 1)"
1423
- },
1424
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1218
+ ]
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1425
1222
  "div",
1426
1223
  {
1427
1224
  style: {
1428
- position: "absolute",
1429
- inset: 0,
1430
- display: "flex",
1431
- alignItems: "center",
1432
- justifyContent: "space-between",
1433
- padding: "0 8px 0 12px"
1225
+ maxHeight: "calc(100vh - 200px)",
1226
+ overflowY: "auto",
1227
+ background: "hsl(var(--background))"
1434
1228
  },
1435
- children: [
1229
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "16px", display: "flex", flexDirection: "column", gap: "24px" }, children: [
1436
1230
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1437
- "div",
1231
+ "p",
1438
1232
  {
1439
1233
  style: {
1440
- width: "32px",
1441
- height: "32px",
1442
- borderRadius: "50%",
1443
- background: localPrimary,
1444
- border: "1px solid hsl(var(--border))",
1445
- boxShadow: "0 0 0 2px hsl(var(--background))",
1446
- flexShrink: 0
1447
- }
1234
+ fontSize: "11px",
1235
+ color: "hsl(var(--muted-foreground))",
1236
+ margin: 0,
1237
+ lineHeight: 1.5
1238
+ },
1239
+ children: labels.description
1448
1240
  }
1449
1241
  ),
1450
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1451
- "div",
1452
- {
1453
- style: {
1454
- display: "flex",
1455
- flexDirection: "column",
1456
- gap: "2px",
1457
- flex: 1,
1458
- padding: "0 8px"
1459
- },
1460
- children: [
1461
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1462
- "span",
1463
- {
1464
- style: {
1465
- fontSize: "10px",
1466
- fontWeight: 700,
1467
- letterSpacing: "0.08em",
1468
- textTransform: "uppercase",
1469
- color: "hsl(var(--foreground))"
1470
- },
1471
- children: labels.fabPrimaryLabel
1472
- }
1473
- ),
1474
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1475
- "div",
1242
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1243
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionHeading, { children: labels.baseColors }),
1244
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1245
+ ColorRow,
1246
+ {
1247
+ label: labels.primary,
1248
+ color: localPrimary,
1249
+ onColorChange: setLocalPrimary,
1250
+ onInputChange: (v) => {
1251
+ if (v.length === 6) setLocalPrimary(`#${v}`);
1252
+ }
1253
+ }
1254
+ ),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1256
+ ColorRow,
1257
+ {
1258
+ label: labels.secondary,
1259
+ badge: labels.optional,
1260
+ color: localSecondary,
1261
+ disabled: !isSecondaryEnabled,
1262
+ onColorChange: (c) => {
1263
+ if (isSecondaryEnabled) setLocalSecondary(c);
1264
+ },
1265
+ onInputChange: (v) => {
1266
+ if (isSecondaryEnabled && v.length === 6) setLocalSecondary(`#${v}`);
1267
+ },
1268
+ actionButton: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1269
+ "button",
1476
1270
  {
1271
+ onClick: isSecondaryEnabled ? handleDisableSecondary : handleEnableSecondary,
1477
1272
  style: {
1273
+ background: "none",
1274
+ border: "none",
1275
+ cursor: "pointer",
1276
+ padding: "2px",
1277
+ color: "hsl(var(--muted-foreground))",
1478
1278
  display: "flex",
1479
- gap: "8px",
1480
- fontSize: "10px",
1481
- fontFamily: "monospace",
1482
- color: "hsl(var(--muted-foreground))"
1279
+ alignItems: "center",
1280
+ justifyContent: "center",
1281
+ borderRadius: "4px"
1483
1282
  },
1484
- children: [
1485
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1486
- "S:",
1487
- localSaturation[0] > 0 ? "+" : "",
1488
- localSaturation[0],
1489
- "%"
1490
- ] }),
1491
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1492
- "L:",
1493
- localLightness[0] > 0 ? "+" : "",
1494
- localLightness[0],
1495
- "%"
1496
- ] })
1497
- ]
1283
+ children: isSecondaryEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(XIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, {})
1498
1284
  }
1499
1285
  )
1500
- ]
1501
- }
1502
- ),
1503
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1504
- "div",
1505
- {
1506
- style: {
1507
- width: "32px",
1508
- height: "32px",
1509
- display: "flex",
1510
- alignItems: "center",
1511
- justifyContent: "center",
1512
- borderRadius: "50%",
1513
- background: "hsl(var(--muted) / 0.5)",
1514
- flexShrink: 0
1515
- },
1516
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUpIcon, {})
1517
- }
1518
- )
1519
- ]
1286
+ }
1287
+ )
1288
+ ] }),
1289
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionHeading, { children: labels.fineTuning }),
1291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1292
+ SliderRow,
1293
+ {
1294
+ label: labels.saturation,
1295
+ value: localSaturation,
1296
+ onChange: setLocalSaturation,
1297
+ min: -100,
1298
+ max: 100,
1299
+ step: 1,
1300
+ display: (v) => `${v > 0 ? "+" : ""}${v}%`
1301
+ }
1302
+ ),
1303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1304
+ SliderRow,
1305
+ {
1306
+ label: labels.lightness,
1307
+ value: localLightness,
1308
+ onChange: setLocalLightness,
1309
+ min: -100,
1310
+ max: 100,
1311
+ step: 1,
1312
+ display: (v) => `${v > 0 ? "+" : ""}${v}%`
1313
+ }
1314
+ ),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1316
+ SliderRow,
1317
+ {
1318
+ label: labels.borderRadius,
1319
+ value: localRadius,
1320
+ onChange: setLocalRadius,
1321
+ min: 0,
1322
+ max: 2,
1323
+ step: 0.1,
1324
+ display: (v) => `${v.toFixed(1)}rem`
1325
+ }
1326
+ )
1327
+ ] }),
1328
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
1329
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SectionHeading, { children: labels.advancedOptions }),
1330
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1331
+ ToggleRow,
1332
+ {
1333
+ label: labels.colorfulCard,
1334
+ checked: localCardIsColored,
1335
+ onChange: (v) => handleToggle("cardIsColored", v)
1336
+ }
1337
+ ),
1338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1339
+ ToggleRow,
1340
+ {
1341
+ label: labels.colorfulBackground,
1342
+ checked: localBackgroundIsColored,
1343
+ onChange: (v) => handleToggle("backgroundIsColored", v)
1344
+ }
1345
+ ),
1346
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1347
+ ToggleRow,
1348
+ {
1349
+ label: labels.colorfulBorder,
1350
+ checked: localBorderIsColored,
1351
+ onChange: (v) => handleToggle("borderIsColored", v)
1352
+ }
1353
+ )
1354
+ ] })
1355
+ ] })
1356
+ }
1357
+ ),
1358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1359
+ "div",
1360
+ {
1361
+ style: {
1362
+ padding: "10px 12px",
1363
+ borderTop: "1px solid hsl(var(--border))",
1364
+ background: "hsl(var(--muted) / 0.2)"
1365
+ },
1366
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1367
+ "button",
1368
+ {
1369
+ onClick: handleReset,
1370
+ style: {
1371
+ width: "100%",
1372
+ height: "32px",
1373
+ background: "none",
1374
+ border: "1px solid hsl(var(--border))",
1375
+ borderRadius: "6px",
1376
+ cursor: "pointer",
1377
+ display: "flex",
1378
+ alignItems: "center",
1379
+ justifyContent: "center",
1380
+ gap: "6px",
1381
+ fontSize: "12px",
1382
+ color: "hsl(var(--muted-foreground))",
1383
+ transition: "background 0.15s"
1384
+ },
1385
+ onMouseEnter: (e) => {
1386
+ e.currentTarget.style.background = "hsl(var(--muted))";
1387
+ },
1388
+ onMouseLeave: (e) => {
1389
+ e.currentTarget.style.background = "none";
1390
+ },
1391
+ children: [
1392
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RotateCcwIcon, {}),
1393
+ labels.reset
1394
+ ]
1395
+ }
1396
+ )
1520
1397
  }
1521
1398
  )
1522
- }
1523
- )
1524
- ]
1525
- }
1526
- )
1527
- ] });
1399
+ ]
1400
+ }
1401
+ ),
1402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1403
+ "div",
1404
+ {
1405
+ onClick: () => setIsOpen(true),
1406
+ style: {
1407
+ width: isOpen ? "56px" : "180px",
1408
+ height: "56px",
1409
+ borderRadius: "99px",
1410
+ border: "1px solid hsl(var(--border))",
1411
+ background: "hsl(var(--card))",
1412
+ boxShadow: "0 4px 12px rgba(0,0,0,0.1)",
1413
+ cursor: isOpen ? "default" : "pointer",
1414
+ position: "relative",
1415
+ overflow: "hidden",
1416
+ opacity: isOpen ? 0 : 1,
1417
+ transform: isOpen ? "scale(0.5) translateY(16px)" : "scale(1) translateY(0)",
1418
+ pointerEvents: isOpen ? "none" : "auto",
1419
+ transition: "all 500ms cubic-bezier(0.32, 0.72, 0, 1)"
1420
+ },
1421
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1422
+ "div",
1423
+ {
1424
+ style: {
1425
+ position: "absolute",
1426
+ inset: 0,
1427
+ display: "flex",
1428
+ alignItems: "center",
1429
+ justifyContent: "space-between",
1430
+ padding: "0 8px 0 12px"
1431
+ },
1432
+ children: [
1433
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1434
+ "div",
1435
+ {
1436
+ style: {
1437
+ width: "32px",
1438
+ height: "32px",
1439
+ borderRadius: "50%",
1440
+ background: localPrimary,
1441
+ border: "1px solid hsl(var(--border))",
1442
+ boxShadow: "0 0 0 2px hsl(var(--background))",
1443
+ flexShrink: 0
1444
+ }
1445
+ }
1446
+ ),
1447
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1448
+ "div",
1449
+ {
1450
+ style: {
1451
+ display: "flex",
1452
+ flexDirection: "column",
1453
+ gap: "2px",
1454
+ flex: 1,
1455
+ padding: "0 8px"
1456
+ },
1457
+ children: [
1458
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1459
+ "span",
1460
+ {
1461
+ style: {
1462
+ fontSize: "10px",
1463
+ fontWeight: 700,
1464
+ letterSpacing: "0.08em",
1465
+ textTransform: "uppercase",
1466
+ color: "hsl(var(--foreground))"
1467
+ },
1468
+ children: labels.fabPrimaryLabel
1469
+ }
1470
+ ),
1471
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1472
+ "div",
1473
+ {
1474
+ style: {
1475
+ display: "flex",
1476
+ gap: "8px",
1477
+ fontSize: "10px",
1478
+ fontFamily: "monospace",
1479
+ color: "hsl(var(--muted-foreground))"
1480
+ },
1481
+ children: [
1482
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1483
+ "S:",
1484
+ localSaturation[0] > 0 ? "+" : "",
1485
+ localSaturation[0],
1486
+ "%"
1487
+ ] }),
1488
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
1489
+ "L:",
1490
+ localLightness[0] > 0 ? "+" : "",
1491
+ localLightness[0],
1492
+ "%"
1493
+ ] })
1494
+ ]
1495
+ }
1496
+ )
1497
+ ]
1498
+ }
1499
+ ),
1500
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1501
+ "div",
1502
+ {
1503
+ style: {
1504
+ width: "32px",
1505
+ height: "32px",
1506
+ display: "flex",
1507
+ alignItems: "center",
1508
+ justifyContent: "center",
1509
+ borderRadius: "50%",
1510
+ background: "hsl(var(--muted) / 0.5)",
1511
+ flexShrink: 0
1512
+ },
1513
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUpIcon, {})
1514
+ }
1515
+ )
1516
+ ]
1517
+ }
1518
+ )
1519
+ }
1520
+ )
1521
+ ]
1522
+ }
1523
+ ) });
1528
1524
  }
1529
1525
 
1530
1526
  // src/hooks/useTheme.ts