@promakeai/inspector 0.2.1 → 1.0.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.
Files changed (170) hide show
  1. package/dist/inspector.css +1 -0
  2. package/dist/inspector.js +8740 -0
  3. package/dist/packages/inspector/src/App.d.ts +5 -0
  4. package/dist/packages/inspector/src/App.d.ts.map +1 -0
  5. package/dist/packages/inspector/src/__tests__/App.test.d.ts +5 -0
  6. package/dist/packages/inspector/src/__tests__/App.test.d.ts.map +1 -0
  7. package/dist/packages/inspector/src/components/Badge.d.ts +9 -0
  8. package/dist/packages/inspector/src/components/Badge.d.ts.map +1 -0
  9. package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts +10 -0
  10. package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts.map +1 -0
  11. package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts +12 -0
  12. package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts.map +1 -0
  13. package/dist/packages/inspector/src/components/ControlBox/index.d.ts +21 -0
  14. package/dist/packages/inspector/src/components/ControlBox/index.d.ts.map +1 -0
  15. package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts +10 -0
  16. package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts.map +1 -0
  17. package/dist/packages/inspector/src/components/ImageEditor/index.d.ts +11 -0
  18. package/dist/packages/inspector/src/components/ImageEditor/index.d.ts.map +1 -0
  19. package/dist/packages/inspector/src/components/Overlay.d.ts +11 -0
  20. package/dist/packages/inspector/src/components/Overlay.d.ts.map +1 -0
  21. package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts +13 -0
  22. package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts.map +1 -0
  23. package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts +13 -0
  24. package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts.map +1 -0
  25. package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts +13 -0
  26. package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts.map +1 -0
  27. package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts +13 -0
  28. package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts.map +1 -0
  29. package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts +13 -0
  30. package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts.map +1 -0
  31. package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts +17 -0
  32. package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts.map +1 -0
  33. package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts +16 -0
  34. package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts.map +1 -0
  35. package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts +13 -0
  36. package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts.map +1 -0
  37. package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts +13 -0
  38. package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts.map +1 -0
  39. package/dist/packages/inspector/src/components/StyleEditor/index.d.ts +12 -0
  40. package/dist/packages/inspector/src/components/StyleEditor/index.d.ts.map +1 -0
  41. package/dist/packages/inspector/src/components/TextEditor/index.d.ts +11 -0
  42. package/dist/packages/inspector/src/components/TextEditor/index.d.ts.map +1 -0
  43. package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts +26 -0
  44. package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts.map +1 -0
  45. package/dist/packages/inspector/src/components/ui/button.d.ts +9 -0
  46. package/dist/packages/inspector/src/components/ui/button.d.ts.map +1 -0
  47. package/dist/packages/inspector/src/components/ui/color-picker.d.ts +10 -0
  48. package/dist/packages/inspector/src/components/ui/color-picker.d.ts.map +1 -0
  49. package/dist/packages/inspector/src/components/ui/input.d.ts +6 -0
  50. package/dist/packages/inspector/src/components/ui/input.d.ts.map +1 -0
  51. package/dist/packages/inspector/src/components/ui/popover.d.ts +8 -0
  52. package/dist/packages/inspector/src/components/ui/popover.d.ts.map +1 -0
  53. package/dist/packages/inspector/src/components/ui/select.d.ts +16 -0
  54. package/dist/packages/inspector/src/components/ui/select.d.ts.map +1 -0
  55. package/dist/packages/inspector/src/components/ui/slider.d.ts +5 -0
  56. package/dist/packages/inspector/src/components/ui/slider.d.ts.map +1 -0
  57. package/dist/packages/inspector/src/components/ui/textarea.d.ts +4 -0
  58. package/dist/packages/inspector/src/components/ui/textarea.d.ts.map +1 -0
  59. package/dist/packages/inspector/src/components/ui/tooltip.d.ts +8 -0
  60. package/dist/packages/inspector/src/components/ui/tooltip.d.ts.map +1 -0
  61. package/dist/packages/inspector/src/core/highlighter.d.ts +40 -0
  62. package/dist/packages/inspector/src/core/highlighter.d.ts.map +1 -0
  63. package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts +9 -0
  64. package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts.map +1 -0
  65. package/dist/packages/inspector/src/hooks/useStylePreview.d.ts +11 -0
  66. package/dist/packages/inspector/src/hooks/useStylePreview.d.ts.map +1 -0
  67. package/dist/packages/inspector/src/index.d.ts +16 -0
  68. package/dist/packages/inspector/src/index.d.ts.map +1 -0
  69. package/dist/packages/inspector/src/lib/utils.d.ts +3 -0
  70. package/dist/packages/inspector/src/lib/utils.d.ts.map +1 -0
  71. package/dist/packages/inspector/src/plugin.d.ts +4 -0
  72. package/dist/packages/inspector/src/plugin.d.ts.map +1 -0
  73. package/dist/packages/inspector/src/store/useInspectorStore.d.ts +13 -0
  74. package/dist/packages/inspector/src/store/useInspectorStore.d.ts.map +1 -0
  75. package/dist/packages/inspector/src/styles.d.ts +5 -0
  76. package/dist/packages/inspector/src/styles.d.ts.map +1 -0
  77. package/dist/packages/inspector/src/utils/colorUtils.d.ts +49 -0
  78. package/dist/packages/inspector/src/utils/colorUtils.d.ts.map +1 -0
  79. package/dist/packages/inspector/src/utils/elementNames.d.ts +7 -0
  80. package/dist/packages/inspector/src/utils/elementNames.d.ts.map +1 -0
  81. package/dist/packages/inspector/src/utils/elementUtils.d.ts +28 -0
  82. package/dist/packages/inspector/src/utils/elementUtils.d.ts.map +1 -0
  83. package/dist/packages/inspector/src/utils/errorTracker.d.ts +48 -0
  84. package/dist/packages/inspector/src/utils/errorTracker.d.ts.map +1 -0
  85. package/dist/packages/inspector/src/utils/inputStyles.d.ts +23 -0
  86. package/dist/packages/inspector/src/utils/inputStyles.d.ts.map +1 -0
  87. package/dist/packages/inspector/src/utils/styleUtils.d.ts +27 -0
  88. package/dist/packages/inspector/src/utils/styleUtils.d.ts.map +1 -0
  89. package/dist/packages/inspector/src/utils/tailwindMapper.d.ts +9 -0
  90. package/dist/packages/inspector/src/utils/tailwindMapper.d.ts.map +1 -0
  91. package/dist/packages/inspector/src/utils/urlTracker.d.ts +27 -0
  92. package/dist/packages/inspector/src/utils/urlTracker.d.ts.map +1 -0
  93. package/dist/packages/inspector/tsconfig.tsbuildinfo +1 -0
  94. package/dist/plugin.js +10 -1813
  95. package/package.json +86 -76
  96. package/src/App.tsx +912 -0
  97. package/src/__tests__/App.test.tsx +373 -0
  98. package/src/assets/fonts/Satoshi-Variable.woff +0 -0
  99. package/src/assets/fonts/Satoshi-Variable.woff2 +0 -0
  100. package/src/components/Badge.tsx +118 -0
  101. package/src/components/ControlBox/ContentArea.tsx +13 -0
  102. package/src/components/ControlBox/PromptInput.module.css +66 -0
  103. package/src/components/ControlBox/PromptInput.tsx +104 -0
  104. package/src/components/ControlBox/index.module.css +81 -0
  105. package/src/components/ControlBox/index.tsx +409 -0
  106. package/src/components/ImageEditor/UploadBox.module.css +69 -0
  107. package/src/components/ImageEditor/UploadBox.tsx +113 -0
  108. package/src/components/ImageEditor/index.module.css +11 -0
  109. package/src/components/ImageEditor/index.tsx +84 -0
  110. package/src/components/Overlay.tsx +157 -0
  111. package/src/components/StyleEditor/BorderSection.tsx +147 -0
  112. package/src/components/StyleEditor/ColorPicker.tsx +182 -0
  113. package/src/components/StyleEditor/DisplaySection.tsx +349 -0
  114. package/src/components/StyleEditor/ImageSection.tsx +105 -0
  115. package/src/components/StyleEditor/LayoutSection.tsx +63 -0
  116. package/src/components/StyleEditor/NumberInput.tsx +138 -0
  117. package/src/components/StyleEditor/SliderInput.tsx +121 -0
  118. package/src/components/StyleEditor/SpacingSection.tsx +365 -0
  119. package/src/components/StyleEditor/TextSection.tsx +381 -0
  120. package/src/components/StyleEditor/index.module.css +133 -0
  121. package/src/components/StyleEditor/index.tsx +612 -0
  122. package/src/components/StyleEditor/shared.module.css +193 -0
  123. package/src/components/TextEditor/index.module.css +31 -0
  124. package/src/components/TextEditor/index.tsx +166 -0
  125. package/src/components/ui/CustomCollapsible.tsx +159 -0
  126. package/src/components/ui/button.module.css +141 -0
  127. package/src/components/ui/button.tsx +73 -0
  128. package/src/components/ui/color-picker.module.css +112 -0
  129. package/src/components/ui/color-picker.tsx +146 -0
  130. package/src/components/ui/input.module.css +49 -0
  131. package/src/components/ui/input.tsx +34 -0
  132. package/src/components/ui/popover.module.css +42 -0
  133. package/src/components/ui/popover.tsx +59 -0
  134. package/src/components/ui/select.module.css +160 -0
  135. package/src/components/ui/select.tsx +216 -0
  136. package/src/components/ui/slider.module.css +75 -0
  137. package/src/components/ui/slider.tsx +60 -0
  138. package/src/components/ui/textarea.module.css +30 -0
  139. package/src/components/ui/textarea.tsx +23 -0
  140. package/src/components/ui/tooltip.module.css +11 -0
  141. package/src/components/ui/tooltip.tsx +37 -0
  142. package/src/core/highlighter.ts +197 -0
  143. package/src/hooks/useMessageBridge.ts +49 -0
  144. package/src/hooks/useStylePreview.ts +332 -0
  145. package/src/index.ts +20 -0
  146. package/src/lib/utils.ts +5 -0
  147. package/src/plugin.ts +11 -0
  148. package/src/store/useInspectorStore.ts +235 -0
  149. package/src/styles/fonts.css +15 -0
  150. package/src/styles/global.css +138 -0
  151. package/src/styles/variables.css +151 -0
  152. package/src/styles.ts +5 -0
  153. package/src/utils/colorUtils.ts +133 -0
  154. package/src/utils/elementNames.ts +103 -0
  155. package/src/utils/elementUtils.ts +90 -0
  156. package/src/utils/errorTracker.ts +186 -0
  157. package/src/utils/inputStyles.ts +30 -0
  158. package/src/utils/styleUtils.ts +226 -0
  159. package/src/utils/tailwindMapper.ts +554 -0
  160. package/src/utils/urlTracker.ts +75 -0
  161. package/src/vite-env.d.ts +7 -0
  162. package/README.md +0 -866
  163. package/dist/hook.d.ts +0 -115
  164. package/dist/hook.d.ts.map +0 -1
  165. package/dist/hook.js +0 -288
  166. package/dist/plugin.d.ts +0 -44
  167. package/dist/plugin.d.ts.map +0 -1
  168. package/dist/types.d.ts +0 -139
  169. package/dist/types.d.ts.map +0 -1
  170. package/dist/types.js +0 -7
