@newtonedev/editor 0.1.5 → 0.1.6

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
@@ -1,5 +1,5 @@
1
1
  import { useState, useCallback, useRef, useMemo, useEffect } from 'react';
2
- import { getComponent, useTokens, ColorScaleSlider, TextInput, HueSlider, Slider, Select, Toggle, GOOGLE_FONTS, SYSTEM_FONTS, Button, CATEGORIES, getComponentsByCategory, Icon, Text, getCategory, generateComponentCode, NewtoneProvider, Wrapper, Frame, Card } from '@newtonedev/components';
2
+ import { getComponent, useTokens, ColorScaleSlider, TextInput, HueSlider, Slider, Select, Toggle, GOOGLE_FONTS, SYSTEM_FONTS, Icon, Button, CATEGORIES, getComponentsByCategory, Text, getCategory, generateComponentCode, NewtoneProvider, Wrapper, Frame, Card, ICON_CATALOG } from '@newtonedev/components';
3
3
  import { useConfigurator, usePreviewColors, SEMANTIC_HUE_RANGES, useWcagValidation, traditionalHueToOklch, hexToPaletteParams } from '@newtonedev/configurator';
4
4
  import { srgbToHex, resolveLightness, findMaxChromaInGamut, clampSrgb, oklchToSrgb, HUE_GRADING_STRENGTH_HARD, HUE_GRADING_STRENGTH_MEDIUM, HUE_GRADING_STRENGTH_LOW, HUE_GRADING_EASING_POWER } from 'newtone';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -336,9 +336,19 @@ function useEditorState({
336
336
  initOverridesFromVariant(sidebarSelection.componentId);
337
337
  }
338
338
  }, [sidebarSelection, initOverridesFromVariant]);
339
- const handlePropOverride = useCallback((propName, value) => {
340
- setPropOverrides((prev) => ({ ...prev, [propName]: value }));
341
- }, []);
339
+ const handlePropOverride = useCallback(
340
+ (propName, value) => {
341
+ setPropOverrides((prev) => ({ ...prev, [propName]: value }));
342
+ setSidebarSelection((prev) => {
343
+ if (prev !== null) return prev;
344
+ if (previewView.kind === "component") {
345
+ return { scope: "component", componentId: previewView.componentId };
346
+ }
347
+ return prev;
348
+ });
349
+ },
350
+ [previewView]
351
+ );
342
352
  const handleResetOverrides = useCallback(() => {
343
353
  if (sidebarSelection?.scope === "variant") {
344
354
  initOverridesFromVariant(
@@ -2022,20 +2032,15 @@ function PresetSelector({
2022
2032
  }
2023
2033
  ),
2024
2034
  /* @__PURE__ */ jsx(
2025
- "svg",
2035
+ Icon,
2026
2036
  {
2027
- width: 10,
2028
- height: 10,
2029
- viewBox: "0 0 24 24",
2030
- fill: "none",
2031
- stroke: "currentColor",
2032
- strokeWidth: 2,
2037
+ name: "expand_more",
2038
+ size: 14,
2033
2039
  style: {
2034
2040
  transform: isOpen ? "rotate(180deg)" : "none",
2035
2041
  transition: "transform 150ms ease",
2036
2042
  flexShrink: 0
2037
- },
2038
- children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
2043
+ }
2039
2044
  }
2040
2045
  )
2041
2046
  ]
@@ -2183,20 +2188,7 @@ function PresetSelector({
2183
2188
  borderRadius: 4,
2184
2189
  flexShrink: 0
2185
2190
  },
2186
- children: /* @__PURE__ */ jsxs(
2187
- "svg",
2188
- {
2189
- width: 14,
2190
- height: 14,
2191
- viewBox: "0 0 24 24",
2192
- fill: "currentColor",
2193
- children: [
2194
- /* @__PURE__ */ jsx("circle", { cx: 12, cy: 5, r: 2 }),
2195
- /* @__PURE__ */ jsx("circle", { cx: 12, cy: 12, r: 2 }),
2196
- /* @__PURE__ */ jsx("circle", { cx: 12, cy: 19, r: 2 })
2197
- ]
2198
- }
2199
- )
2191
+ children: /* @__PURE__ */ jsx(Icon, { name: "more_vert", size: 14, color: textSecondary })
2200
2192
  }
2201
2193
  )
2202
2194
  ] }),
