@pictor-sdk/ui 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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/index.d.mts +833 -0
  4. package/dist/index.d.ts +833 -0
  5. package/dist/index.js +4620 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +4643 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/package.json +68 -0
  10. package/src/Editor.tsx +276 -0
  11. package/src/ToolPanelHost.tsx +98 -0
  12. package/src/components/Slider.tsx +172 -0
  13. package/src/components/StraightenRuler.tsx +57 -0
  14. package/src/components/ToolRail.tsx +58 -0
  15. package/src/components/TopBar.tsx +53 -0
  16. package/src/composer/TextComposer.tsx +540 -0
  17. package/src/composer/keyboardLayout.ts +130 -0
  18. package/src/composer/useTextSession.ts +230 -0
  19. package/src/gestures/CropGestureSurface.tsx +270 -0
  20. package/src/gestures/CropGrid.tsx +24 -0
  21. package/src/gestures/DrawingSurface.tsx +77 -0
  22. package/src/gestures/EditorGestures.tsx +97 -0
  23. package/src/gestures/InteractionGuides.tsx +161 -0
  24. package/src/gestures/LayerGestureSurface.tsx +462 -0
  25. package/src/gestures/StoryMediaGestureSurface.tsx +517 -0
  26. package/src/gestures/TiltShiftGestureSurface.tsx +189 -0
  27. package/src/gestures/controller.ts +152 -0
  28. package/src/gestures/drawController.ts +104 -0
  29. package/src/gestures/interactionState.tsx +81 -0
  30. package/src/gestures/layerGestureWorklet.ts +198 -0
  31. package/src/gestures/mediaGestureWorklet.ts +159 -0
  32. package/src/gestures/routing.ts +42 -0
  33. package/src/gestures/settleCoordinator.ts +61 -0
  34. package/src/gestures/transformOwnership.ts +91 -0
  35. package/src/hostCallbacks.tsx +62 -0
  36. package/src/index.ts +72 -0
  37. package/src/panels/AddPhotoPanel.tsx +101 -0
  38. package/src/panels/AdjustPanel.tsx +158 -0
  39. package/src/panels/ColorPanel.tsx +193 -0
  40. package/src/panels/CropPanel.tsx +185 -0
  41. package/src/panels/DrawPanel.tsx +106 -0
  42. package/src/panels/FilterStrip.tsx +153 -0
  43. package/src/panels/LayersPanel.tsx +85 -0
  44. package/src/panels/LayoutPanel.tsx +55 -0
  45. package/src/panels/LuxPanel.tsx +122 -0
  46. package/src/panels/MediaPanel.tsx +73 -0
  47. package/src/panels/PerspectivePanel.tsx +157 -0
  48. package/src/panels/StickerPanel.tsx +78 -0
  49. package/src/panels/TextPanel.tsx +177 -0
  50. package/src/panels/TiltShiftPanel.tsx +146 -0
  51. package/src/panels/addPhotoController.ts +196 -0
  52. package/src/panels/cropMath.ts +37 -0
  53. package/src/panels/layoutMath.ts +58 -0
  54. package/src/panels/useTargetImageLayer.ts +41 -0
  55. package/src/theme.ts +61 -0
  56. package/src/uiState.tsx +57 -0