@@ -0,0 +1,349 @@
1
+ /**
2
+ * DisplaySection - Display mode and Opacity
3
+ */
4
+
5
+ import type { StyleChanges } from "@promakeai/inspector-types";
6
+ import { NumberInput } from "./NumberInput";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue,
13
+ } from "../ui/select";
14
+ import { RotateCcw } from "lucide-react";
15
+ import { useInspectorStore } from "../../store/useInspectorStore";
16
+ import styles from "./shared.module.css";
17
+
18
+ interface DisplaySectionProps {
19
+ styles: StyleChanges;
20
+ onChange: (property: keyof StyleChanges, value: string) => void;
21
+ originalStyles: StyleChanges;
22
+ onResetProperty: (property: keyof StyleChanges) => void;
23
+ }
24
+
25
+ export function DisplaySection({
26
+ styles: styleValues,
27
+ onChange,
28
+ originalStyles,
29
+ onResetProperty,
30
+ }: DisplaySectionProps) {
31
+ const { labels, theme } = useInspectorStore();
32
+
33
+ const DISPLAY_MODES = [
34
+ { label: labels.displayBlock || "Block", value: "block" },
35
+ { label: labels.displayInline || "Inline", value: "inline" },
36
+ { label: labels.displayInlineBlock || "Inline Block", value: "inline-block" },
37
+ { label: labels.displayFlex || "Flex", value: "flex" },
38
+ { label: labels.displayGrid || "Grid", value: "grid" },
39
+ { label: labels.displayNone || "None", value: "none" },
40
+ ];
41
+
42
+ const JUSTIFY_CONTENT_OPTIONS = [
43
+ { label: labels.justifyContentFlexStart || "Flex Start", value: "flex-start" },
44
+ { label: labels.justifyContentCenter || "Center", value: "center" },
45
+ { label: labels.justifyContentFlexEnd || "Flex End", value: "flex-end" },
46
+ { label: labels.justifyContentSpaceBetween || "Space Between", value: "space-between" },
47
+ { label: labels.justifyContentSpaceAround || "Space Around", value: "space-around" },
48
+ { label: labels.justifyContentSpaceEvenly || "Space Evenly", value: "space-evenly" },
49
+ ];
50
+
51
+ const ALIGN_ITEMS_OPTIONS = [
52
+ { label: labels.alignItemsFlexStart || "Flex Start", value: "flex-start" },
53
+ { label: labels.alignItemsCenter || "Center", value: "center" },
54
+ { label: labels.alignItemsFlexEnd || "Flex End", value: "flex-end" },
55
+ { label: labels.alignItemsStretch || "Stretch", value: "stretch" },
56
+ { label: labels.alignItemsBaseline || "Baseline", value: "baseline" },
57
+ ];
58
+
59
+ const FLEX_DIRECTION_OPTIONS = [
60
+ { label: labels.flexDirectionRow || "Row", value: "row" },
61
+ { label: labels.flexDirectionRowReverse || "Row Reverse", value: "row-reverse" },
62
+ { label: labels.flexDirectionColumn || "Column", value: "column" },
63
+ { label: labels.flexDirectionColumnReverse || "Column Reverse", value: "column-reverse" },
64
+ ];
65
+
66
+ return (
67
+ <div className={styles.section}>
68
+ {/* Display Mode and Opacity - Side by side */}
69
+ <div className={styles.grid2}>
70
+ {/* Display Mode */}
71
+ <div>
72
+ <div className={styles.labelContainer}>
73
+ <label className={styles.label} style={{ color: theme.textColor }}>
74
+ {labels.displayLabel || "Display"}
75
+ </label>
76
+ {styleValues.display !== originalStyles.display && (
77
+ <button
78
+ type="button"
79
+ onClick={() => onResetProperty("display")}
80
+ className={styles.resetIcon}
81
+ style={{ color: theme.secondaryTextColor }}
82
+ title="Reset to original"
83
+ >
84
+ <RotateCcw size={12} />
85
+ </button>
86
+ )}
87
+ </div>
88
+ <div
89
+ className={styles.inputContainer}
90
+ style={{
91
+ backgroundColor: theme.inputBackgroundColor,
92
+ borderColor: theme.inputBorderColor,
93
+ }}
94
+ >
95
+ <Select
96
+ value={styleValues.display || "block"}
97
+ onValueChange={(value) => onChange("display", value)}
98
+ >
99
+ <SelectTrigger
100
+ className={styles.input}
101
+ style={{
102
+ backgroundColor: "transparent",
103
+ color: theme.inputTextColor,
104
+ }}
105
+ size="sm"
106
+ >
107
+ <SelectValue />
108
+ </SelectTrigger>
109
+ <SelectContent
110
+ style={{
111
+ backgroundColor: theme.backgroundColor,
112
+ borderColor: theme.borderColor,
113
+ }}
114
+ >
115
+ {DISPLAY_MODES.map((mode) => (
116
+ <SelectItem
117
+ key={mode.value}
118
+ value={mode.value}
119
+ style={{
120
+ color: theme.textColor,
121
+ }}
122
+ >
123
+ {mode.label}
124
+ </SelectItem>
125
+ ))}
126
+ </SelectContent>
127
+ </Select>
128
+ </div>
129
+ </div>
130
+
131
+ {/* Opacity */}
132
+ <NumberInput
133
+ label={labels.opacityLabel || "Opacity"}
134
+ value={styleValues.opacity}
135
+ onChange={(value) => onChange("opacity", value)}
136
+ min={0}
137
+ max={1}
138
+ step={0.1}
139
+ unit=""
140
+ originalValue={originalStyles.opacity}
141
+ onReset={() => onResetProperty("opacity")}
142
+ />
143
+ </div>
144
+
145
+ {/* Flex and Flex Direction - Side by side */}
146
+ <div className={styles.grid2}>
147
+ {/* Flex */}
148
+ <NumberInput
149
+ label={labels.flexLabel || "Flex"}
150
+ value={styleValues.flex}
151
+ onChange={(value) => onChange("flex", value)}
152
+ min={0}
153
+ max={100}
154
+ step={1}
155
+ unit=""
156
+ originalValue={originalStyles.flex}
157
+ onReset={() => onResetProperty("flex")}
158
+ />
159
+
160
+ {/* Flex Direction */}
161
+ <div>
162
+ <div className={styles.labelContainer}>
163
+ <label className={styles.label} style={{ color: theme.textColor }}>
164
+ {labels.flexDirectionLabel || "Flex Direction"}
165
+ </label>
166
+ {styleValues.flexDirection !== originalStyles.flexDirection && (
167
+ <button
168
+ type="button"
169
+ onClick={() => onResetProperty("flexDirection")}
170
+ className={styles.resetIcon}
171
+ style={{ color: theme.secondaryTextColor }}
172
+ title="Reset to original"
173
+ >
174
+ <RotateCcw size={12} />
175
+ </button>
176
+ )}
177
+ </div>
178
+ <div
179
+ className={styles.inputContainer}
180
+ style={{
181
+ backgroundColor: theme.inputBackgroundColor,
182
+ borderColor: theme.inputBorderColor,
183
+ }}
184
+ >
185
+ <Select
186
+ value={styleValues.flexDirection || "row"}
187
+ onValueChange={(value) => onChange("flexDirection", value)}
188
+ >
189
+ <SelectTrigger
190
+ className={styles.input}
191
+ style={{
192
+ backgroundColor: "transparent",
193
+ color: theme.inputTextColor,
194
+ }}
195
+ size="sm"
196
+ >
197
+ <SelectValue />
198
+ </SelectTrigger>
199
+ <SelectContent
200
+ style={{
201
+ backgroundColor: theme.backgroundColor,
202
+ borderColor: theme.borderColor,
203
+ }}
204
+ >
205
+ {FLEX_DIRECTION_OPTIONS.map((option) => (
206
+ <SelectItem
207
+ key={option.value}
208
+ value={option.value}
209
+ style={{
210
+ color: theme.textColor,
211
+ }}
212
+ >
213
+ {option.label}
214
+ </SelectItem>
215
+ ))}
216
+ </SelectContent>
217
+ </Select>
218
+ </div>
219
+ </div>
220
+ </div>
221
+
222
+ {/* Justify Content and Align Items - Side by side */}
223
+ <div className={styles.grid2}>
224
+ {/* Justify Content */}
225
+ <div>
226
+ <div className={styles.labelContainer}>
227
+ <label className={styles.label} style={{ color: theme.textColor }}>
228
+ {labels.justifyContentLabel || "Justify Content"}
229
+ </label>
230
+ {styleValues.justifyContent !== originalStyles.justifyContent && (
231
+ <button
232
+ type="button"
233
+ onClick={() => onResetProperty("justifyContent")}
234
+ className={styles.resetIcon}
235
+ style={{ color: theme.secondaryTextColor }}
236
+ title="Reset to original"
237
+ >
238
+ <RotateCcw size={12} />
239
+ </button>
240
+ )}
241
+ </div>
242
+ <div
243
+ className={styles.inputContainer}
244
+ style={{
245
+ backgroundColor: theme.inputBackgroundColor,
246
+ borderColor: theme.inputBorderColor,
247
+ }}
248
+ >
249
+ <Select
250
+ value={styleValues.justifyContent || "flex-start"}
251
+ onValueChange={(value) => onChange("justifyContent", value)}
252
+ >
253
+ <SelectTrigger
254
+ className={styles.input}
255
+ style={{
256
+ backgroundColor: "transparent",
257
+ color: theme.inputTextColor,
258
+ }}
259
+ size="sm"
260
+ >
261
+ <SelectValue />
262
+ </SelectTrigger>
263
+ <SelectContent
264
+ style={{
265
+ backgroundColor: theme.backgroundColor,
266
+ borderColor: theme.borderColor,
267
+ }}
268
+ >
269
+ {JUSTIFY_CONTENT_OPTIONS.map((option) => (
270
+ <SelectItem
271
+ key={option.value}
272
+ value={option.value}
273
+ style={{
274
+ color: theme.textColor,
275
+ }}
276
+ >
277
+ {option.label}
278
+ </SelectItem>
279
+ ))}
280
+ </SelectContent>
281
+ </Select>
282
+ </div>
283
+ </div>
284
+
285
+ {/* Align Items */}
286
+ <div>
287
+ <div className={styles.labelContainer}>
288
+ <label className={styles.label} style={{ color: theme.textColor }}>
289
+ {labels.alignItemsLabel || "Align Items"}
290
+ </label>
291
+ {styleValues.alignItems !== originalStyles.alignItems && (
292
+ <button
293
+ type="button"
294
+ onClick={() => onResetProperty("alignItems")}
295
+ className={styles.resetIcon}
296
+ style={{ color: theme.secondaryTextColor }}
297
+ title="Reset to original"
298
+ >
299
+ <RotateCcw size={12} />
300
+ </button>
301
+ )}
302
+ </div>
303
+ <div
304
+ className={styles.inputContainer}
305
+ style={{
306
+ backgroundColor: theme.inputBackgroundColor,
307
+ borderColor: theme.inputBorderColor,
308
+ }}
309
+ >
310
+ <Select
311
+ value={styleValues.alignItems || "stretch"}
312
+ onValueChange={(value) => onChange("alignItems", value)}
313
+ >
314
+ <SelectTrigger
315
+ className={styles.input}
316
+ style={{
317
+ backgroundColor: "transparent",
318
+ color: theme.inputTextColor,
319
+ }}
320
+ size="sm"
321
+ >
322
+ <SelectValue />
323
+ </SelectTrigger>
324
+ <SelectContent
325
+ style={{
326
+ backgroundColor: theme.backgroundColor,
327
+ borderColor: theme.borderColor,
328
+ }}
329
+ >
330
+ {ALIGN_ITEMS_OPTIONS.map((option) => (
331
+ <SelectItem
332
+ key={option.value}
333
+ value={option.value}
334
+ style={{
335
+ color: theme.textColor,
336
+ }}
337
+ >
338
+ {option.label}
339
+ </SelectItem>
340
+ ))}
341
+ </SelectContent>
342
+ </Select>
343
+ </div>
344
+ </div>
345
+ </div>
346
+ </div>
347
+ );
348
+ }
349
+
@@ -0,0 +1,105 @@
1
+ /**
2
+ * ImageSection - Object Fit for image elements
3
+ */
4
+
5
+ import type { StyleChanges } from "@promakeai/inspector-types";
6
+ import {
7
+ Select,
8
+ SelectContent,
9
+ SelectItem,
10
+ SelectTrigger,
11
+ SelectValue,
12
+ } from "../ui/select";
13
+ import { RotateCcw } from "lucide-react";
14
+ import { useInspectorStore } from "../../store/useInspectorStore";
15
+ import styles from "./shared.module.css";
16
+
17
+ interface ImageSectionProps {
18
+ styles: StyleChanges;
19
+ onChange: (property: keyof StyleChanges, value: string) => void;
20
+ originalStyles: StyleChanges;
21
+ onResetProperty: (property: keyof StyleChanges) => void;
22
+ }
23
+
24
+ export function ImageSection({
25
+ styles: styleValues,
26
+ onChange,
27
+ originalStyles,
28
+ onResetProperty,
29
+ }: ImageSectionProps) {
30
+ const { labels, theme } = useInspectorStore();
31
+
32
+ const OBJECT_FIT_OPTIONS = [
33
+ { label: labels.objectFitFill || "Fill", value: "fill" },
34
+ { label: labels.objectFitContain || "Contain", value: "contain" },
35
+ { label: labels.objectFitCover || "Cover", value: "cover" },
36
+ { label: labels.objectFitNone || "None", value: "none" },
37
+ { label: labels.objectFitScaleDown || "Scale Down", value: "scale-down" },
38
+ ];
39
+
40
+ return (
41
+ <div className={styles.section}>
42
+ {/* Object Fit */}
43
+ <div>
44
+ <div className={styles.labelContainer}>
45
+ <label className={styles.label} style={{ color: theme.textColor }}>
46
+ {labels.objectFitLabel || "Object Fit"}
47
+ </label>
48
+ {styleValues.objectFit !== originalStyles.objectFit && (
49
+ <button
50
+ type="button"
51
+ onClick={() => onResetProperty("objectFit")}
52
+ className={styles.resetIcon}
53
+ style={{ color: theme.secondaryTextColor }}
54
+ title="Reset to original"
55
+ >
56
+ <RotateCcw size={12} />
57
+ </button>
58
+ )}
59
+ </div>
60
+ <div
61
+ className={styles.inputContainer}
62
+ style={{
63
+ backgroundColor: theme.inputBackgroundColor,
64
+ borderColor: theme.inputBorderColor,
65
+ }}
66
+ >
67
+ <Select
68
+ value={styleValues.objectFit || "fill"}
69
+ onValueChange={(value) => onChange("objectFit", value)}
70
+ >
71
+ <SelectTrigger
72
+ className={styles.input}
73
+ style={{
74
+ backgroundColor: "transparent",
75
+ color: theme.inputTextColor,
76
+ }}
77
+ size="sm"
78
+ >
79
+ <SelectValue />
80
+ </SelectTrigger>
81
+ <SelectContent
82
+ style={{
83
+ backgroundColor: theme.backgroundColor,
84
+ borderColor: theme.borderColor,
85
+ }}
86
+ >
87
+ {OBJECT_FIT_OPTIONS.map((option) => (
88
+ <SelectItem
89
+ key={option.value}
90
+ value={option.value}
91
+ style={{
92
+ color: theme.textColor,
93
+ }}
94
+ >
95
+ {option.label}
96
+ </SelectItem>
97
+ ))}
98
+ </SelectContent>
99
+ </Select>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ );
104
+ }
105
+
@@ -0,0 +1,63 @@
1
+ /**
2
+ * LayoutSection - Background Color, Height, Width
3
+ */
4
+
5
+ import type { StyleChanges } from "@promakeai/inspector-types";
6
+ import { ColorPicker } from "./ColorPicker";
7
+ import { NumberInput } from "./NumberInput";
8
+ import { useInspectorStore } from "../../store/useInspectorStore";
9
+ import styles from "./shared.module.css";
10
+
11
+ interface LayoutSectionProps {
12
+ styles: StyleChanges;
13
+ onChange: (property: keyof StyleChanges, value: string) => void;
14
+ originalStyles: StyleChanges;
15
+ onResetProperty: (property: keyof StyleChanges) => void;
16
+ }
17
+
18
+ export function LayoutSection({
19
+ styles: styleValues,
20
+ onChange,
21
+ originalStyles,
22
+ onResetProperty
23
+ }: LayoutSectionProps) {
24
+ const { labels } = useInspectorStore();
25
+
26
+ return (
27
+ <div className={styles.section}>
28
+ <ColorPicker
29
+ label={labels.backgroundColorLabel || "Background Color"}
30
+ value={styleValues.backgroundColor || "#ffffff"}
31
+ onChange={(value) => onChange("backgroundColor", value)}
32
+ originalValue={originalStyles.backgroundColor}
33
+ onReset={() => onResetProperty("backgroundColor")}
34
+ />
35
+
36
+ <div className={styles.grid2}>
37
+ <NumberInput
38
+ label={labels.heightLabel || "Height"}
39
+ value={styleValues.height}
40
+ onChange={(value) => onChange("height", value)}
41
+ min={0}
42
+ max={2000}
43
+ step={1}
44
+ unit="px"
45
+ originalValue={originalStyles.height}
46
+ onReset={() => onResetProperty("height")}
47
+ />
48
+
49
+ <NumberInput
50
+ label={labels.widthLabel || "Width"}
51
+ value={styleValues.width}
52
+ onChange={(value) => onChange("width", value)}
53
+ min={0}
54
+ max={2000}
55
+ step={1}
56
+ unit="px"
57
+ originalValue={originalStyles.width}
58
+ onReset={() => onResetProperty("width")}
59
+ />
60
+ </div>
61
+ </div>
62
+ );
63
+ }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * NumberInput - Input with drag-to-adjust handle (Figma-style)
3
+ */
4
+
5
+ import { useState, useRef, useEffect } from "react";
6
+ import { Input } from "../ui/input";
7
+ import { GripVertical, RotateCcw } from "lucide-react";
8
+ import { useInspectorStore } from "../../store/useInspectorStore";
9
+ import styles from "./shared.module.css";
10
+
11
+ interface NumberInputProps {
12
+ label: string;
13
+ value: string | undefined;
14
+ onChange: (value: string) => void;
15
+ min?: number;
16
+ max?: number;
17
+ step?: number;
18
+ unit?: string;
19
+ originalValue?: string;
20
+ onReset?: () => void;
21
+ }
22
+
23
+ export function NumberInput({
24
+ label,
25
+ value,
26
+ onChange,
27
+ min = 0,
28
+ max = 1000,
29
+ step = 1,
30
+ unit = "px",
31
+ originalValue,
32
+ onReset,
33
+ }: NumberInputProps) {
34
+ const { labels, theme } = useInspectorStore();
35
+ const hasChanged = originalValue !== undefined && value !== originalValue;
36
+ const [isDragging, setIsDragging] = useState(false);
37
+ const dragStartX = useRef(0);
38
+ const dragStartValue = useRef(0);
39
+ const dragHandleRef = useRef<HTMLDivElement>(null);
40
+
41
+ const parseValue = (val: string | undefined): number => {
42
+ if (!val) return 0;
43
+ const parsed = parseFloat(val.replace(/[^\d.-]/g, ""));
44
+ return isNaN(parsed) ? 0 : parsed;
45
+ };
46
+
47
+ const currentValue = parseValue(value);
48
+
49
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
50
+ onChange(e.target.value);
51
+ };
52
+
53
+ useEffect(() => {
54
+ if (!isDragging) return;
55
+
56
+ const handleMouseMove = (e: MouseEvent) => {
57
+ const deltaX = e.clientX - dragStartX.current;
58
+ const deltaValue = Math.round(deltaX / 2) * step; // 2px movement = 1 step
59
+ let newValue = dragStartValue.current + deltaValue;
60
+
61
+ // Clamp value
62
+ newValue = Math.max(min, Math.min(max, newValue));
63
+
64
+ onChange(`${newValue}${unit}`);
65
+ };
66
+
67
+ const handleMouseUp = () => {
68
+ setIsDragging(false);
69
+ document.body.style.cursor = "";
70
+ };
71
+
72
+ document.addEventListener("mousemove", handleMouseMove);
73
+ document.addEventListener("mouseup", handleMouseUp);
74
+
75
+ return () => {
76
+ document.removeEventListener("mousemove", handleMouseMove);
77
+ document.removeEventListener("mouseup", handleMouseUp);
78
+ };
79
+ }, [isDragging, step, min, max, unit, onChange]);
80
+
81
+ const handleDragStart = (e: React.MouseEvent) => {
82
+ e.preventDefault();
83
+ setIsDragging(true);
84
+ dragStartX.current = e.clientX;
85
+ dragStartValue.current = currentValue;
86
+ document.body.style.cursor = "ew-resize";
87
+ };
88
+
89
+ return (
90
+ <div className={styles.inputField}>
91
+ <div className={styles.labelContainer}>
92
+ <label className={styles.label} style={{ color: theme.textColor }}>
93
+ {label}
94
+ </label>
95
+ {hasChanged && onReset && (
96
+ <button
97
+ type="button"
98
+ onClick={onReset}
99
+ className={styles.resetIcon}
100
+ style={{ color: theme.secondaryTextColor }}
101
+ title="Reset to original"
102
+ >
103
+ <RotateCcw size={12} />
104
+ </button>
105
+ )}
106
+ </div>
107
+ <div
108
+ className={styles.inputContainer}
109
+ style={{
110
+ backgroundColor: theme.inputBackgroundColor,
111
+ borderColor: theme.inputBorderColor,
112
+ }}
113
+ >
114
+ <Input
115
+ type="text"
116
+ value={value || ""}
117
+ onChange={handleInputChange}
118
+ className={styles.input}
119
+ style={{
120
+ backgroundColor: "transparent",
121
+ color: theme.inputTextColor,
122
+ }}
123
+ />
124
+ <div
125
+ ref={dragHandleRef}
126
+ onMouseDown={handleDragStart}
127
+ className={styles.dragHandle}
128
+ style={{
129
+ color: theme.secondaryTextColor || theme.textColor,
130
+ opacity: isDragging ? 1 : 0.6,
131
+ }}
132
+ >
133
+ <GripVertical className={styles.dragHandleIcon} />
134
+ </div>
135
+ </div>
136
+ </div>
137
+ );
138
+ }