@newtonedev/editor 0.1.4 → 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.
Files changed (48) hide show
  1. package/dist/Editor.d.ts.map +1 -1
  2. package/dist/components/CodeBlock.d.ts.map +1 -1
  3. package/dist/components/PresetSelector.d.ts.map +1 -1
  4. package/dist/components/PreviewWindow.d.ts +3 -2
  5. package/dist/components/PreviewWindow.d.ts.map +1 -1
  6. package/dist/components/RightSidebar.d.ts +4 -1
  7. package/dist/components/RightSidebar.d.ts.map +1 -1
  8. package/dist/components/Sidebar.d.ts.map +1 -1
  9. package/dist/components/sections/DynamicRangeSection.d.ts.map +1 -1
  10. package/dist/hooks/useEditorState.d.ts +1 -3
  11. package/dist/hooks/useEditorState.d.ts.map +1 -1
  12. package/dist/index.cjs +686 -346
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +1 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +689 -348
  17. package/dist/index.js.map +1 -1
  18. package/dist/preview/ComponentDetailView.d.ts +3 -2
  19. package/dist/preview/ComponentDetailView.d.ts.map +1 -1
  20. package/dist/preview/ComponentRenderer.d.ts.map +1 -1
  21. package/dist/preview/IconBrowserView.d.ts +7 -0
  22. package/dist/preview/IconBrowserView.d.ts.map +1 -0
  23. package/dist/types.d.ts +0 -1
  24. package/dist/types.d.ts.map +1 -1
  25. package/package.json +1 -1
  26. package/src/Editor.tsx +19 -9
  27. package/src/components/CodeBlock.tsx +42 -14
  28. package/src/components/EditorHeader.tsx +3 -3
  29. package/src/components/EditorShell.tsx +2 -2
  30. package/src/components/FontPicker.tsx +1 -1
  31. package/src/components/PresetSelector.tsx +11 -36
  32. package/src/components/PreviewWindow.tsx +6 -3
  33. package/src/components/RightSidebar.tsx +105 -42
  34. package/src/components/Sidebar.tsx +12 -92
  35. package/src/components/TableOfContents.tsx +1 -1
  36. package/src/components/sections/ColorsSection.tsx +2 -2
  37. package/src/components/sections/DynamicRangeSection.tsx +226 -3
  38. package/src/hooks/useEditorState.ts +14 -19
  39. package/src/index.ts +0 -2
  40. package/src/preview/CategoryView.tsx +1 -1
  41. package/src/preview/ComponentDetailView.tsx +47 -8
  42. package/src/preview/ComponentRenderer.tsx +51 -0
  43. package/src/preview/IconBrowserView.tsx +187 -0
  44. package/src/preview/OverviewView.tsx +1 -1
  45. package/src/types.ts +0 -2
  46. package/dist/components/ThemeBar.d.ts +0 -8
  47. package/dist/components/ThemeBar.d.ts.map +0 -1
  48. package/src/components/ThemeBar.tsx +0 -76
@@ -1,9 +1,10 @@
1
1
  interface ComponentDetailViewProps {
2
2
  readonly componentId: string;
3
3
  readonly selectedVariantId: string | null;
4
- readonly propOverrides?: Record<string, unknown>;
5
4
  readonly onSelectVariant: (variantId: string) => void;
5
+ readonly propOverrides?: Record<string, unknown>;
6
+ readonly onPropOverride?: (name: string, value: unknown) => void;
6
7
  }
7
- export declare function ComponentDetailView({ componentId, selectedVariantId, propOverrides, onSelectVariant, }: ComponentDetailViewProps): import("react/jsx-runtime").JSX.Element | null;
8
+ export declare function ComponentDetailView({ componentId, selectedVariantId, onSelectVariant, propOverrides, onPropOverride, }: ComponentDetailViewProps): import("react/jsx-runtime").JSX.Element | null;
8
9
  export {};
9
10
  //# sourceMappingURL=ComponentDetailView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ComponentDetailView.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentDetailView.tsx"],"names":[],"mappings":"AAMA,UAAU,wBAAwB;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,QAAQ,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,EAAE,wBAAwB,kDA2G1B"}
