@aprovan/patchwork 0.1.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 (225) hide show
  1. package/.eslintrc.json +22 -0
  2. package/.github/workflows/publish.yml +41 -0
  3. package/.prettierignore +17 -0
  4. package/LICENSE +373 -0
  5. package/README.md +15 -0
  6. package/apps/chat/.utcp_config.json +14 -0
  7. package/apps/chat/.working/widgets/27060b91-a2a5-4272-b243-6eb904bd4070/main.tsx +107 -0
  8. package/apps/chat/index.html +17 -0
  9. package/apps/chat/node_modules/.bin/autoprefixer +17 -0
  10. package/apps/chat/node_modules/.bin/browserslist +17 -0
  11. package/apps/chat/node_modules/.bin/conc +17 -0
  12. package/apps/chat/node_modules/.bin/concurrently +17 -0
  13. package/apps/chat/node_modules/.bin/copilot-proxy +17 -0
  14. package/apps/chat/node_modules/.bin/jiti +17 -0
  15. package/apps/chat/node_modules/.bin/tailwind +17 -0
  16. package/apps/chat/node_modules/.bin/tailwindcss +17 -0
  17. package/apps/chat/node_modules/.bin/tsc +17 -0
  18. package/apps/chat/node_modules/.bin/tsserver +17 -0
  19. package/apps/chat/node_modules/.bin/tsx +17 -0
  20. package/apps/chat/node_modules/.bin/vite +17 -0
  21. package/apps/chat/package.json +55 -0
  22. package/apps/chat/postcss.config.js +6 -0
  23. package/apps/chat/src/App.tsx +7 -0
  24. package/apps/chat/src/components/ui/avatar.tsx +48 -0
  25. package/apps/chat/src/components/ui/badge.tsx +36 -0
  26. package/apps/chat/src/components/ui/button.tsx +56 -0
  27. package/apps/chat/src/components/ui/card.tsx +86 -0
  28. package/apps/chat/src/components/ui/collapsible.tsx +9 -0
  29. package/apps/chat/src/components/ui/dialog.tsx +60 -0
  30. package/apps/chat/src/components/ui/input.tsx +25 -0
  31. package/apps/chat/src/components/ui/scroll-area.tsx +46 -0
  32. package/apps/chat/src/index.css +190 -0
  33. package/apps/chat/src/lib/utils.ts +6 -0
  34. package/apps/chat/src/main.tsx +10 -0
  35. package/apps/chat/src/pages/ChatPage.tsx +460 -0
  36. package/apps/chat/tailwind.config.js +71 -0
  37. package/apps/chat/tsconfig.json +25 -0
  38. package/apps/chat/vite.config.ts +26 -0
  39. package/package.json +35 -0
  40. package/packages/bobbin/node_modules/.bin/esbuild +14 -0
  41. package/packages/bobbin/node_modules/.bin/jiti +17 -0
  42. package/packages/bobbin/node_modules/.bin/tsc +17 -0
  43. package/packages/bobbin/node_modules/.bin/tsserver +17 -0
  44. package/packages/bobbin/node_modules/.bin/tsup +17 -0
  45. package/packages/bobbin/node_modules/.bin/tsup-node +17 -0
  46. package/packages/bobbin/node_modules/.bin/tsx +17 -0
  47. package/packages/bobbin/package.json +30 -0
  48. package/packages/bobbin/src/Bobbin.tsx +89 -0
  49. package/packages/bobbin/src/components/EditPanel/EditPanel.tsx +376 -0
  50. package/packages/bobbin/src/components/EditPanel/controls/ColorPicker.tsx +138 -0
  51. package/packages/bobbin/src/components/EditPanel/controls/QuickSelectDropdown.tsx +142 -0
  52. package/packages/bobbin/src/components/EditPanel/controls/SliderInput.tsx +94 -0
  53. package/packages/bobbin/src/components/EditPanel/controls/SpacingControl.tsx +285 -0
  54. package/packages/bobbin/src/components/EditPanel/controls/ToggleGroup.tsx +37 -0
  55. package/packages/bobbin/src/components/EditPanel/controls/TokenDropdown.tsx +33 -0
  56. package/packages/bobbin/src/components/EditPanel/sections/AnnotationSection.tsx +136 -0
  57. package/packages/bobbin/src/components/EditPanel/sections/BackgroundSection.tsx +79 -0
  58. package/packages/bobbin/src/components/EditPanel/sections/EffectsSection.tsx +85 -0
  59. package/packages/bobbin/src/components/EditPanel/sections/LayoutSection.tsx +224 -0
  60. package/packages/bobbin/src/components/EditPanel/sections/SectionWrapper.tsx +57 -0
  61. package/packages/bobbin/src/components/EditPanel/sections/SizeSection.tsx +166 -0
  62. package/packages/bobbin/src/components/EditPanel/sections/SpacingSection.tsx +69 -0
  63. package/packages/bobbin/src/components/EditPanel/sections/TypographySection.tsx +148 -0
  64. package/packages/bobbin/src/components/Inspector/Inspector.tsx +221 -0
  65. package/packages/bobbin/src/components/Overlay/ControlHandles.tsx +572 -0
  66. package/packages/bobbin/src/components/Overlay/MarginPaddingOverlay.tsx +229 -0
  67. package/packages/bobbin/src/components/Overlay/SelectionOverlay.tsx +73 -0
  68. package/packages/bobbin/src/components/Pill/Pill.tsx +155 -0
  69. package/packages/bobbin/src/components/ThemeToggle/ThemeToggle.tsx +72 -0
  70. package/packages/bobbin/src/core/changeSerializer.ts +139 -0
  71. package/packages/bobbin/src/core/useBobbin.ts +399 -0
  72. package/packages/bobbin/src/core/useChangeTracker.ts +186 -0
  73. package/packages/bobbin/src/core/useClipboard.ts +21 -0
  74. package/packages/bobbin/src/core/useElementSelection.ts +146 -0
  75. package/packages/bobbin/src/index.ts +46 -0
  76. package/packages/bobbin/src/tokens/borders.ts +19 -0
  77. package/packages/bobbin/src/tokens/colors.ts +150 -0
  78. package/packages/bobbin/src/tokens/index.ts +37 -0
  79. package/packages/bobbin/src/tokens/shadows.ts +10 -0
  80. package/packages/bobbin/src/tokens/spacing.ts +37 -0
  81. package/packages/bobbin/src/tokens/typography.ts +51 -0
  82. package/packages/bobbin/src/types.ts +157 -0
  83. package/packages/bobbin/src/utils/animation.ts +40 -0
  84. package/packages/bobbin/src/utils/dom.ts +36 -0
  85. package/packages/bobbin/src/utils/selectors.ts +76 -0
  86. package/packages/bobbin/tsconfig.json +10 -0
  87. package/packages/bobbin/tsup.config.ts +10 -0
  88. package/packages/compiler/node_modules/.bin/esbuild +17 -0
  89. package/packages/compiler/node_modules/.bin/jiti +17 -0
  90. package/packages/compiler/node_modules/.bin/tsc +17 -0
  91. package/packages/compiler/node_modules/.bin/tsserver +17 -0
  92. package/packages/compiler/node_modules/.bin/tsup +17 -0
  93. package/packages/compiler/node_modules/.bin/tsup-node +17 -0
  94. package/packages/compiler/node_modules/.bin/tsx +17 -0
  95. package/packages/compiler/package.json +38 -0
  96. package/packages/compiler/src/compiler.ts +258 -0
  97. package/packages/compiler/src/images/index.ts +13 -0
  98. package/packages/compiler/src/images/loader.ts +234 -0
  99. package/packages/compiler/src/images/registry.ts +112 -0
  100. package/packages/compiler/src/index.ts +141 -0
  101. package/packages/compiler/src/mount/bridge.ts +399 -0
  102. package/packages/compiler/src/mount/embedded.ts +306 -0
  103. package/packages/compiler/src/mount/iframe.ts +433 -0
  104. package/packages/compiler/src/mount/index.ts +18 -0
  105. package/packages/compiler/src/schemas.ts +169 -0
  106. package/packages/compiler/src/transforms/cdn.ts +411 -0
  107. package/packages/compiler/src/transforms/index.ts +4 -0
  108. package/packages/compiler/src/transforms/vfs.ts +138 -0
  109. package/packages/compiler/src/types.ts +233 -0
  110. package/packages/compiler/src/vfs/backends/indexeddb.ts +66 -0
  111. package/packages/compiler/src/vfs/backends/local-fs.ts +41 -0
  112. package/packages/compiler/src/vfs/backends/s3.ts +60 -0
  113. package/packages/compiler/src/vfs/index.ts +11 -0
  114. package/packages/compiler/src/vfs/project.ts +56 -0
  115. package/packages/compiler/src/vfs/store.ts +53 -0
  116. package/packages/compiler/src/vfs/types.ts +20 -0
  117. package/packages/compiler/tsconfig.json +8 -0
  118. package/packages/compiler/tsup.config.ts +14 -0
  119. package/packages/editor/node_modules/.bin/jiti +17 -0
  120. package/packages/editor/node_modules/.bin/tsc +17 -0
  121. package/packages/editor/node_modules/.bin/tsserver +17 -0
  122. package/packages/editor/node_modules/.bin/tsup +17 -0
  123. package/packages/editor/node_modules/.bin/tsup-node +17 -0
  124. package/packages/editor/node_modules/.bin/tsx +17 -0
  125. package/packages/editor/package.json +45 -0
  126. package/packages/editor/src/components/CodeBlockExtension.tsx +190 -0
  127. package/packages/editor/src/components/CodePreview.tsx +344 -0
  128. package/packages/editor/src/components/MarkdownEditor.tsx +270 -0
  129. package/packages/editor/src/components/ServicesInspector.tsx +118 -0
  130. package/packages/editor/src/components/edit/EditHistory.tsx +89 -0
  131. package/packages/editor/src/components/edit/EditModal.tsx +236 -0
  132. package/packages/editor/src/components/edit/FileTree.tsx +144 -0
  133. package/packages/editor/src/components/edit/api.ts +100 -0
  134. package/packages/editor/src/components/edit/index.ts +6 -0
  135. package/packages/editor/src/components/edit/types.ts +53 -0
  136. package/packages/editor/src/components/edit/useEditSession.ts +164 -0
  137. package/packages/editor/src/components/index.ts +5 -0
  138. package/packages/editor/src/index.ts +72 -0
  139. package/packages/editor/src/lib/code-extractor.ts +210 -0
  140. package/packages/editor/src/lib/diff.ts +308 -0
  141. package/packages/editor/src/lib/index.ts +4 -0
  142. package/packages/editor/src/lib/utils.ts +6 -0
  143. package/packages/editor/src/lib/vfs.ts +106 -0
  144. package/packages/editor/tsconfig.json +10 -0
  145. package/packages/editor/tsup.config.ts +10 -0
  146. package/packages/images/ink/node_modules/.bin/jiti +17 -0
  147. package/packages/images/ink/node_modules/.bin/tsc +17 -0
  148. package/packages/images/ink/node_modules/.bin/tsserver +17 -0
  149. package/packages/images/ink/node_modules/.bin/tsup +17 -0
  150. package/packages/images/ink/node_modules/.bin/tsup-node +17 -0
  151. package/packages/images/ink/node_modules/.bin/tsx +17 -0
  152. package/packages/images/ink/package.json +53 -0
  153. package/packages/images/ink/src/index.ts +48 -0
  154. package/packages/images/ink/src/runner.ts +331 -0
  155. package/packages/images/ink/src/setup.ts +123 -0
  156. package/packages/images/ink/tsconfig.json +10 -0
  157. package/packages/images/ink/tsup.config.ts +11 -0
  158. package/packages/images/shadcn/node_modules/.bin/jiti +17 -0
  159. package/packages/images/shadcn/node_modules/.bin/tsc +17 -0
  160. package/packages/images/shadcn/node_modules/.bin/tsserver +17 -0
  161. package/packages/images/shadcn/node_modules/.bin/tsup +17 -0
  162. package/packages/images/shadcn/node_modules/.bin/tsup-node +17 -0
  163. package/packages/images/shadcn/node_modules/.bin/tsx +17 -0
  164. package/packages/images/shadcn/package.json +82 -0
  165. package/packages/images/shadcn/src/html.ts +341 -0
  166. package/packages/images/shadcn/src/index.ts +37 -0
  167. package/packages/images/shadcn/src/setup.ts +287 -0
  168. package/packages/images/shadcn/tsconfig.json +9 -0
  169. package/packages/images/shadcn/tsup.config.ts +13 -0
  170. package/packages/images/vanilla/node_modules/.bin/jiti +17 -0
  171. package/packages/images/vanilla/node_modules/.bin/tsc +17 -0
  172. package/packages/images/vanilla/node_modules/.bin/tsserver +17 -0
  173. package/packages/images/vanilla/node_modules/.bin/tsup +17 -0
  174. package/packages/images/vanilla/node_modules/.bin/tsup-node +17 -0
  175. package/packages/images/vanilla/node_modules/.bin/tsx +17 -0
  176. package/packages/images/vanilla/package.json +35 -0
  177. package/packages/images/vanilla/src/index.ts +7 -0
  178. package/packages/images/vanilla/src/setup.ts +6 -0
  179. package/packages/images/vanilla/tsconfig.json +9 -0
  180. package/packages/images/vanilla/tsup.config.ts +10 -0
  181. package/packages/patchwork/node_modules/.bin/jiti +17 -0
  182. package/packages/patchwork/node_modules/.bin/tsc +17 -0
  183. package/packages/patchwork/node_modules/.bin/tsserver +17 -0
  184. package/packages/patchwork/node_modules/.bin/tsup +17 -0
  185. package/packages/patchwork/node_modules/.bin/tsup-node +17 -0
  186. package/packages/patchwork/node_modules/.bin/tsx +17 -0
  187. package/packages/patchwork/package.json +27 -0
  188. package/packages/patchwork/src/index.ts +15 -0
  189. package/packages/patchwork/src/services/index.ts +11 -0
  190. package/packages/patchwork/src/services/proxy.ts +213 -0
  191. package/packages/patchwork/src/services/types.ts +28 -0
  192. package/packages/patchwork/src/types.ts +116 -0
  193. package/packages/patchwork/tsconfig.json +8 -0
  194. package/packages/patchwork/tsup.config.ts +14 -0
  195. package/packages/stitchery/node_modules/.bin/jiti +17 -0
  196. package/packages/stitchery/node_modules/.bin/tsc +17 -0
  197. package/packages/stitchery/node_modules/.bin/tsserver +17 -0
  198. package/packages/stitchery/node_modules/.bin/tsup +17 -0
  199. package/packages/stitchery/node_modules/.bin/tsup-node +17 -0
  200. package/packages/stitchery/node_modules/.bin/tsx +17 -0
  201. package/packages/stitchery/package.json +40 -0
  202. package/packages/stitchery/src/cli.ts +116 -0
  203. package/packages/stitchery/src/index.ts +16 -0
  204. package/packages/stitchery/src/prompts.ts +326 -0
  205. package/packages/stitchery/src/server/index.ts +365 -0
  206. package/packages/stitchery/src/server/local-packages.ts +91 -0
  207. package/packages/stitchery/src/server/routes.ts +122 -0
  208. package/packages/stitchery/src/server/services.ts +382 -0
  209. package/packages/stitchery/src/server/vfs-routes.ts +142 -0
  210. package/packages/stitchery/src/types.ts +59 -0
  211. package/packages/stitchery/tsconfig.json +13 -0
  212. package/packages/stitchery/tsup.config.ts +15 -0
  213. package/packages/utcp/node_modules/.bin/jiti +17 -0
  214. package/packages/utcp/node_modules/.bin/tsc +17 -0
  215. package/packages/utcp/node_modules/.bin/tsserver +17 -0
  216. package/packages/utcp/node_modules/.bin/tsup +17 -0
  217. package/packages/utcp/node_modules/.bin/tsup-node +17 -0
  218. package/packages/utcp/node_modules/.bin/tsx +17 -0
  219. package/packages/utcp/package.json +38 -0
  220. package/packages/utcp/src/index.ts +153 -0
  221. package/packages/utcp/tsconfig.json +8 -0
  222. package/packages/utcp/tsup.config.ts +12 -0
  223. package/pnpm-workspace.yaml +3 -0
  224. package/tsconfig.json +18 -0
  225. package/turbo.json +23 -0
