@newtonedev/editor 0.1.1

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 (86) hide show
  1. package/dist/Editor.d.ts +3 -0
  2. package/dist/Editor.d.ts.map +1 -0
  3. package/dist/components/CodeBlock.d.ts +7 -0
  4. package/dist/components/CodeBlock.d.ts.map +1 -0
  5. package/dist/components/EditorHeader.d.ts +16 -0
  6. package/dist/components/EditorHeader.d.ts.map +1 -0
  7. package/dist/components/EditorShell.d.ts +10 -0
  8. package/dist/components/EditorShell.d.ts.map +1 -0
  9. package/dist/components/FontPicker.d.ts +11 -0
  10. package/dist/components/FontPicker.d.ts.map +1 -0
  11. package/dist/components/PresetSelector.d.ts +14 -0
  12. package/dist/components/PresetSelector.d.ts.map +1 -0
  13. package/dist/components/PreviewWindow.d.ts +11 -0
  14. package/dist/components/PreviewWindow.d.ts.map +1 -0
  15. package/dist/components/RightSidebar.d.ts +12 -0
  16. package/dist/components/RightSidebar.d.ts.map +1 -0
  17. package/dist/components/Sidebar.d.ts +25 -0
  18. package/dist/components/Sidebar.d.ts.map +1 -0
  19. package/dist/components/TableOfContents.d.ts +9 -0
  20. package/dist/components/TableOfContents.d.ts.map +1 -0
  21. package/dist/components/ThemeBar.d.ts +8 -0
  22. package/dist/components/ThemeBar.d.ts.map +1 -0
  23. package/dist/components/sections/ColorsSection.d.ts +14 -0
  24. package/dist/components/sections/ColorsSection.d.ts.map +1 -0
  25. package/dist/components/sections/DynamicRangeSection.d.ts +9 -0
  26. package/dist/components/sections/DynamicRangeSection.d.ts.map +1 -0
  27. package/dist/components/sections/FontsSection.d.ts +9 -0
  28. package/dist/components/sections/FontsSection.d.ts.map +1 -0
  29. package/dist/components/sections/IconsSection.d.ts +9 -0
  30. package/dist/components/sections/IconsSection.d.ts.map +1 -0
  31. package/dist/components/sections/OthersSection.d.ts +9 -0
  32. package/dist/components/sections/OthersSection.d.ts.map +1 -0
  33. package/dist/components/sections/index.d.ts +6 -0
  34. package/dist/components/sections/index.d.ts.map +1 -0
  35. package/dist/hooks/useEditorState.d.ts +53 -0
  36. package/dist/hooks/useEditorState.d.ts.map +1 -0
  37. package/dist/hooks/useHover.d.ts +8 -0
  38. package/dist/hooks/useHover.d.ts.map +1 -0
  39. package/dist/hooks/usePresets.d.ts +33 -0
  40. package/dist/hooks/usePresets.d.ts.map +1 -0
  41. package/dist/index.cjs +3846 -0
  42. package/dist/index.cjs.map +1 -0
  43. package/dist/index.d.ts +22 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +3819 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/preview/CategoryView.d.ts +7 -0
  48. package/dist/preview/CategoryView.d.ts.map +1 -0
  49. package/dist/preview/ComponentDetailView.d.ts +9 -0
  50. package/dist/preview/ComponentDetailView.d.ts.map +1 -0
  51. package/dist/preview/ComponentRenderer.d.ts +7 -0
  52. package/dist/preview/ComponentRenderer.d.ts.map +1 -0
  53. package/dist/preview/OverviewView.d.ts +7 -0
  54. package/dist/preview/OverviewView.d.ts.map +1 -0
  55. package/dist/types.d.ts +69 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/utils/presets.d.ts +5 -0
  58. package/dist/utils/presets.d.ts.map +1 -0
  59. package/package.json +51 -0
  60. package/src/Editor.tsx +128 -0
  61. package/src/components/CodeBlock.tsx +58 -0
  62. package/src/components/EditorHeader.tsx +86 -0
  63. package/src/components/EditorShell.tsx +67 -0
  64. package/src/components/FontPicker.tsx +351 -0
  65. package/src/components/PresetSelector.tsx +455 -0
  66. package/src/components/PreviewWindow.tsx +69 -0
  67. package/src/components/RightSidebar.tsx +374 -0
  68. package/src/components/Sidebar.tsx +332 -0
  69. package/src/components/TableOfContents.tsx +152 -0
  70. package/src/components/ThemeBar.tsx +76 -0
  71. package/src/components/sections/ColorsSection.tsx +485 -0
  72. package/src/components/sections/DynamicRangeSection.tsx +399 -0
  73. package/src/components/sections/FontsSection.tsx +132 -0
  74. package/src/components/sections/IconsSection.tsx +66 -0
  75. package/src/components/sections/OthersSection.tsx +70 -0
  76. package/src/components/sections/index.ts +5 -0
  77. package/src/hooks/useEditorState.ts +381 -0
  78. package/src/hooks/useHover.ts +8 -0
  79. package/src/hooks/usePresets.ts +254 -0
  80. package/src/index.ts +52 -0
  81. package/src/preview/CategoryView.tsx +134 -0
  82. package/src/preview/ComponentDetailView.tsx +126 -0
  83. package/src/preview/ComponentRenderer.tsx +107 -0
  84. package/src/preview/OverviewView.tsx +177 -0
  85. package/src/types.ts +77 -0
  86. package/src/utils/presets.ts +24 -0