1
+ {"version":3,"file":"ComponentDetailView.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentDetailView.tsx"],"names":[],"mappings":"AAOA,UAAU,wBAAwB;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAClE;AAED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,cAAc,GACf,EAAE,wBAAwB,kDA+I1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"ComponentRenderer.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentRenderer.tsx"],"names":[],"mappings":"AAaA,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAyDD,wBAAgB,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,sBAAsB,kDAiC/E"}
1
+ {"version":3,"file":"ComponentRenderer.d.ts","sourceRoot":"","sources":["../../src/preview/ComponentRenderer.tsx"],"names":[],"mappings":"AAiBA,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AA2ED,wBAAgB,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,sBAAsB,kDA8D/E"}
@@ -0,0 +1,7 @@
1
+ interface IconBrowserViewProps {
2
+ readonly selectedIconName: string;
3
+ readonly onIconSelect: (name: string) => void;
4
+ }
5
+ export declare function IconBrowserView({ selectedIconName, onIconSelect, }: IconBrowserViewProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=IconBrowserView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IconBrowserView.d.ts","sourceRoot":"","sources":["../../src/preview/IconBrowserView.tsx"],"names":[],"mappings":"AAIA,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,eAAe,CAAC,EAC9B,gBAAgB,EAChB,YAAY,GACb,EAAE,oBAAoB,2CA8KtB"}
package/dist/types.d.ts CHANGED
@@ -8,7 +8,6 @@ export interface Preset {
8
8
  readonly published_state: ConfiguratorState | null;
9
9
  }
10
10
  export type SaveStatus = "saved" | "saving" | "unsaved" | "error";
11
- export type ThemeName = "neutral" | "primary" | "secondary" | "strong";
12
11
  export type PreviewView = {
13
12
  readonly kind: "overview";
14
13
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newtonedev/editor",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Shared color system editor for Newtone applications",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/Editor.tsx CHANGED
@@ -1,9 +1,10 @@
1
+ import { useMemo } from "react";
1
2
  import { NewtoneProvider } from "@newtonedev/components";
3
+ import type { NewtoneThemeConfig } from "@newtonedev/components";
2
4
  import { useEditorState } from "./hooks/useEditorState";
3
5
  import { EditorShell } from "./components/EditorShell";
4
6
  import { Sidebar } from "./components/Sidebar";
5
7
  import { EditorHeader } from "./components/EditorHeader";
6
- import { ThemeBar } from "./components/ThemeBar";
7
8
  import { TableOfContents } from "./components/TableOfContents";
8
9
  import { PreviewWindow } from "./components/PreviewWindow";
9
10
  import { RightSidebar } from "./components/RightSidebar";
@@ -34,6 +35,17 @@ export function Editor({
34
35
  initialPreviewView,
35
36
  });
36
37
 
38
+ // Merge token overrides from chrome config into the preview config.
39
+ // Token overrides (from Token Tuner) are stored separately from configurator
40
+ // state, but should apply to the preview so components render accurately.
41
+ const previewConfig: NewtoneThemeConfig = useMemo(
42
+ () =>
43
+ chromeThemeConfig.tokenOverrides
44
+ ? { ...editor.themeConfig, tokenOverrides: chromeThemeConfig.tokenOverrides }
45
+ : editor.themeConfig,
46
+ [editor.themeConfig, chromeThemeConfig.tokenOverrides],
47
+ );
48
+
37
49
  return (
38
50
  <NewtoneProvider config={chromeThemeConfig}>
39
51
  <EditorShell
@@ -90,22 +102,18 @@ export function Editor({
90
102
  }}
91
103
  >
92
104
  <NewtoneProvider
93
- config={editor.themeConfig}
105
+ config={previewConfig}
94
106
  initialMode={editor.colorMode}
95
- initialTheme={editor.activeTheme}
96
- key={`${editor.colorMode}-${editor.activeTheme}`}
107
+ key={editor.colorMode}
97
108
  >
98
- <ThemeBar
99
- activeTheme={editor.activeTheme}
100
- onThemeChange={editor.handleThemeChange}
101
- />
102
109
  <div style={{ flex: 1, overflowY: "auto", minWidth: 0 }}>
103
110
  <PreviewWindow
104
111
  view={editor.previewView}
105
112
  selectedVariantId={editor.selectedVariantId}
106
- propOverrides={editor.propOverrides}
107
113
  onNavigate={editor.handlePreviewNavigate}
108
114
  onSelectVariant={editor.handleSelectVariant}
115
+ propOverrides={editor.propOverrides}
116
+ onPropOverride={editor.handlePropOverride}
109
117
  />
110
118
  </div>
111
119
  </NewtoneProvider>
@@ -120,6 +128,8 @@ export function Editor({
120
128
  onResetOverrides={editor.handleResetOverrides}
121
129
  onClose={editor.handleCloseSidebar}
122
130
  onScopeToComponent={editor.handleScopeToComponent}
131
+ previewConfig={previewConfig}
132
+ colorMode={editor.colorMode}
123
133
  />
124
134
  }
125
135
  />
@@ -1,8 +1,9 @@
1
1
  import { useState, useCallback } from "react";
2
- import { useTokens, Button } from "@newtonedev/components";
2
+ import { useTokens, Icon } from "@newtonedev/components";
3
3
  import { srgbToHex } from "newtone";
4
4
 
5
5
  export function CopyButton({ text }: { readonly text: string }) {
6
+ const tokens = useTokens();
6
7
  const [copied, setCopied] = useState(false);
7
8
 
8
9
  const handleCopy = useCallback(async () => {
@@ -12,9 +13,31 @@ export function CopyButton({ text }: { readonly text: string }) {
12
13
  }, [text]);
13
14
 
14
15
  return (
15
- <Button variant="tertiary" semantic="neutral" size="sm" icon={copied ? "check" : "content_copy"} onPress={handleCopy}>
16
- {copied ? "Copied!" : "Copy"}
17
- </Button>
16
+ <button
17
+ onClick={handleCopy}
18
+ aria-label={copied ? "Copied" : "Copy code"}
19
+ style={{
20
+ background: "none",
21
+ border: "none",
22
+ cursor: "pointer",
23
+ padding: 4,
24
+ display: "flex",
25
+ alignItems: "center",
26
+ justifyContent: "center",
27
+ color: srgbToHex(
28
+ copied ? tokens.accent.fill.srgb : tokens.textTertiary.srgb,
29
+ ),
30
+ transition: "color 150ms ease",
31
+ }}
32
+ >
33
+ <Icon
34
+ name={copied ? "check" : "content_copy"}
35
+ size={16}
36
+ color={srgbToHex(
37
+ copied ? tokens.accent.fill.srgb : tokens.textTertiary.srgb,
38
+ )}
39
+ />
40
+ </button>
18
41
  );
19
42
  }
20
43
 
@@ -26,24 +49,29 @@ export function CodeBlock({
26
49
  const tokens = useTokens();
27
50
 
28
51
  return (
29
- <div style={{ position: "relative" }}>
52
+ <div
53
+ style={{
54
+ backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
55
+ border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
56
+ borderRadius: 8,
57
+ overflow: "hidden",
58
+ }}
59
+ >
30
60
  <div
31
61
  style={{
32
- position: "absolute",
33
- top: 8,
34
- right: 8,
62
+ display: "flex",
63
+ justifyContent: "flex-end",
64
+ padding: "4px 8px",
65
+ borderBottom: `1px solid ${srgbToHex(tokens.border.srgb)}`,
35
66
  }}
36
67
  >
37
68
  <CopyButton text={code} />
38
69
  </div>
39
70
  <pre
40
71
  style={{
41
- backgroundColor: srgbToHex(tokens.backgroundSunken.srgb),
42
- border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
43
- borderRadius: 8,
44
- padding: 16,
45
- paddingRight: 80,
46
- overflow: "auto",
72
+ padding: "12px 16px",
73
+ whiteSpace: "pre-wrap",
74
+ wordBreak: "break-word",
47
75
  fontSize: 13,
48
76
  lineHeight: 1.5,
49
77
  fontFamily: "'SF Mono', 'Fira Code', 'Fira Mono', Menlo, monospace",
@@ -34,10 +34,10 @@ export function EditorHeader({
34
34
  const borderColor = srgbToHex(tokens.border.srgb);
35
35
 
36
36
  const statusColor: Record<SaveStatus, string> = {
37
- saved: srgbToHex(tokens.success.srgb),
38
- saving: srgbToHex(tokens.warning.srgb),
37
+ saved: srgbToHex(tokens.success.fill.srgb),
38
+ saving: srgbToHex(tokens.warning.fill.srgb),
39
39
  unsaved: srgbToHex(tokens.textSecondary.srgb),
40
- error: srgbToHex(tokens.error.srgb),
40
+ error: srgbToHex(tokens.error.fill.srgb),
41
41
  };
42
42
 
43
43
  return (
@@ -23,7 +23,7 @@ export function EditorShell({
23
23
  <div
24
24
  style={{
25
25
  display: "flex",
26
- height: "100vh",
26
+ height: "100%",
27
27
  overflow: "hidden",
28
28
  backgroundColor: srgbToHex(tokens.background.srgb),
29
29
  }}
@@ -33,7 +33,7 @@ export function EditorShell({
33
33
  flex: 1,
34
34
  display: "flex",
35
35
  flexDirection: "column",
36
- height: "100vh",
36
+ height: "100%",
37
37
  overflow: "hidden",
38
38
  minWidth: 0,
39
39
  }}
@@ -84,7 +84,7 @@ export function FontPicker({
84
84
  const bgColor = srgbToHex(tokens.backgroundElevated.srgb);
85
85
  const borderColor = srgbToHex(tokens.border.srgb);
86
86
  const hoverColor = srgbToHex(tokens.backgroundSunken.srgb);
87
- const interactiveColor = srgbToHex(tokens.interactive.srgb);
87
+ const interactiveColor = srgbToHex(tokens.accent.fill.srgb);
88
88
 
89
89
  useEffect(() => {
90
90
  if (!isOpen) return;
@@ -1,5 +1,5 @@
1
1
  import { useState, useRef, useEffect, useCallback } from "react";
2
- import { useTokens } from "@newtonedev/components";
2
+ import { useTokens, Icon } from "@newtonedev/components";
3
3
  import { srgbToHex } from "newtone";
4
4
  import type { Preset } from "../types";
5
5
  import { presetHasUnpublishedChanges } from "../utils/presets";
@@ -44,9 +44,9 @@ export function PresetSelector({
44
44
  const bgColor = srgbToHex(tokens.background.srgb);
45
45
  const textPrimary = srgbToHex(tokens.textPrimary.srgb);
46
46
  const textSecondary = srgbToHex(tokens.textSecondary.srgb);
47
- const interactiveColor = srgbToHex(tokens.interactive.srgb);
48
- const warningColor = srgbToHex(tokens.warning.srgb);
49
- const errorColor = srgbToHex(tokens.error.srgb);
47
+ const interactiveColor = srgbToHex(tokens.accent.fill.srgb);
48
+ const warningColor = srgbToHex(tokens.warning.fill.srgb);
49
+ const errorColor = srgbToHex(tokens.error.fill.srgb);
50
50
  const hoverBg = `${borderColor}18`;
51
51
  const activeBg = `${interactiveColor}14`;
52
52
 
@@ -145,21 +145,15 @@ export function PresetSelector({
145
145
  >
146
146
  {activePreset?.name ?? "Default"}
147
147
  </span>
148
- <svg
149
- width={10}
150
- height={10}
151
- viewBox="0 0 24 24"
152
- fill="none"
153
- stroke="currentColor"
154
- strokeWidth={2}
148
+ <Icon
149
+ name="expand_more"
150
+ size={14}
155
151
  style={{
156
152
  transform: isOpen ? "rotate(180deg)" : "none",
157
153
  transition: "transform 150ms ease",
158
154
  flexShrink: 0,
159
- }}
160
- >
161
- <polyline points="6 9 12 15 18 9" />
162
- </svg>
155
+ } as any}
156
+ />
163
157
  </button>
164
158
 
165
159
  {isOpen && (
@@ -303,16 +297,7 @@ export function PresetSelector({
303
297
  flexShrink: 0,
304
298
  }}
305
299
  >
306
- <svg
307
- width={14}
308
- height={14}
309
- viewBox="0 0 24 24"
310
- fill="currentColor"
311
- >
312
- <circle cx={12} cy={5} r={2} />
313
- <circle cx={12} cy={12} r={2} />
314
- <circle cx={12} cy={19} r={2} />
315
- </svg>
300
+ <Icon name="more_vert" size={14} color={textSecondary} />
316
301
  </button>
317
302
  )}
318
303
  </>
@@ -435,17 +420,7 @@ export function PresetSelector({
435
420
  cursor: "pointer",
436
421
  }}
437
422
  >
438
- <svg
439
- width={14}
440
- height={14}
441
- viewBox="0 0 24 24"
442
- fill="none"
443
- stroke="currentColor"
444
- strokeWidth={2}
445
- >
446
- <line x1={12} y1={5} x2={12} y2={19} />
447
- <line x1={5} y1={12} x2={19} y2={12} />
448
- </svg>
423
+ <Icon name="add" size={14} color={textSecondary} />
449
424
  New preset
450
425
  </button>
451
426
  </div>
@@ -9,17 +9,19 @@ import type { PreviewView } from "../types";
9
9
  interface PreviewWindowProps {
10
10
  readonly view: PreviewView;
11
11
  readonly selectedVariantId: string | null;
12
- readonly propOverrides?: Record<string, unknown>;
13
12
  readonly onNavigate: (view: PreviewView) => void;
14
13
  readonly onSelectVariant: (variantId: string) => void;
14
+ readonly propOverrides?: Record<string, unknown>;
15
+ readonly onPropOverride?: (name: string, value: unknown) => void;
15
16
  }
16
17
 
17
18
  export function PreviewWindow({
18
19
  view,
19
20
  selectedVariantId,
20
- propOverrides,
21
21
  onNavigate,
22
22
  onSelectVariant,
23
+ propOverrides,
24
+ onPropOverride,
23
25
  }: PreviewWindowProps) {
24
26
  const tokens = useTokens();
25
27
 
@@ -59,8 +61,9 @@ export function PreviewWindow({
59
61
  <ComponentDetailView
60
62
  componentId={view.componentId}
61
63
  selectedVariantId={selectedVariantId}
62
- propOverrides={propOverrides}
63
64
  onSelectVariant={onSelectVariant}
65
+ propOverrides={propOverrides}
66
+ onPropOverride={onPropOverride}
64
67
  />
65
68
  )}
66
69
  </div>
@@ -1,8 +1,9 @@
1
1
  import { useCallback, type KeyboardEvent } from "react";
2
- import { useTokens, getComponent, generateComponentCode, Select } from "@newtonedev/components";
3
- import type { EditableProp } from "@newtonedev/components";
2
+ import { useTokens, getComponent, generateComponentCode, Select, NewtoneProvider, Icon } from "@newtonedev/components";
3
+ import type { EditableProp, NewtoneThemeConfig, ColorMode } from "@newtonedev/components";
4
4
  import { srgbToHex } from "newtone";
5
5
  import { CodeBlock } from "./CodeBlock";
6
+ import { ComponentRenderer } from "../preview/ComponentRenderer";
6
7
  import type { SidebarSelection } from "../types";
7
8
 
8
9
  interface RightSidebarProps {
@@ -12,6 +13,8 @@ interface RightSidebarProps {
12
13
  readonly onResetOverrides: () => void;
13
14
  readonly onClose: () => void;
14
15
  readonly onScopeToComponent: () => void;
16
+ readonly previewConfig: NewtoneThemeConfig;
17
+ readonly colorMode: ColorMode;
15
18
  }
16
19
 
17
20
  export function RightSidebar({
@@ -21,6 +24,8 @@ export function RightSidebar({
21
24
  onResetOverrides,
22
25
  onClose,
23
26
  onScopeToComponent,
27
+ previewConfig,
28
+ colorMode,
24
29
  }: RightSidebarProps) {
25
30
  const tokens = useTokens();
26
31
  const visible = selection !== null;
@@ -79,19 +84,7 @@ export function RightSidebar({
79
84
  alignItems: "center",
80
85
  }}
81
86
  >
82
- <svg
83
- width={16}
84
- height={16}
85
- viewBox="0 0 24 24"
86
- fill="none"
87
- stroke="currentColor"
88
- strokeWidth={2}
89
- strokeLinecap="round"
90
- strokeLinejoin="round"
91
- >
92
- <line x1="19" y1="12" x2="5" y2="12" />
93
- <polyline points="12 19 5 12 12 5" />
94
- </svg>
87
+ <Icon name="arrow_back" size={16} color={srgbToHex(tokens.textSecondary.srgb)} />
95
88
  </button>
96
89
  {selection.scope === "variant" && variant ? (
97
90
  <>
@@ -105,7 +98,7 @@ export function RightSidebar({
105
98
  padding: 0,
106
99
  fontSize: 14,
107
100
  fontWeight: 500,
108
- color: srgbToHex(tokens.interactive.srgb),
101
+ color: srgbToHex(tokens.accent.fill.srgb),
109
102
  whiteSpace: "nowrap",
110
103
  }}
111
104
  >
@@ -154,6 +147,27 @@ export function RightSidebar({
154
147
  padding: 16,
155
148
  }}
156
149
  >
150
+ {/* Live Preview */}
151
+ <div
152
+ style={{
153
+ marginBottom: 20,
154
+ borderRadius: 8,
155
+ border: `1px solid ${srgbToHex(tokens.border.srgb)}`,
156
+ overflow: "hidden",
157
+ }}
158
+ >
159
+ <NewtoneProvider
160
+ config={previewConfig}
161
+ initialMode={colorMode}
162
+ key={colorMode}
163
+ >
164
+ <PreviewSurface
165
+ componentId={selection.componentId}
166
+ propOverrides={propOverrides}
167
+ />
168
+ </NewtoneProvider>
169
+ </div>
170
+
157
171
  <h3
158
172
  style={{
159
173
  fontSize: 13,
@@ -222,6 +236,31 @@ export function RightSidebar({
222
236
  );
223
237
  }
224
238
 
239
+ function PreviewSurface({
240
+ componentId,
241
+ propOverrides,
242
+ }: {
243
+ readonly componentId: string;
244
+ readonly propOverrides: Record<string, unknown>;
245
+ }) {
246
+ const previewTokens = useTokens();
247
+
248
+ return (
249
+ <div
250
+ style={{
251
+ display: "flex",
252
+ alignItems: "center",
253
+ justifyContent: "center",
254
+ padding: 24,
255
+ height: 120,
256
+ backgroundColor: srgbToHex(previewTokens.backgroundElevated.srgb),
257
+ }}
258
+ >
259
+ <ComponentRenderer componentId={componentId} props={propOverrides} />
260
+ </div>
261
+ );
262
+ }
263
+
225
264
  function PropControl({
226
265
  prop,
227
266
  value,
@@ -257,14 +296,7 @@ function PropControl({
257
296
 
258
297
  return (
259
298
  <div>
260
- <div
261
- style={{
262
- display: "flex",
263
- alignItems: "center",
264
- justifyContent: "space-between",
265
- marginBottom: 4,
266
- }}
267
- >
299
+ <div style={{ marginBottom: 4 }}>
268
300
  <span
269
301
  style={{
270
302
  fontSize: 12,
@@ -274,15 +306,6 @@ function PropControl({
274
306
  >
275
307
  {prop.label}
276
308
  </span>
277
- <span
278
- style={{
279
- fontSize: 11,
280
- color: srgbToHex(tokens.textSecondary.srgb),
281
- fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace",
282
- }}
283
- >
284
- {prop.control}
285
- </span>
286
309
  </div>
287
310
 
288
311
  {prop.control === "select" && prop.options && (
@@ -318,6 +341,54 @@ function PropControl({
318
341
  />
319
342
  )}
320
343
 
344
+ {prop.control === "discrete-slider" && prop.options && (() => {
345
+ const options = prop.options!;
346
+ const currentIndex = options.findIndex((o) => o.value === value);
347
+ const idx = currentIndex >= 0 ? currentIndex : 0;
348
+
349
+ return (
350
+ <div>
351
+ <input
352
+ type="range"
353
+ min={0}
354
+ max={options.length - 1}
355
+ step={1}
356
+ value={idx}
357
+ onChange={(e) => onChange(options[Number(e.target.value)].value)}
358
+ aria-label={prop.label}
359
+ style={{
360
+ width: "100%",
361
+ accentColor: srgbToHex(tokens.accent.fill.srgb),
362
+ cursor: "pointer",
363
+ }}
364
+ />
365
+ <div
366
+ style={{
367
+ display: "flex",
368
+ justifyContent: "space-between",
369
+ marginTop: 2,
370
+ }}
371
+ >
372
+ {options.map((o) => (
373
+ <span
374
+ key={String(o.value)}
375
+ style={{
376
+ fontSize: 11,
377
+ fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace",
378
+ color: o.value === value
379
+ ? srgbToHex(tokens.textPrimary.srgb)
380
+ : srgbToHex(tokens.textTertiary.srgb),
381
+ fontWeight: o.value === value ? 600 : 400,
382
+ }}
383
+ >
384
+ {o.label}
385
+ </span>
386
+ ))}
387
+ </div>
388
+ </div>
389
+ );
390
+ })()}
391
+
321
392
  {prop.control === "toggle" && (
322
393
  <div
323
394
  role="switch"
@@ -339,7 +410,7 @@ function PropControl({
339
410
  height: 20,
340
411
  borderRadius: 10,
341
412
  backgroundColor: value
342
- ? srgbToHex(tokens.interactive.srgb)
413
+ ? srgbToHex(tokens.accent.fill.srgb)
343
414
  : srgbToHex(tokens.border.srgb),
344
415
  position: "relative",
345
416
  transition: "background-color 150ms ease",
@@ -359,14 +430,6 @@ function PropControl({
359
430
  }}
360
431
  />
361
432
  </div>
362
- <span
363
- style={{
364
- fontSize: 12,
365
- color: srgbToHex(tokens.textSecondary.srgb),
366
- }}
367
- >
368
- {value ? "true" : "false"}
369
- </span>
370
433
  </div>
371
434
  )}
372
435
  </div>