@@ -0,0 +1,146 @@
1
+ import { useState, useCallback, useEffect, useRef } from 'react';
2
+ import type { SelectedElement } from '../types';
3
+ import { getElementPath, getElementXPath } from '../utils/selectors';
4
+
5
+ export interface UseElementSelectionOptions {
6
+ container?: HTMLElement | null;
7
+ exclude?: string[];
8
+ enabled?: boolean;
9
+ }
10
+
11
+ export function useElementSelection(options: UseElementSelectionOptions) {
12
+ const { container, exclude = [], enabled = true } = options;
13
+
14
+ const [hoveredElement, setHoveredElement] = useState<SelectedElement | null>(
15
+ null,
16
+ );
17
+ const [selectedElement, setSelectedElement] =
18
+ useState<SelectedElement | null>(null);
19
+ const lastRectRef = useRef<DOMRect | null>(null);
20
+
21
+ const isExcluded = useCallback(
22
+ (el: HTMLElement): boolean => {
23
+ // Exclude bobbin elements themselves
24
+ if (el.closest('[data-bobbin]')) return true;
25
+ // Exclude user-specified selectors
26
+ return exclude.some(
27
+ (selector) => el.matches(selector) || el.closest(selector),
28
+ );
29
+ },
30
+ [exclude],
31
+ );
32
+
33
+ const createSelectedElement = useCallback(
34
+ (el: HTMLElement): SelectedElement => {
35
+ return {
36
+ element: el,
37
+ rect: el.getBoundingClientRect(),
38
+ path: getElementPath(el),
39
+ xpath: getElementXPath(el),
40
+ tagName: el.tagName.toLowerCase(),
41
+ id: el.id || undefined,
42
+ classList: Array.from(el.classList),
43
+ };
44
+ },
45
+ [],
46
+ );
47
+
48
+ const handleMouseMove = useCallback(
49
+ (e: MouseEvent) => {
50
+ if (!enabled) return;
51
+
52
+ const target = document.elementFromPoint(
53
+ e.clientX,
54
+ e.clientY,
55
+ ) as HTMLElement | null;
56
+ if (!target || isExcluded(target)) {
57
+ setHoveredElement(null);
58
+ return;
59
+ }
60
+
61
+ // Check if within container bounds
62
+ if (container && !container.contains(target)) {
63
+ setHoveredElement(null);
64
+ return;
65
+ }
66
+
67
+ setHoveredElement(createSelectedElement(target));
68
+ },
69
+ [enabled, container, isExcluded, createSelectedElement],
70
+ );
71
+
72
+ const handleClick = useCallback(
73
+ (e: MouseEvent) => {
74
+ if (!enabled) return;
75
+
76
+ // Don't intercept clicks on bobbin UI elements
77
+ const target = e.target as HTMLElement;
78
+ if (target.closest('[data-bobbin]')) {
79
+ return;
80
+ }
81
+
82
+ if (!hoveredElement) return;
83
+
84
+ e.preventDefault();
85
+ e.stopPropagation();
86
+
87
+ setSelectedElement(hoveredElement);
88
+ lastRectRef.current = hoveredElement.rect;
89
+ },
90
+ [enabled, hoveredElement],
91
+ );
92
+
93
+ const clearSelection = useCallback(() => {
94
+ setSelectedElement(null);
95
+ setHoveredElement(null);
96
+ }, []);
97
+
98
+ const selectElement = useCallback(
99
+ (el: HTMLElement | null) => {
100
+ if (!el) {
101
+ clearSelection();
102
+ return;
103
+ }
104
+ setSelectedElement(createSelectedElement(el));
105
+ },
106
+ [createSelectedElement, clearSelection],
107
+ );
108
+
109
+ useEffect(() => {
110
+ if (!enabled) return;
111
+
112
+ document.addEventListener('mousemove', handleMouseMove, { passive: true });
113
+ document.addEventListener('click', handleClick, { capture: true });
114
+
115
+ return () => {
116
+ document.removeEventListener('mousemove', handleMouseMove);
117
+ document.removeEventListener('click', handleClick, { capture: true });
118
+ };
119
+ }, [enabled, handleMouseMove, handleClick]);
120
+
121
+ // Update rect on scroll/resize
122
+ useEffect(() => {
123
+ if (!selectedElement) return;
124
+
125
+ const updateRect = () => {
126
+ const newRect = selectedElement.element.getBoundingClientRect();
127
+ setSelectedElement((prev) => (prev ? { ...prev, rect: newRect } : null));
128
+ };
129
+
130
+ window.addEventListener('scroll', updateRect, { passive: true });
131
+ window.addEventListener('resize', updateRect, { passive: true });
132
+
133
+ return () => {
134
+ window.removeEventListener('scroll', updateRect);
135
+ window.removeEventListener('resize', updateRect);
136
+ };
137
+ }, [selectedElement?.element]);
138
+
139
+ return {
140
+ hoveredElement,
141
+ selectedElement,
142
+ selectElement,
143
+ clearSelection,
144
+ lastRect: lastRectRef.current,
145
+ };
146
+ }
@@ -0,0 +1,46 @@
1
+ // Main component
2
+ export { Bobbin } from './Bobbin';
3
+ export type { BobbinComponentProps } from './Bobbin';
4
+
5
+ // Hooks
6
+ export { useBobbin } from './core/useBobbin';
7
+ export { useElementSelection } from './core/useElementSelection';
8
+ export { useChangeTracker } from './core/useChangeTracker';
9
+ export { useClipboard } from './core/useClipboard';
10
+
11
+ // Utilities
12
+ export {
13
+ serializeChangesToYAML,
14
+ parseYAMLChangeset,
15
+ } from './core/changeSerializer';
16
+ export { getElementPath, getElementXPath, generateId } from './utils/selectors';
17
+
18
+ // Types
19
+ export type {
20
+ BobbinProps,
21
+ BobbinState,
22
+ BobbinActions,
23
+ SelectedElement,
24
+ Change,
25
+ ChangeType,
26
+ StyleChange,
27
+ TextChange,
28
+ MoveChange,
29
+ Annotation,
30
+ DesignTokens,
31
+ BobbinChangeset,
32
+ } from './types';
33
+
34
+ // Tokens
35
+ export { defaultTokens } from './tokens';
36
+ export { colors } from './tokens/colors';
37
+ export { spacing } from './tokens/spacing';
38
+ export {
39
+ fontSize,
40
+ fontWeight,
41
+ fontFamily,
42
+ lineHeight,
43
+ letterSpacing,
44
+ } from './tokens/typography';
45
+ export { borderRadius, borderWidth } from './tokens/borders';
46
+ export { boxShadow } from './tokens/shadows';
@@ -0,0 +1,19 @@
1
+ export const borderRadius: Record<string, string> = {
2
+ none: '0px',
3
+ sm: '0.125rem',
4
+ DEFAULT: '0.25rem',
5
+ md: '0.375rem',
6
+ lg: '0.5rem',
7
+ xl: '0.75rem',
8
+ '2xl': '1rem',
9
+ '3xl': '1.5rem',
10
+ full: '9999px',
11
+ };
12
+
13
+ export const borderWidth: Record<string, string> = {
14
+ '0': '0px',
15
+ DEFAULT: '1px',
16
+ '2': '2px',
17
+ '4': '4px',
18
+ '8': '8px',
19
+ };
@@ -0,0 +1,150 @@
1
+ export const colors = {
2
+ slate: {
3
+ 50: '#f8fafc',
4
+ 100: '#f1f5f9',
5
+ 200: '#e2e8f0',
6
+ 300: '#cbd5e1',
7
+ 400: '#94a3b8',
8
+ 500: '#64748b',
9
+ 600: '#475569',
10
+ 700: '#334155',
11
+ 800: '#1e293b',
12
+ 900: '#0f172a',
13
+ 950: '#020617',
14
+ },
15
+ gray: {
16
+ 50: '#f9fafb',
17
+ 100: '#f3f4f6',
18
+ 200: '#e5e7eb',
19
+ 300: '#d1d5db',
20
+ 400: '#9ca3af',
21
+ 500: '#6b7280',
22
+ 600: '#4b5563',
23
+ 700: '#374151',
24
+ 800: '#1f2937',
25
+ 900: '#111827',
26
+ 950: '#030712',
27
+ },
28
+ zinc: {
29
+ 50: '#fafafa',
30
+ 100: '#f4f4f5',
31
+ 200: '#e4e4e7',
32
+ 300: '#d4d4d8',
33
+ 400: '#a1a1aa',
34
+ 500: '#71717a',
35
+ 600: '#52525b',
36
+ 700: '#3f3f46',
37
+ 800: '#27272a',
38
+ 900: '#18181b',
39
+ 950: '#09090b',
40
+ },
41
+ red: {
42
+ 50: '#fef2f2',
43
+ 100: '#fee2e2',
44
+ 200: '#fecaca',
45
+ 300: '#fca5a5',
46
+ 400: '#f87171',
47
+ 500: '#ef4444',
48
+ 600: '#dc2626',
49
+ 700: '#b91c1c',
50
+ 800: '#991b1b',
51
+ 900: '#7f1d1d',
52
+ 950: '#450a0a',
53
+ },
54
+ orange: {
55
+ 50: '#fff7ed',
56
+ 100: '#ffedd5',
57
+ 200: '#fed7aa',
58
+ 300: '#fdba74',
59
+ 400: '#fb923c',
60
+ 500: '#f97316',
61
+ 600: '#ea580c',
62
+ 700: '#c2410c',
63
+ 800: '#9a3412',
64
+ 900: '#7c2d12',
65
+ 950: '#431407',
66
+ },
67
+ yellow: {
68
+ 50: '#fefce8',
69
+ 100: '#fef9c3',
70
+ 200: '#fef08a',
71
+ 300: '#fde047',
72
+ 400: '#facc15',
73
+ 500: '#eab308',
74
+ 600: '#ca8a04',
75
+ 700: '#a16207',
76
+ 800: '#854d0e',
77
+ 900: '#713f12',
78
+ 950: '#422006',
79
+ },
80
+ green: {
81
+ 50: '#f0fdf4',
82
+ 100: '#dcfce7',
83
+ 200: '#bbf7d0',
84
+ 300: '#86efac',
85
+ 400: '#4ade80',
86
+ 500: '#22c55e',
87
+ 600: '#16a34a',
88
+ 700: '#15803d',
89
+ 800: '#166534',
90
+ 900: '#14532d',
91
+ 950: '#052e16',
92
+ },
93
+ blue: {
94
+ 50: '#eff6ff',
95
+ 100: '#dbeafe',
96
+ 200: '#bfdbfe',
97
+ 300: '#93c5fd',
98
+ 400: '#60a5fa',
99
+ 500: '#3b82f6',
100
+ 600: '#2563eb',
101
+ 700: '#1d4ed8',
102
+ 800: '#1e40af',
103
+ 900: '#1e3a8a',
104
+ 950: '#172554',
105
+ },
106
+ indigo: {
107
+ 50: '#eef2ff',
108
+ 100: '#e0e7ff',
109
+ 200: '#c7d2fe',
110
+ 300: '#a5b4fc',
111
+ 400: '#818cf8',
112
+ 500: '#6366f1',
113
+ 600: '#4f46e5',
114
+ 700: '#4338ca',
115
+ 800: '#3730a3',
116
+ 900: '#312e81',
117
+ 950: '#1e1b4b',
118
+ },
119
+ purple: {
120
+ 50: '#faf5ff',
121
+ 100: '#f3e8ff',
122
+ 200: '#e9d5ff',
123
+ 300: '#d8b4fe',
124
+ 400: '#c084fc',
125
+ 500: '#a855f7',
126
+ 600: '#9333ea',
127
+ 700: '#7e22ce',
128
+ 800: '#6b21a8',
129
+ 900: '#581c87',
130
+ 950: '#3b0764',
131
+ },
132
+ pink: {
133
+ 50: '#fdf2f8',
134
+ 100: '#fce7f3',
135
+ 200: '#fbcfe8',
136
+ 300: '#f9a8d4',
137
+ 400: '#f472b6',
138
+ 500: '#ec4899',
139
+ 600: '#db2777',
140
+ 700: '#be185d',
141
+ 800: '#9d174d',
142
+ 900: '#831843',
143
+ 950: '#500724',
144
+ },
145
+ // Semantic
146
+ white: { DEFAULT: '#ffffff' },
147
+ black: { DEFAULT: '#000000' },
148
+ transparent: { DEFAULT: 'transparent' },
149
+ current: { DEFAULT: 'currentColor' },
150
+ };
@@ -0,0 +1,37 @@
1
+ import type { DesignTokens } from '../types';
2
+ import { colors } from './colors';
3
+ import { spacing } from './spacing';
4
+ import {
5
+ fontSize,
6
+ fontWeight,
7
+ fontFamily,
8
+ lineHeight,
9
+ letterSpacing,
10
+ } from './typography';
11
+ import { borderRadius, borderWidth } from './borders';
12
+ import { boxShadow } from './shadows';
13
+
14
+ export const defaultTokens: DesignTokens = {
15
+ colors,
16
+ spacing,
17
+ fontSize,
18
+ fontWeight,
19
+ fontFamily,
20
+ borderRadius,
21
+ borderWidth,
22
+ boxShadow,
23
+ lineHeight,
24
+ letterSpacing,
25
+ };
26
+
27
+ export { colors } from './colors';
28
+ export { spacing } from './spacing';
29
+ export {
30
+ fontSize,
31
+ fontWeight,
32
+ fontFamily,
33
+ lineHeight,
34
+ letterSpacing,
35
+ } from './typography';
36
+ export { borderRadius, borderWidth } from './borders';
37
+ export { boxShadow } from './shadows';
@@ -0,0 +1,10 @@
1
+ export const boxShadow: Record<string, string> = {
2
+ sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
3
+ DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
4
+ md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
5
+ lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
6
+ xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
7
+ '2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
8
+ inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
9
+ none: 'none',
10
+ };
@@ -0,0 +1,37 @@
1
+ export const spacing: Record<string, string> = {
2
+ px: '1px',
3
+ '0': '0px',
4
+ '0.5': '0.125rem',
5
+ '1': '0.25rem',
6
+ '1.5': '0.375rem',
7
+ '2': '0.5rem',
8
+ '2.5': '0.625rem',
9
+ '3': '0.75rem',
10
+ '3.5': '0.875rem',
11
+ '4': '1rem',
12
+ '5': '1.25rem',
13
+ '6': '1.5rem',
14
+ '7': '1.75rem',
15
+ '8': '2rem',
16
+ '9': '2.25rem',
17
+ '10': '2.5rem',
18
+ '11': '2.75rem',
19
+ '12': '3rem',
20
+ '14': '3.5rem',
21
+ '16': '4rem',
22
+ '20': '5rem',
23
+ '24': '6rem',
24
+ '28': '7rem',
25
+ '32': '8rem',
26
+ '36': '9rem',
27
+ '40': '10rem',
28
+ '44': '11rem',
29
+ '48': '12rem',
30
+ '52': '13rem',
31
+ '56': '14rem',
32
+ '60': '15rem',
33
+ '64': '16rem',
34
+ '72': '18rem',
35
+ '80': '20rem',
36
+ '96': '24rem',
37
+ };
@@ -0,0 +1,51 @@
1
+ export const fontSize: Record<string, string> = {
2
+ xs: '0.75rem',
3
+ sm: '0.875rem',
4
+ base: '1rem',
5
+ lg: '1.125rem',
6
+ xl: '1.25rem',
7
+ '2xl': '1.5rem',
8
+ '3xl': '1.875rem',
9
+ '4xl': '2.25rem',
10
+ '5xl': '3rem',
11
+ '6xl': '3.75rem',
12
+ '7xl': '4.5rem',
13
+ '8xl': '6rem',
14
+ '9xl': '8rem',
15
+ };
16
+
17
+ export const fontWeight: Record<string, string> = {
18
+ thin: '100',
19
+ extralight: '200',
20
+ light: '300',
21
+ normal: '400',
22
+ medium: '500',
23
+ semibold: '600',
24
+ bold: '700',
25
+ extrabold: '800',
26
+ black: '900',
27
+ };
28
+
29
+ export const fontFamily: Record<string, string> = {
30
+ sans: 'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
31
+ serif: 'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',
32
+ mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace',
33
+ };
34
+
35
+ export const lineHeight: Record<string, string> = {
36
+ none: '1',
37
+ tight: '1.25',
38
+ snug: '1.375',
39
+ normal: '1.5',
40
+ relaxed: '1.625',
41
+ loose: '2',
42
+ };
43
+
44
+ export const letterSpacing: Record<string, string> = {
45
+ tighter: '-0.05em',
46
+ tight: '-0.025em',
47
+ normal: '0em',
48
+ wide: '0.025em',
49
+ wider: '0.05em',
50
+ widest: '0.1em',
51
+ };
@@ -0,0 +1,157 @@
1
+ // === Element Selection ===
2
+ export interface SelectedElement {
3
+ element: HTMLElement;
4
+ rect: DOMRect;
5
+ path: string; // CSS selector path
6
+ xpath: string; // XPath selector
7
+ tagName: string;
8
+ id?: string;
9
+ classList: string[];
10
+ }
11
+
12
+ // === Change Tracking ===
13
+ export type ChangeType =
14
+ | 'style' // CSS property change
15
+ | 'text' // Text content change
16
+ | 'delete' // Element removed
17
+ | 'move' // Element repositioned
18
+ | 'duplicate' // Element duplicated
19
+ | 'insert' // New element inserted
20
+ | 'attribute'; // Attribute modified
21
+
22
+ export interface Change {
23
+ id: string;
24
+ type: ChangeType;
25
+ timestamp: number;
26
+ target: {
27
+ path: string; // CSS selector path to element
28
+ xpath: string; // XPath selector to element
29
+ tagName: string;
30
+ };
31
+ before: unknown;
32
+ after: unknown;
33
+ metadata?: Record<string, unknown>;
34
+ }
35
+
36
+ export interface StyleChange extends Change {
37
+ type: 'style';
38
+ before: { property: string; value: string };
39
+ after: { property: string; value: string };
40
+ }
41
+
42
+ export interface TextChange extends Change {
43
+ type: 'text';
44
+ before: string;
45
+ after: string;
46
+ }
47
+
48
+ export interface MoveChange extends Change {
49
+ type: 'move';
50
+ before: { parent: string; index: number };
51
+ after: { parent: string; index: number };
52
+ }
53
+
54
+ // === Annotations ===
55
+ export interface Annotation {
56
+ id: string;
57
+ elementPath: string; // CSS selector
58
+ elementXpath: string; // XPath selector
59
+ content: string;
60
+ createdAt: number;
61
+ }
62
+
63
+ // === Design Tokens ===
64
+ export interface DesignTokens {
65
+ colors: Record<string, Record<string, string>>;
66
+ spacing: Record<string, string>;
67
+ fontSize: Record<string, string>;
68
+ fontWeight: Record<string, string>;
69
+ fontFamily: Record<string, string>;
70
+ borderRadius: Record<string, string>;
71
+ borderWidth: Record<string, string>;
72
+ boxShadow: Record<string, string>;
73
+ lineHeight: Record<string, string>;
74
+ letterSpacing: Record<string, string>;
75
+ }
76
+
77
+ // === Bobbin State ===
78
+ export interface BobbinState {
79
+ isActive: boolean;
80
+ isPillExpanded: boolean;
81
+ hoveredElement: SelectedElement | null;
82
+ selectedElement: SelectedElement | null;
83
+ changes: Change[];
84
+ annotations: Annotation[];
85
+ clipboard: SelectedElement | null;
86
+ showMarginPadding: boolean;
87
+ activePanel: 'style' | 'inspector' | null;
88
+ theme: 'light' | 'dark' | 'system';
89
+ }
90
+
91
+ export interface BobbinActions {
92
+ activate: () => void;
93
+ deactivate: () => void;
94
+ selectElement: (el: HTMLElement | null) => void;
95
+ clearSelection: () => void;
96
+ applyStyle: (property: string, value: string) => void;
97
+ deleteElement: () => void;
98
+ moveElement: (targetParent: HTMLElement, index: number) => void;
99
+ duplicateElement: () => void;
100
+ insertElement: (
101
+ direction: 'before' | 'after' | 'child',
102
+ content?: string,
103
+ ) => void;
104
+ copyElement: () => void;
105
+ pasteElement: (direction: 'before' | 'after' | 'child') => void;
106
+ annotate: (content: string) => void;
107
+ toggleMarginPadding: () => void;
108
+ toggleTheme: () => void;
109
+ undo: () => void;
110
+ exportChanges: () => string; // Returns YAML
111
+ getChanges: () => Change[];
112
+ resetChanges: () => void; // Reset all style changes
113
+ }
114
+
115
+ // === YAML Export Format ===
116
+ export interface BobbinChangeset {
117
+ version: '1.0';
118
+ timestamp: string;
119
+ changeCount: number;
120
+ changes: Array<{
121
+ type: ChangeType;
122
+ target: string; // CSS selector
123
+ xpath: string; // XPath selector
124
+ property?: string;
125
+ before?: string;
126
+ after?: string;
127
+ note?: string;
128
+ }>;
129
+ annotations: Array<{
130
+ type: 'annotation';
131
+ target: string;
132
+ xpath: string;
133
+ note: string;
134
+ }>;
135
+ }
136
+
137
+ // === Component Props ===
138
+ export interface BobbinProps {
139
+ /** Custom design tokens to merge with defaults */
140
+ tokens?: Partial<DesignTokens>;
141
+ /** Container to scope element selection (default: document.body) */
142
+ container?: HTMLElement | null;
143
+ /** Container for pill positioning (if different from container) */
144
+ pillContainer?: HTMLElement | null;
145
+ /** Initial active state */
146
+ defaultActive?: boolean;
147
+ /** Callback when changes occur */
148
+ onChanges?: (changes: Change[]) => void;
149
+ /** Callback when selection changes */
150
+ onSelect?: (element: SelectedElement | null) => void;
151
+ /** Custom pill position offset from bottom-right of container */
152
+ position?: { bottom: number; right: number };
153
+ /** Z-index for overlay elements */
154
+ zIndex?: number;
155
+ /** Elements to exclude from selection (CSS selectors) */
156
+ exclude?: string[];
157
+ }
@@ -0,0 +1,40 @@
1
+ export interface FLIPState {
2
+ rect: DOMRect;
3
+ opacity: number;
4
+ }
5
+
6
+ export function measureElement(el: HTMLElement): FLIPState {
7
+ return {
8
+ rect: el.getBoundingClientRect(),
9
+ opacity: parseFloat(getComputedStyle(el).opacity),
10
+ };
11
+ }
12
+
13
+ export function animateFLIP(
14
+ el: HTMLElement,
15
+ from: FLIPState,
16
+ to: FLIPState,
17
+ duration = 150,
18
+ ): void {
19
+ const deltaX = from.rect.left - to.rect.left;
20
+ const deltaY = from.rect.top - to.rect.top;
21
+ const deltaW = from.rect.width / to.rect.width;
22
+ const deltaH = from.rect.height / to.rect.height;
23
+
24
+ el.animate(
25
+ [
26
+ {
27
+ transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,
28
+ opacity: from.opacity,
29
+ },
30
+ {
31
+ transform: 'translate(0, 0) scale(1, 1)',
32
+ opacity: to.opacity,
33
+ },
34
+ ],
35
+ {
36
+ duration,
37
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
38
+ },
39
+ );
40
+ }