@@ -2315,21 +2307,7 @@ function PresetSelector({
2315
2307
  cursor: "pointer"
2316
2308
  },
2317
2309
  children: [
2318
- /* @__PURE__ */ jsxs(
2319
- "svg",
2320
- {
2321
- width: 14,
2322
- height: 14,
2323
- viewBox: "0 0 24 24",
2324
- fill: "none",
2325
- stroke: "currentColor",
2326
- strokeWidth: 2,
2327
- children: [
2328
- /* @__PURE__ */ jsx("line", { x1: 12, y1: 5, x2: 12, y2: 19 }),
2329
- /* @__PURE__ */ jsx("line", { x1: 5, y1: 12, x2: 19, y2: 12 })
2330
- ]
2331
- }
2332
- ),
2310
+ /* @__PURE__ */ jsx(Icon, { name: "add", size: 14, color: textSecondary }),
2333
2311
  "New preset"
2334
2312
  ]
2335
2313
  }
@@ -2341,67 +2319,12 @@ function PresetSelector({
2341
2319
  }
2342
2320
  var SIDEBAR_WIDTH2 = 360;
2343
2321
  var ACCORDION_SECTIONS = [
2344
- { id: "dynamic-range", label: "Dynamic Range" },
2345
- { id: "colors", label: "Colors" },
2346
- { id: "fonts", label: "Fonts" },
2347
- { id: "icons", label: "Icons" },
2348
- { id: "others", label: "Others" }
2322
+ { id: "dynamic-range", label: "Dynamic Range", icon: "contrast" },
2323
+ { id: "colors", label: "Colors", icon: "palette" },
2324
+ { id: "fonts", label: "Fonts", icon: "text_fields" },
2325
+ { id: "icons", label: "Icons", icon: "grid_view" },
2326
+ { id: "others", label: "Others", icon: "tune" }
2349
2327
  ];
2350
- function SectionIcon({ id }) {
2351
- const props = {
2352
- width: 16,
2353
- height: 16,
2354
- viewBox: "0 0 24 24",
2355
- fill: "none",
2356
- stroke: "currentColor",
2357
- strokeWidth: 2,
2358
- strokeLinecap: "round",
2359
- strokeLinejoin: "round"
2360
- };
2361
- switch (id) {
2362
- case "dynamic-range":
2363
- return /* @__PURE__ */ jsxs("svg", { ...props, children: [
2364
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "5" }),
2365
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "1", x2: "12", y2: "3" }),
2366
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "21", x2: "12", y2: "23" }),
2367
- /* @__PURE__ */ jsx("line", { x1: "4.22", y1: "4.22", x2: "5.64", y2: "5.64" }),
2368
- /* @__PURE__ */ jsx("line", { x1: "18.36", y1: "18.36", x2: "19.78", y2: "19.78" }),
2369
- /* @__PURE__ */ jsx("line", { x1: "1", y1: "12", x2: "3", y2: "12" }),
2370
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "23", y2: "12" }),
2371
- /* @__PURE__ */ jsx("line", { x1: "4.22", y1: "19.78", x2: "5.64", y2: "18.36" }),
2372
- /* @__PURE__ */ jsx("line", { x1: "18.36", y1: "5.64", x2: "19.78", y2: "4.22" })
2373
- ] });
2374
- case "colors":
2375
- return /* @__PURE__ */ jsx("svg", { ...props, children: /* @__PURE__ */ jsx("path", { d: "M12 2.69l5.66 5.66a8 8 0 1 1-11.31 0z" }) });
2376
- case "fonts":
2377
- return /* @__PURE__ */ jsxs("svg", { ...props, children: [
2378
- /* @__PURE__ */ jsx("polyline", { points: "4 7 4 4 20 4 20 7" }),
2379
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "20", x2: "15", y2: "20" }),
2380
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "4", x2: "12", y2: "20" })
2381
- ] });
2382
- case "icons":
2383
- return /* @__PURE__ */ jsxs("svg", { ...props, children: [
2384
- /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "7", height: "7" }),
2385
- /* @__PURE__ */ jsx("rect", { x: "14", y: "3", width: "7", height: "7" }),
2386
- /* @__PURE__ */ jsx("rect", { x: "3", y: "14", width: "7", height: "7" }),
2387
- /* @__PURE__ */ jsx("rect", { x: "14", y: "14", width: "7", height: "7" })
2388
- ] });
2389
- case "others":
2390
- return /* @__PURE__ */ jsxs("svg", { ...props, children: [
2391
- /* @__PURE__ */ jsx("line", { x1: "4", y1: "21", x2: "4", y2: "14" }),
2392
- /* @__PURE__ */ jsx("line", { x1: "4", y1: "10", x2: "4", y2: "3" }),
2393
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "21", x2: "12", y2: "12" }),
2394
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "3" }),
2395
- /* @__PURE__ */ jsx("line", { x1: "20", y1: "21", x2: "20", y2: "16" }),
2396
- /* @__PURE__ */ jsx("line", { x1: "20", y1: "12", x2: "20", y2: "3" }),
2397
- /* @__PURE__ */ jsx("line", { x1: "1", y1: "14", x2: "7", y2: "14" }),
2398
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "8", x2: "15", y2: "8" }),
2399
- /* @__PURE__ */ jsx("line", { x1: "17", y1: "16", x2: "23", y2: "16" })
2400
- ] });
2401
- default:
2402
- return null;
2403
- }
2404
- }
2405
2328
  function Sidebar({
2406
2329
  state,
2407
2330
  dispatch,
@@ -2549,23 +2472,18 @@ function Sidebar({
2549
2472
  },
2550
2473
  children: [
2551
2474
  /* @__PURE__ */ jsxs("span", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2552
- /* @__PURE__ */ jsx(SectionIcon, { id: section.id }),
2475
+ /* @__PURE__ */ jsx(Icon, { name: section.icon, size: 16 }),
2553
2476
  section.label
2554
2477
  ] }),
2555
2478
  /* @__PURE__ */ jsx(
2556
- "svg",
2479
+ Icon,
2557
2480
  {
2558
- width: 12,
2559
- height: 12,
2560
- viewBox: "0 0 24 24",
2561
- fill: "none",
2562
- stroke: "currentColor",
2563
- strokeWidth: 2,
2481
+ name: "expand_more",
2482
+ size: 16,
2564
2483
  style: {
2565
2484
  transform: isOpen ? "rotate(180deg)" : "none",
2566
2485
  transition: "transform 150ms ease"
2567
- },
2568
- children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
2486
+ }
2569
2487
  }
2570
2488
  )
2571
2489
  ]