@@ -0,0 +1,152 @@
1
+ import { useState } from "react";
2
+ import {
3
+ useTokens,
4
+ CATEGORIES,
5
+ getComponentsByCategory,
6
+ } from "@newtonedev/components";
7
+ import { srgbToHex } from "newtone";
8
+ import type { PreviewView } from "../types";
9
+
10
+ interface TableOfContentsProps {
11
+ readonly activeView: PreviewView;
12
+ readonly selectedComponentId: string | null;
13
+ readonly onNavigate: (view: PreviewView) => void;
14
+ }
15
+
16
+ const TOC_WIDTH = 220;
17
+
18
+ export function TableOfContents({
19
+ activeView,
20
+ selectedComponentId,
21
+ onNavigate,
22
+ }: TableOfContentsProps) {
23
+ const tokens = useTokens();
24
+ const [hoveredId, setHoveredId] = useState<string | null>(null);
25
+
26
+ const borderColor = srgbToHex(tokens.border.srgb);
27
+ const activeColor = srgbToHex(tokens.interactive.srgb);
28
+ const textPrimary = srgbToHex(tokens.textPrimary.srgb);
29
+ const textSecondary = srgbToHex(tokens.textSecondary.srgb);
30
+ const hoverBg = `${borderColor}20`;
31
+
32
+ const isOverviewActive = activeView.kind === "overview";
33
+
34
+ return (
35
+ <nav
36
+ aria-label="Component navigation"
37
+ style={{
38
+ width: TOC_WIDTH,
39
+ flexShrink: 0,
40
+ overflowY: "auto",
41
+ borderRight: `1px solid ${borderColor}`,
42
+ padding: "16px 0",
43
+ backgroundColor: srgbToHex(tokens.background.srgb),
44
+ }}
45
+ >
46
+ <button
47
+ onClick={() => onNavigate({ kind: "overview" })}
48
+ onMouseEnter={() => setHoveredId("overview")}
49
+ onMouseLeave={() => setHoveredId(null)}
50
+ aria-current={isOverviewActive ? "page" : undefined}
51
+ style={{
52
+ display: "block",
53
+ width: "100%",
54
+ padding: "6px 20px",
55
+ border: "none",
56
+ background: isOverviewActive
57
+ ? `${activeColor}14`
58
+ : hoveredId === "overview"
59
+ ? hoverBg
60
+ : "none",
61
+ cursor: "pointer",
62
+ textAlign: "left",
63
+ fontSize: 13,
64
+ fontWeight: isOverviewActive ? 600 : 400,
65
+ color: isOverviewActive ? activeColor : textPrimary,
66
+ transition: "background-color 100ms ease",
67
+ }}
68
+ >
69
+ Overview
70
+ </button>
71
+
72
+ {CATEGORIES.map((category) => {
73
+ const components = getComponentsByCategory(category.id);
74
+ const isCategoryActive =
75
+ activeView.kind === "category" &&
76
+ activeView.categoryId === category.id;
77
+
78
+ return (
79
+ <div key={category.id} style={{ marginTop: 16 }}>
80
+ <button
81
+ onClick={() =>
82
+ onNavigate({ kind: "category", categoryId: category.id })
83
+ }
84
+ onMouseEnter={() => setHoveredId(`cat-${category.id}`)}
85
+ onMouseLeave={() => setHoveredId(null)}
86
+ aria-current={isCategoryActive ? "page" : undefined}
87
+ style={{
88
+ display: "block",
89
+ width: "100%",
90
+ padding: "6px 20px",
91
+ border: "none",
92
+ background: isCategoryActive
93
+ ? `${activeColor}14`
94
+ : hoveredId === `cat-${category.id}`
95
+ ? hoverBg
96
+ : "none",
97
+ cursor: "pointer",
98
+ textAlign: "left",
99
+ fontSize: 11,
100
+ fontWeight: 600,
101
+ color: isCategoryActive ? activeColor : textSecondary,
102
+ textTransform: "uppercase",
103
+ letterSpacing: 0.5,
104
+ transition: "background-color 100ms ease",
105
+ }}
106
+ >
107
+ {category.name}
108
+ </button>
109
+
110
+ {components.map((comp) => {
111
+ const isComponentActive =
112
+ (activeView.kind === "component" &&
113
+ activeView.componentId === comp.id) ||
114
+ selectedComponentId === comp.id;
115
+
116
+ return (
117
+ <button
118
+ key={comp.id}
119
+ onClick={() =>
120
+ onNavigate({ kind: "component", componentId: comp.id })
121
+ }
122
+ onMouseEnter={() => setHoveredId(comp.id)}
123
+ onMouseLeave={() => setHoveredId(null)}
124
+ aria-current={isComponentActive ? "page" : undefined}
125
+ style={{
126
+ display: "block",
127
+ width: "100%",
128
+ padding: "4px 20px 4px 32px",
129
+ border: "none",
130
+ background: isComponentActive
131
+ ? `${activeColor}14`
132
+ : hoveredId === comp.id
133
+ ? hoverBg
134
+ : "none",
135
+ cursor: "pointer",
136
+ textAlign: "left",
137
+ fontSize: 13,
138
+ fontWeight: isComponentActive ? 600 : 400,
139
+ color: isComponentActive ? activeColor : textPrimary,
140
+ transition: "background-color 100ms ease",
141
+ }}
142
+ >
143
+ {comp.name}
144
+ </button>
145
+ );
146
+ })}
147
+ </div>
148
+ );
149
+ })}
150
+ </nav>
151
+ );
152
+ }
@@ -0,0 +1,76 @@
1
+ import { useState } from "react";
2
+ import { useTokens } from "@newtonedev/components";
3
+ import { srgbToHex } from "newtone";
4
+ import type { ThemeName } from "../types";
5
+
6
+ interface ThemeBarProps {
7
+ readonly activeTheme: ThemeName;
8
+ readonly onThemeChange: (theme: ThemeName) => void;
9
+ }
10
+
11
+ const THEME_CHIPS: readonly { id: ThemeName; label: string }[] = [
12
+ { id: "neutral", label: "Neutral" },
13
+ { id: "primary", label: "Primary" },
14
+ { id: "secondary", label: "Secondary" },
15
+ { id: "strong", label: "Strong" },
16
+ ];
17
+
18
+ export function ThemeBar({ activeTheme, onThemeChange }: ThemeBarProps) {
19
+ const tokens = useTokens();
20
+ const [hoveredChipId, setHoveredChipId] = useState<string | null>(null);
21
+
22
+ const borderColor = srgbToHex(tokens.border.srgb);
23
+ const interactiveColor = srgbToHex(tokens.interactive.srgb);
24
+
25
+ return (
26
+ <div
27
+ style={{
28
+ display: "flex",
29
+ alignItems: "center",
30
+ padding: "8px 24px",
31
+ borderBottom: `1px solid ${borderColor}`,
32
+ backgroundColor: srgbToHex(tokens.background.srgb),
33
+ flexShrink: 0,
34
+ }}
35
+ >
36
+ {/* Theme Chips */}
37
+ <div style={{ display: "flex", gap: 8 }} role="group" aria-label="Theme">
38
+ {THEME_CHIPS.map((chip) => {
39
+ const isActive = chip.id === activeTheme;
40
+ const isHovered = hoveredChipId === chip.id;
41
+
42
+ return (
43
+ <button
44
+ key={chip.id}
45
+ onClick={() => onThemeChange(chip.id)}
46
+ onMouseEnter={() => setHoveredChipId(chip.id)}
47
+ onMouseLeave={() => setHoveredChipId(null)}
48
+ aria-pressed={isActive}
49
+ style={{
50
+ padding: "4px 12px",
51
+ borderRadius: 16,
52
+ border: `1px solid ${srgbToHex(
53
+ isActive ? tokens.interactive.srgb : tokens.border.srgb,
54
+ )}`,
55
+ backgroundColor: isActive
56
+ ? interactiveColor
57
+ : isHovered
58
+ ? `${interactiveColor}10`
59
+ : "transparent",
60
+ color: isActive
61
+ ? "#fff"
62
+ : srgbToHex(tokens.textPrimary.srgb),
63
+ fontSize: 12,
64
+ fontWeight: 500,
65
+ cursor: "pointer",
66
+ transition: "background-color 150ms ease",
67
+ }}
68
+ >
69
+ {chip.label}
70
+ </button>
71
+ );
72
+ })}
73
+ </div>
74
+ </div>
75
+ );
76
+ }