package/src/theme.ts ADDED
@@ -0,0 +1,61 @@
1
+ import { createContext, useContext } from 'react'
2
+
3
+ /**
4
+ * Theming is one token object on context — no style props on individual
5
+ * components (ARCHITECTURE.md). Override any subset via <Editor theme={…}>.
6
+ */
7
+ export interface EditorTheme {
8
+ colors: {
9
+ background: string
10
+ surface: string
11
+ text: string
12
+ textMuted: string
13
+ accent: string
14
+ danger: string
15
+ track: string
16
+ thumb: string
17
+ }
18
+ radii: { sm: number; md: number; lg: number }
19
+ spacing: { xs: number; sm: number; md: number; lg: number }
20
+ font: { size: number; sizeSm: number; weight: '400' | '500' | '600' | '700' }
21
+ }
22
+
23
+ /** The bundled dark theme. Every value is overridable; see {@link mergeTheme}. */
24
+ export const defaultTheme: EditorTheme = {
25
+ colors: {
26
+ background: '#000000',
27
+ surface: '#121212',
28
+ text: '#ffffff',
29
+ textMuted: '#9a9a9a',
30
+ accent: '#3897f0',
31
+ danger: '#ed4956',
32
+ track: '#3a3a3a',
33
+ thumb: '#ffffff',
34
+ },
35
+ radii: { sm: 6, md: 10, lg: 16 },
36
+ spacing: { xs: 4, sm: 8, md: 14, lg: 22 },
37
+ font: { size: 15, sizeSm: 12, weight: '600' },
38
+ }
39
+
40
+ /** A theme override — any subset of any group, the rest falling back to the default. */
41
+ export type PartialTheme = {
42
+ [K in keyof EditorTheme]?: Partial<EditorTheme[K]>
43
+ }
44
+
45
+ /** Apply an override onto the default theme, one group at a time. */
46
+ export function mergeTheme(overrides?: PartialTheme): EditorTheme {
47
+ if (!overrides) return defaultTheme
48
+ return {
49
+ colors: { ...defaultTheme.colors, ...overrides.colors },
50
+ radii: { ...defaultTheme.radii, ...overrides.radii },
51
+ spacing: { ...defaultTheme.spacing, ...overrides.spacing },
52
+ font: { ...defaultTheme.font, ...overrides.font },
53
+ }
54
+ }
55
+
56
+ /** Carries the resolved theme. `<Editor>` provides it; components read it with {@link useTheme}. */
57
+ export const ThemeContext = createContext<EditorTheme>(defaultTheme)
58
+ /** The theme in effect. Defaults outside an `<Editor>` rather than throwing. */
59
+ export function useTheme(): EditorTheme {
60
+ return useContext(ThemeContext)
61
+ }
@@ -0,0 +1,57 @@
1
+ import React, { createContext, useCallback, useContext, useRef, useSyncExternalStore } from 'react'
2
+
3
+ /**
4
+ * A tiny shared key/value store for panel ↔ canvas coordination (brush
5
+ * config, sticker catalogs, eyedropper mode). Ephemeral — never touches the
6
+ * document or history.
7
+ */
8
+ export interface UiStateStore {
9
+ get<T>(key: string, fallback: T): T
10
+ set(key: string, value: unknown): void
11
+ subscribe(listener: () => void): () => void
12
+ }
13
+
14
+ /** A scratch store for UI state that is neither document nor history. */
15
+ export function createUiStateStore(): UiStateStore {
16
+ const values = new Map<string, unknown>()
17
+ const listeners = new Set<() => void>()
18
+ return {
19
+ get: <T,>(key: string, fallback: T) =>
20
+ (values.has(key) ? (values.get(key) as T) : fallback),
21
+ set(key, value) {
22
+ values.set(key, value)
23
+ for (const l of [...listeners]) l()
24
+ },
25
+ subscribe(listener) {
26
+ listeners.add(listener)
27
+ return () => listeners.delete(listener)
28
+ },
29
+ }
30
+ }
31
+
32
+ const UiStateContext = createContext<UiStateStore | null>(null)
33
+
34
+ /**
35
+ * Holds ephemeral panel state — which tab is open, which swatch is selected.
36
+ *
37
+ * Deliberately outside the document: none of it should be serialized, undoable,
38
+ * or survive the editor closing.
39
+ */
40
+ export function UiStateProvider({ children }: { children?: React.ReactNode }) {
41
+ const ref = useRef<UiStateStore | null>(null)
42
+ if (!ref.current) ref.current = createUiStateStore()
43
+ return <UiStateContext.Provider value={ref.current}>{children}</UiStateContext.Provider>
44
+ }
45
+
46
+ /** Read and write one key of the ephemeral UI state. Throws outside an `<Editor>`. */
47
+ export function useUiState<T>(key: string, fallback: T): [T, (value: T) => void] {
48
+ const store = useContext(UiStateContext)
49
+ if (!store) throw new Error('useUiState must be used inside <Editor> (UiStateProvider)')
50
+ const value = useSyncExternalStore(
51
+ store.subscribe,
52
+ () => store.get(key, fallback),
53
+ () => store.get(key, fallback),
54
+ )
55
+ const set = useCallback((v: T) => store.set(key, v), [store, key])
56
+ return [value, set]
57
+ }