@@ -3230,16 +3148,238 @@ function CategoryView({
3230
3148
  )
3231
3149
  ] });
3232
3150
  }
3151
+ function IconBrowserView({
3152
+ selectedIconName,
3153
+ onIconSelect
3154
+ }) {
3155
+ const tokens = useTokens();
3156
+ const [search, setSearch] = useState("");
3157
+ const [hoveredIcon, setHoveredIcon] = useState(null);
3158
+ const scrollRef = useRef(null);
3159
+ const filteredCategories = useMemo(() => {
3160
+ const q = search.toLowerCase().trim();
3161
+ if (!q) return ICON_CATALOG;
3162
+ return ICON_CATALOG.map((cat) => ({
3163
+ ...cat,
3164
+ icons: cat.icons.filter((name) => name.includes(q))
3165
+ })).filter((cat) => cat.icons.length > 0);
3166
+ }, [search]);
3167
+ useEffect(() => {
3168
+ if (!selectedIconName || !scrollRef.current) return;
3169
+ const el = scrollRef.current.querySelector(
3170
+ `[data-icon="${selectedIconName}"]`
3171
+ );
3172
+ if (el) {
3173
+ el.scrollIntoView({ behavior: "smooth", block: "nearest" });
3174
+ }
3175
+ }, [selectedIconName]);
3176
+ const accentColor = srgbToHex(tokens.accent.fill.srgb);
3177
+ return /* @__PURE__ */ jsxs(
3178
+ "div",
3179
+ {
3180
+ style: {
3181
+ display: "flex",
3182
+ flexDirection: "column",
3183
+ height: "100%",
3184
+ minHeight: 0
3185
+ },
3186
+ children: [
3187
+ /* @__PURE__ */ jsx("div", { style: { padding: "0 32px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
3188
+ /* @__PURE__ */ jsx(
3189
+ Icon,
3190
+ {
3191
+ name: "search",
3192
+ size: 18,
3193
+ color: srgbToHex(tokens.textTertiary.srgb),
3194
+ style: {
3195
+ position: "absolute",
3196
+ left: 10,
3197
+ top: 9,
3198
+ pointerEvents: "none"
3199
+ }
3200
+ }
3201
+ ),
3202
+ /* @__PURE__ */ jsx(
3203
+ "input",
3204
+ {
3205
+ type: "text",
3206
+ placeholder: "Search icons...",
3207
+ value: search,
3208
+ onChange: (e) => setSearch(e.target.value),
3209
+ style: {
3210
+ width: "100%",
3211
+ padding: "8px 12px 8px 34px",
3212
+ borderRadius: 8,
3213
+ border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
3214
+ backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
3215
+ color: srgbToHex(tokens.textPrimary.srgb),
3216
+ fontSize: 13,
3217
+ boxSizing: "border-box",
3218
+ outline: "none"
3219
+ }
3220
+ }
3221
+ )
3222
+ ] }) }),
3223
+ /* @__PURE__ */ jsxs(
3224
+ "div",
3225
+ {
3226
+ ref: scrollRef,
3227
+ style: {
3228
+ flex: 1,
3229
+ overflowY: "auto",
3230
+ padding: "16px 32px 32px"
3231
+ },
3232
+ children: [
3233
+ filteredCategories.length === 0 && /* @__PURE__ */ jsx(
3234
+ "p",
3235
+ {
3236
+ style: {
3237
+ fontSize: 13,
3238
+ color: srgbToHex(tokens.textTertiary.srgb),
3239
+ textAlign: "center",
3240
+ marginTop: 32
3241
+ },
3242
+ children: "No icons found"
3243
+ }
3244
+ ),
3245
+ filteredCategories.map((category) => /* @__PURE__ */ jsxs("div", { style: { marginBottom: 24 }, children: [
3246
+ /* @__PURE__ */ jsx(
3247
+ "h3",
3248
+ {
3249
+ style: {
3250
+ fontSize: 12,
3251
+ fontWeight: 600,
3252
+ color: srgbToHex(tokens.textSecondary.srgb),
3253
+ textTransform: "uppercase",
3254
+ letterSpacing: 0.5,
3255
+ margin: "0 0 8px"
3256
+ },
3257
+ children: category.label
3258
+ }
3259
+ ),
3260
+ /* @__PURE__ */ jsx(
3261
+ "div",
3262
+ {
3263
+ style: {
3264
+ display: "grid",
3265
+ gridTemplateColumns: "repeat(auto-fill, minmax(80px, 1fr))",
3266
+ gap: 6
3267
+ },
3268
+ children: category.icons.map((name) => {
3269
+ const isSelected = selectedIconName === name;
3270
+ const isHovered = hoveredIcon === name;
3271
+ const borderColor = isSelected ? accentColor : isHovered ? `${accentColor}66` : "transparent";
3272
+ return /* @__PURE__ */ jsxs(
3273
+ "button",
3274
+ {
3275
+ "data-icon": name,
3276
+ onClick: () => onIconSelect(name),
3277
+ onMouseEnter: () => setHoveredIcon(name),
3278
+ onMouseLeave: () => setHoveredIcon(null),
3279
+ style: {
3280
+ display: "flex",
3281
+ flexDirection: "column",
3282
+ alignItems: "center",
3283
+ justifyContent: "center",
3284
+ gap: 4,
3285
+ padding: "8px 4px 6px",
3286
+ borderRadius: 8,
3287
+ border: `2px solid ${borderColor}`,
3288
+ backgroundColor: isSelected ? srgbToHex(tokens.backgroundElevated.srgb) : "transparent",
3289
+ cursor: "pointer",
3290
+ transition: "border-color 150ms ease"
3291
+ },
3292
+ children: [
3293
+ /* @__PURE__ */ jsx(Icon, { name, size: 40 }),
3294
+ /* @__PURE__ */ jsx(
3295
+ "span",
3296
+ {
3297
+ style: {
3298
+ fontSize: 10,
3299
+ color: isSelected ? accentColor : srgbToHex(tokens.textTertiary.srgb),
3300
+ fontWeight: isSelected ? 600 : 400,
3301
+ maxWidth: "100%",
3302
+ overflow: "hidden",
3303
+ textOverflow: "ellipsis",
3304
+ whiteSpace: "nowrap"
3305
+ },
3306
+ children: name
3307
+ }
3308
+ )
3309
+ ]
3310
+ },
3311
+ name
3312
+ );
3313
+ })
3314
+ }
3315
+ )
3316
+ ] }, category.id))
3317
+ ]
3318
+ }
3319
+ )
3320
+ ]
3321
+ }
3322
+ );
3323
+ }
3233
3324
  function ComponentDetailView({
3234
3325
  componentId,
3235
3326
  selectedVariantId,
3327
+ onSelectVariant,
3236
3328
  propOverrides,
3237
- onSelectVariant
3329
+ onPropOverride
3238
3330
  }) {
3239
3331
  const tokens = useTokens();
3240
3332
  const component = getComponent(componentId);
3241
3333
  const [hoveredId, setHoveredId] = useState(null);
3242
3334
  if (!component) return null;
3335
+ if (componentId === "icon" && propOverrides && onPropOverride) {
3336
+ return /* @__PURE__ */ jsxs(
3337
+ "div",
3338
+ {
3339
+ style: {
3340
+ padding: "32px 0 0",
3341
+ height: "100%",
3342
+ display: "flex",
3343
+ flexDirection: "column"
3344
+ },
3345
+ children: [
3346
+ /* @__PURE__ */ jsxs("div", { style: { padding: "0 32px", marginBottom: 24 }, children: [
3347
+ /* @__PURE__ */ jsx(
3348
+ "h2",
3349
+ {
3350
+ style: {
3351
+ fontSize: 22,
3352
+ fontWeight: 700,
3353
+ color: srgbToHex(tokens.textPrimary.srgb),
3354
+ margin: 0,
3355
+ marginBottom: 4
3356
+ },
3357
+ children: component.name
3358
+ }
3359
+ ),
3360
+ /* @__PURE__ */ jsx(
3361
+ "p",
3362
+ {
3363
+ style: {
3364
+ fontSize: 14,
3365
+ color: srgbToHex(tokens.textSecondary.srgb),
3366
+ margin: 0
3367
+ },
3368
+ children: component.description
3369
+ }
3370
+ )
3371
+ ] }),
3372
+ /* @__PURE__ */ jsx(
3373
+ IconBrowserView,
3374
+ {
3375
+ selectedIconName: propOverrides.name ?? "add",
3376
+ onIconSelect: (name) => onPropOverride("name", name)
3377
+ }
3378
+ )
3379
+ ]
3380
+ }
3381
+ );
3382
+ }
3243
3383
  const interactiveColor = srgbToHex(tokens.accent.fill.srgb);
3244
3384
  return /* @__PURE__ */ jsxs("div", { style: { padding: 32 }, children: [
3245
3385
  /* @__PURE__ */ jsx(
@@ -3315,7 +3455,7 @@ function ComponentDetailView({
3315
3455
  ComponentRenderer,
3316
3456
  {
3317
3457
  componentId,
3318
- props: isSelected && propOverrides ? { ...variant.props, ...propOverrides } : variant.props
3458
+ props: variant.props
3319
3459
  }
3320
3460
  )
3321
3461
  }
@@ -3343,9 +3483,10 @@ function ComponentDetailView({
3343
3483
  function PreviewWindow({
3344
3484
  view,
3345
3485
  selectedVariantId,
3346
- propOverrides,
3347
3486
  onNavigate,
3348
- onSelectVariant
3487
+ onSelectVariant,
3488
+ propOverrides,
3489
+ onPropOverride
3349
3490
  }) {
3350
3491
  const tokens = useTokens();
3351
3492
  const handleNavigateToCategory = useCallback(
@@ -3385,8 +3526,9 @@ function PreviewWindow({
3385
3526
  {
3386
3527
  componentId: view.componentId,
3387
3528
  selectedVariantId,
3529
+ onSelectVariant,
3388
3530
  propOverrides,
3389
- onSelectVariant
3531
+ onPropOverride
3390
3532
  }
3391
3533
  )
3392
3534
  ] })
@@ -3394,50 +3536,89 @@ function PreviewWindow({
3394
3536
  );
3395
3537
  }
3396
3538
  function CopyButton({ text }) {
3539
+ const tokens = useTokens();
3397
3540
  const [copied, setCopied] = useState(false);
3398
3541
  const handleCopy = useCallback(async () => {
3399
3542
  await navigator.clipboard.writeText(text);
3400
3543
  setCopied(true);
3401
3544
  setTimeout(() => setCopied(false), 2e3);
3402
3545
  }, [text]);
3403
- return /* @__PURE__ */ jsx(Button, { variant: "tertiary", semantic: "neutral", size: "sm", icon: copied ? "check" : "content_copy", onPress: handleCopy, children: copied ? "Copied!" : "Copy" });
3546
+ return /* @__PURE__ */ jsx(
3547
+ "button",
3548
+ {
3549
+ onClick: handleCopy,
3550
+ "aria-label": copied ? "Copied" : "Copy code",
3551
+ style: {
3552
+ background: "none",
3553
+ border: "none",
3554
+ cursor: "pointer",
3555
+ padding: 4,
3556
+ display: "flex",
3557
+ alignItems: "center",
3558
+ justifyContent: "center",
3559
+ color: srgbToHex(
3560
+ copied ? tokens.accent.fill.srgb : tokens.textTertiary.srgb
3561
+ ),
3562
+ transition: "color 150ms ease"
3563
+ },
3564
+ children: /* @__PURE__ */ jsx(
3565
+ Icon,
3566
+ {
3567
+ name: copied ? "check" : "content_copy",
3568
+ size: 16,
3569
+ color: srgbToHex(
3570
+ copied ? tokens.accent.fill.srgb : tokens.textTertiary.srgb
3571
+ )
3572
+ }
3573
+ )
3574
+ }
3575
+ );
3404
3576
  }
3405
3577
  function CodeBlock({
3406
3578
  code
3407
3579
  }) {
3408
3580
  const tokens = useTokens();
3409
- return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
3410
- /* @__PURE__ */ jsx(
3411
- "div",
3412
- {
3413
- style: {
3414
- position: "absolute",
3415
- top: 8,
3416
- right: 8
3417
- },
3418
- children: /* @__PURE__ */ jsx(CopyButton, { text: code })
3419
- }
3420
- ),
3421
- /* @__PURE__ */ jsx(
3422
- "pre",
3423
- {
3424
- style: {
3425
- backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
3426
- border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
3427
- borderRadius: 8,
3428
- padding: 16,
3429
- paddingRight: 80,
3430
- overflow: "auto",
3431
- fontSize: 13,
3432
- lineHeight: 1.5,
3433
- fontFamily: "'SF Mono', 'Fira Code', 'Fira Mono', Menlo, monospace",
3434
- color: srgbToHex(tokens.textPrimary.srgb),
3435
- margin: 0
3436
- },
3437
- children: /* @__PURE__ */ jsx("code", { children: code })
3438
- }
3439
- )
3440
- ] });
3581
+ return /* @__PURE__ */ jsxs(
3582
+ "div",
3583
+ {
3584
+ style: {
3585
+ backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
3586
+ border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
3587
+ borderRadius: 8,
3588
+ overflow: "hidden"
3589
+ },
3590
+ children: [
3591
+ /* @__PURE__ */ jsx(
3592
+ "div",
3593
+ {
3594
+ style: {
3595
+ display: "flex",
3596
+ justifyContent: "flex-end",
3597
+ padding: "4px 8px",
3598
+ borderBottom: `1px solid ${srgbToHex(tokens.border.srgb)}`
3599
+ },
3600
+ children: /* @__PURE__ */ jsx(CopyButton, { text: code })
3601
+ }
3602
+ ),
3603
+ /* @__PURE__ */ jsx(
3604
+ "pre",
3605
+ {
3606
+ style: {
3607
+ padding: "12px 16px",
3608
+ whiteSpace: "pre-wrap",
3609
+ wordBreak: "break-word",
3610
+ fontSize: 13,
3611
+ lineHeight: 1.5,
3612
+ fontFamily: "'SF Mono', 'Fira Code', 'Fira Mono', Menlo, monospace",
3613
+ color: srgbToHex(tokens.textPrimary.srgb),
3614
+ margin: 0
3615
+ },
3616
+ children: /* @__PURE__ */ jsx("code", { children: code })
3617
+ }
3618
+ )
3619
+ ]
3620
+ }
3621
+ );
3441
3622
  }
3442
3623
  function RightSidebar({
3443
3624
  selection,
@@ -3445,7 +3626,9 @@ function RightSidebar({
3445
3626
  onPropOverride,
3446
3627
  onResetOverrides,
3447
3628
  onClose,
3448
- onScopeToComponent
3629
+ onScopeToComponent,
3630
+ previewConfig,
3631
+ colorMode
3449
3632
  }) {
3450
3633
  const tokens = useTokens();
3451
3634
  const visible = selection !== null;
@@ -3498,23 +3681,7 @@ function RightSidebar({
3498
3681
  display: "flex",
3499
3682
  alignItems: "center"
3500
3683
  },
3501
- children: /* @__PURE__ */ jsxs(
3502
- "svg",
3503
- {
3504
- width: 16,
3505
- height: 16,
3506
- viewBox: "0 0 24 24",
3507
- fill: "none",
3508
- stroke: "currentColor",
3509
- strokeWidth: 2,
3510
- strokeLinecap: "round",
3511
- strokeLinejoin: "round",
3512
- children: [
3513
- /* @__PURE__ */ jsx("line", { x1: "19", y1: "12", x2: "5", y2: "12" }),
3514
- /* @__PURE__ */ jsx("polyline", { points: "12 19 5 12 12 5" })
3515
- ]
3516
- }
3517
- )
3684
+ children: /* @__PURE__ */ jsx(Icon, { name: "arrow_back", size: 16, color: srgbToHex(tokens.textSecondary.srgb) })
3518
3685
  }
3519
3686
  ),
3520
3687
  selection.scope === "variant" && variant ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -3583,6 +3750,32 @@ function RightSidebar({
3583
3750
  padding: 16
3584
3751
  },
3585
3752
  children: [
3753
+ /* @__PURE__ */ jsx(
3754
+ "div",
3755
+ {
3756
+ style: {
3757
+ marginBottom: 20,
3758
+ borderRadius: 8,
3759
+ border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
3760
+ overflow: "hidden"
3761
+ },
3762
+ children: /* @__PURE__ */ jsx(
3763
+ NewtoneProvider,
3764
+ {
3765
+ config: previewConfig,
3766
+ initialMode: colorMode,
3767
+ children: /* @__PURE__ */ jsx(
3768
+ PreviewSurface,
3769
+ {
3770
+ componentId: selection.componentId,
3771
+ propOverrides
3772
+ }
3773
+ )
3774
+ },
3775
+ colorMode
3776
+ )
3777
+ }
3778
+ ),
3586
3779
  /* @__PURE__ */ jsx(
3587
3780
  "h3",
3588
3781
  {
@@ -3650,6 +3843,26 @@ function RightSidebar({
3650
3843
  }
3651
3844
  );
3652
3845
  }
3846
+ function PreviewSurface({
3847
+ componentId,
3848
+ propOverrides
3849
+ }) {
3850
+ const previewTokens = useTokens();
3851
+ return /* @__PURE__ */ jsx(
3852
+ "div",
3853
+ {
3854
+ style: {
3855
+ display: "flex",
3856
+ alignItems: "center",
3857
+ justifyContent: "center",
3858
+ padding: 24,
3859
+ height: 120,
3860
+ backgroundColor: srgbToHex(previewTokens.backgroundElevated.srgb)
3861
+ },
3862
+ children: /* @__PURE__ */ jsx(ComponentRenderer, { componentId, props: propOverrides })
3863
+ }
3864
+ );
3865
+ }
3653
3866
  function PropControl({
3654
3867
  prop,
3655
3868
  value,
@@ -3677,41 +3890,17 @@ function PropControl({
3677
3890
  boxSizing: "border-box"
3678
3891
  };
3679
3892
  return /* @__PURE__ */ jsxs("div", { children: [
3680
- /* @__PURE__ */ jsxs(
3681
- "div",
3893
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: 4 }, children: /* @__PURE__ */ jsx(
3894
+ "span",
3682
3895
  {
3683
3896
  style: {
3684
- display: "flex",
3685
- alignItems: "center",
3686
- justifyContent: "space-between",
3687
- marginBottom: 4
3897
+ fontSize: 12,
3898
+ fontWeight: 500,
3899
+ color: srgbToHex(tokens.textPrimary.srgb)
3688
3900
  },
3689
- children: [
3690
- /* @__PURE__ */ jsx(
3691
- "span",
3692
- {
3693
- style: {
3694
- fontSize: 12,
3695
- fontWeight: 500,
3696
- color: srgbToHex(tokens.textPrimary.srgb)
3697
- },
3698
- children: prop.label
3699
- }
3700
- ),
3701
- /* @__PURE__ */ jsx(
3702
- "span",
3703
- {
3704
- style: {
3705
- fontSize: 11,
3706
- color: srgbToHex(tokens.textSecondary.srgb),
3707
- fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace"
3708
- },
3709
- children: prop.control
3710
- }
3711
- )
3712
- ]
3901
+ children: prop.label
3713
3902
  }
3714
- ),
3903
+ ) }),
3715
3904
  prop.control === "select" && prop.options && /* @__PURE__ */ jsx(
3716
3905
  Select,
3717
3906
  {
@@ -3745,7 +3934,54 @@ function PropControl({
3745
3934
  style: inputStyle
3746
3935
  }
3747
3936
  ),
3748
- prop.control === "toggle" && /* @__PURE__ */ jsxs(
3937
+ prop.control === "discrete-slider" && prop.options && (() => {
3938
+ const options = prop.options;
3939
+ const currentIndex = options.findIndex((o) => o.value === value);
3940
+ const idx = currentIndex >= 0 ? currentIndex : 0;
3941
+ return /* @__PURE__ */ jsxs("div", { children: [
3942
+ /* @__PURE__ */ jsx(
3943
+ "input",
3944
+ {
3945
+ type: "range",
3946
+ min: 0,
3947
+ max: options.length - 1,
3948
+ step: 1,
3949
+ value: idx,
3950
+ onChange: (e) => onChange(options[Number(e.target.value)].value),
3951
+ "aria-label": prop.label,
3952
+ style: {
3953
+ width: "100%",
3954
+ accentColor: srgbToHex(tokens.accent.fill.srgb),
3955
+ cursor: "pointer"
3956
+ }
3957
+ }
3958
+ ),
3959
+ /* @__PURE__ */ jsx(
3960
+ "div",
3961
+ {
3962
+ style: {
3963
+ display: "flex",
3964
+ justifyContent: "space-between",
3965
+ marginTop: 2
3966
+ },
3967
+ children: options.map((o) => /* @__PURE__ */ jsx(
3968
+ "span",
3969
+ {
3970
+ style: {
3971
+ fontSize: 11,
3972
+ fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace",
3973
+ color: o.value === value ? srgbToHex(tokens.textPrimary.srgb) : srgbToHex(tokens.textTertiary.srgb),
3974
+ fontWeight: o.value === value ? 600 : 400
3975
+ },
3976
+ children: o.label
3977
+ },
3978
+ String(o.value)
3979
+ ))
3980
+ }
3981
+ )
3982
+ ] });
3983
+ })(),
3984
+ prop.control === "toggle" && /* @__PURE__ */ jsx(
3749
3985
  "div",
3750
3986
  {
3751
3987
  role: "switch",
@@ -3760,47 +3996,35 @@ function PropControl({
3760
3996
  gap: 8,
3761
3997
  cursor: "pointer"
3762
3998
  },
3763
- children: [
3764
- /* @__PURE__ */ jsx(
3765
- "div",
3766
- {
3767
- style: {
3768
- width: 36,
3769
- height: 20,
3770
- borderRadius: 10,
3771
- backgroundColor: value ? srgbToHex(tokens.accent.fill.srgb) : srgbToHex(tokens.border.srgb),
3772
- position: "relative",
3773
- transition: "background-color 150ms ease",
3774
- flexShrink: 0
3775
- },
3776
- children: /* @__PURE__ */ jsx(
3777
- "div",
3778
- {
3779
- style: {
3780
- width: 16,
3781
- height: 16,
3782
- borderRadius: 8,
3783
- backgroundColor: "#fff",
3784
- position: "absolute",
3785
- top: 2,
3786
- left: value ? 18 : 2,
3787
- transition: "left 150ms ease"
3788
- }
3999
+ children: /* @__PURE__ */ jsx(
4000
+ "div",
4001
+ {
4002
+ style: {
4003
+ width: 36,
4004
+ height: 20,
4005
+ borderRadius: 10,
4006
+ backgroundColor: value ? srgbToHex(tokens.accent.fill.srgb) : srgbToHex(tokens.border.srgb),
4007
+ position: "relative",
4008
+ transition: "background-color 150ms ease",
4009
+ flexShrink: 0
4010
+ },
4011
+ children: /* @__PURE__ */ jsx(
4012
+ "div",
4013
+ {
4014
+ style: {
4015
+ width: 16,
4016
+ height: 16,
4017
+ borderRadius: 8,
4018
+ backgroundColor: "#fff",
4019
+ position: "absolute",
4020
+ top: 2,
4021
+ left: value ? 18 : 2,
4022
+ transition: "left 150ms ease"
3789
4023
  }
3790
- )
3791
- }
3792
- ),
3793
- /* @__PURE__ */ jsx(
3794
- "span",
3795
- {
3796
- style: {
3797
- fontSize: 12,
3798
- color: srgbToHex(tokens.textSecondary.srgb)
3799
- },
3800
- children: value ? "true" : "false"
3801
- }
3802
- )
3803
- ]
4024
+ }
4025
+ )
4026
+ }
4027
+ )
3804
4028
  }
3805
4029
  )
3806
4030
  ] });
@@ -3905,9 +4129,10 @@ function Editor({
3905
4129
  {
3906
4130
  view: editor.previewView,
3907
4131
  selectedVariantId: editor.selectedVariantId,
3908
- propOverrides: editor.propOverrides,
3909
4132
  onNavigate: editor.handlePreviewNavigate,
3910
- onSelectVariant: editor.handleSelectVariant
4133
+ onSelectVariant: editor.handleSelectVariant,
4134
+ propOverrides: editor.propOverrides,
4135
+ onPropOverride: editor.handlePropOverride
3911
4136
  }
3912
4137
  ) })
3913
4138
  },
@@ -3926,7 +4151,9 @@ function Editor({
3926
4151
  onPropOverride: editor.handlePropOverride,
3927
4152
  onResetOverrides: editor.handleResetOverrides,
3928
4153
  onClose: editor.handleCloseSidebar,
3929
- onScopeToComponent: editor.handleScopeToComponent
4154
+ onScopeToComponent: editor.handleScopeToComponent,
4155
+ previewConfig,
4156
+ colorMode: editor.colorMode
3930
4157
  }
3931
4158
  )
3932
4159
  }