@pictor-sdk/ui 0.1.0 → 0.2.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.
- package/README.md +12 -1
- package/dist/index.d.mts +34 -2
- package/dist/index.d.ts +34 -2
- package/dist/index.js +82 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +80 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/gestures/LayerGestureSurface.tsx +7 -4
- package/src/index.ts +1 -0
- package/src/panels/LayoutPanel.tsx +11 -5
- package/src/panels/layoutMath.ts +86 -32
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ photo and video editor SDK for React Native. Public APIs are pre-1.0 and experim
|
|
|
8
8
|
## Install
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
|
-
pnpm add @pictor-sdk/ui@0.1
|
|
11
|
+
pnpm add @pictor-sdk/ui@0.2.1
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
Install the package's declared peer dependencies in your app. Keep React, React Native,
|
|
@@ -21,6 +21,17 @@ of device verification on every supported version/platform.
|
|
|
21
21
|
|
|
22
22
|
## Documentation and contributing
|
|
23
23
|
|
|
24
|
+
### Story Layout in 0.2.0
|
|
25
|
+
|
|
26
|
+
Upgrade `@pictor-sdk/core`, `@pictor-sdk/skia` and `@pictor-sdk/ui` together.
|
|
27
|
+
`layoutCellBounds('6grid')` supplies a two-column, three-row grid;
|
|
28
|
+
`fitImageToLayoutCell(cell, document.size, intrinsic, { zoom, center })` returns
|
|
29
|
+
the fixed-cell transform, source crop and `pixelSnap` flag. Apply all three in
|
|
30
|
+
one history batch. Zoom and pan change the crop, not the layer's cell bounds.
|
|
31
|
+
See the [host integration guide](https://github.com/zahidhasanaunto/pictor/blob/main/docs/STORY-LAYOUT.md).
|
|
32
|
+
|
|
33
|
+
### Project links
|
|
34
|
+
|
|
24
35
|
- [Repository and example app](https://github.com/zahidhasanaunto/pictor)
|
|
25
36
|
- [Public API inventory](https://github.com/zahidhasanaunto/pictor/blob/main/docs/API-SURFACE.md)
|
|
26
37
|
- [Release and contributor guide](https://github.com/zahidhasanaunto/pictor/blob/main/docs/RELEASING.md)
|
package/dist/index.d.mts
CHANGED
|
@@ -758,7 +758,7 @@ declare function LayersPanel(): React__default.JSX.Element;
|
|
|
758
758
|
declare function LayoutPanel(): React__default.JSX.Element;
|
|
759
759
|
|
|
760
760
|
/** The bundled multi-photo arrangements, by cell count and split direction. */
|
|
761
|
-
type LayoutPreset = '1' | '2v' | '2h' | '3v' | '4grid';
|
|
761
|
+
type LayoutPreset = '1' | '2v' | '2h' | '3v' | '4grid' | '6grid';
|
|
762
762
|
/** One slot in a layout: where its photo sits, in normalized document units. */
|
|
763
763
|
interface LayoutCell {
|
|
764
764
|
/** centre + scale in normalized document units */
|
|
@@ -773,6 +773,38 @@ interface LayoutCell {
|
|
|
773
773
|
* canvas size works.
|
|
774
774
|
*/
|
|
775
775
|
declare function layoutCells(preset: LayoutPreset, _doc: Size): LayoutCell[];
|
|
776
|
+
/**
|
|
777
|
+
* Axis-aligned cell rectangles, row-major, normalized to document width/height.
|
|
778
|
+
* x/y are TOP-LEFT coordinates, unlike the centres in legacy LayoutCell.
|
|
779
|
+
* Returns fresh rectangles; no document aspect ratio is assumed.
|
|
780
|
+
*/
|
|
781
|
+
declare function layoutCellBounds(preset: LayoutPreset): Rect[];
|
|
782
|
+
/** Source-window controls; pan is a source-space crop centre, not a layer translation. */
|
|
783
|
+
interface LayoutCropOptions {
|
|
784
|
+
/** Magnification relative to crop-to-fill. Clamped to [1, 32]; default 1. */
|
|
785
|
+
zoom?: number;
|
|
786
|
+
/** Desired source-normalized crop centre; clamped so the crop stays in the source. */
|
|
787
|
+
center?: {
|
|
788
|
+
x: number;
|
|
789
|
+
y: number;
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
/** Crop and complete transform to apply together in one history batch. */
|
|
793
|
+
interface LayoutImageFit {
|
|
794
|
+
crop: Rect;
|
|
795
|
+
transform: Transform;
|
|
796
|
+
/** Apply to ImageLayerData together with crop for seam-free cell edges. */
|
|
797
|
+
pixelSnap: true;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Fill a fixed cell without bleed. Zoom/pan alter only the source crop, never
|
|
801
|
+
* the cell bounds. intrinsic must describe the decoded, orientation-corrected
|
|
802
|
+
* source. Recompute after source replacement or document resize.
|
|
803
|
+
* Throws RangeError for non-finite controls, invalid sizes or out-of-document cells.
|
|
804
|
+
* Apply transform with layer/transform and crop + pixelSnap with layer/patchData in one batch.
|
|
805
|
+
* General layer gestures must not subsequently move/rotate/scale a fixed cell.
|
|
806
|
+
*/
|
|
807
|
+
declare function fitImageToLayoutCell(cell: Rect, documentSize: Size, intrinsic: Size, options?: LayoutCropOptions): LayoutImageFit;
|
|
776
808
|
/** The transform patch that moves a layer into a cell, leaving its other fields alone. */
|
|
777
809
|
declare function cellToTransformPatch(cell: LayoutCell): Partial<Transform>;
|
|
778
810
|
|
|
@@ -830,4 +862,4 @@ declare function UiStateProvider({ children }: {
|
|
|
830
862
|
/** Read and write one key of the ephemeral UI state. Throws outside an `<Editor>`. */
|
|
831
863
|
declare function useUiState<T>(key: string, fallback: T): [T, (value: T) => void];
|
|
832
864
|
|
|
833
|
-
export { type AddPhotoController, type AddPhotoControllerOptions, AddPhotoPanel, AdjustPanel, type BrushConfig, CanvasStage, type CanvasStageProps, CropGestureSurface, type CropGestureSurfaceProps, CropGrid, CropPanel, DEFAULT_BRUSH, type DrawController, DrawPanel, DrawingSurface, Editor, EditorGestures, type EditorGesturesProps, type EditorProps, type EditorSlots, type EditorTheme, FilterStrip, type GestureController, type GestureControllerOptions, type GestureMetrics, type GestureSnapEvent, type GestureSurfaceKind, type HostCallbacks, HostCallbacksProvider, InteractionGuides, type InteractionGuidesProps, InteractionProvider, InvalidImageResultError, LayerGestureSurface, type LayerGestureSurfaceProps, LayersPanel, type LayoutCell, LayoutPanel, type LayoutPreset, MediaPanel, type PartialTheme, STRAIGHTEN_LIMIT, Slider, type SliderProps, type StickerAsset, StickerPanel, StoryMediaGestureSurface, type StoryMediaGestureSurfaceProps, StraightenRuler, type StraightenRulerProps, TextComposer, TextComposerHost, type TextComposerProps, TextPanel, type TextSessionController, ThemeContext, ToolPanelHost, ToolRail, TopBar, type TopBarProps, UiStateProvider, type UiStateStore, type UseTextSessionOptions, canvasSizeForAspect, cellToTransformPatch, centeredCropForAspect, createAddPhotoController, createDrawController, createGestureController, createUiStateStore, defaultTheme, layoutCells, mergeSlots, mergeTheme, radiansToStraighten, resolveGestureSurface, resolvePanel, straightenToRadians, useBaseImageLayer, useBaseMediaLayer, useHostCallbacks, useInteractionState, useTargetImageLayer, useTextSession, useTheme, useUiState };
|
|
865
|
+
export { type AddPhotoController, type AddPhotoControllerOptions, AddPhotoPanel, AdjustPanel, type BrushConfig, CanvasStage, type CanvasStageProps, CropGestureSurface, type CropGestureSurfaceProps, CropGrid, CropPanel, DEFAULT_BRUSH, type DrawController, DrawPanel, DrawingSurface, Editor, EditorGestures, type EditorGesturesProps, type EditorProps, type EditorSlots, type EditorTheme, FilterStrip, type GestureController, type GestureControllerOptions, type GestureMetrics, type GestureSnapEvent, type GestureSurfaceKind, type HostCallbacks, HostCallbacksProvider, InteractionGuides, type InteractionGuidesProps, InteractionProvider, InvalidImageResultError, LayerGestureSurface, type LayerGestureSurfaceProps, LayersPanel, type LayoutCell, type LayoutCropOptions, type LayoutImageFit, LayoutPanel, type LayoutPreset, MediaPanel, type PartialTheme, STRAIGHTEN_LIMIT, Slider, type SliderProps, type StickerAsset, StickerPanel, StoryMediaGestureSurface, type StoryMediaGestureSurfaceProps, StraightenRuler, type StraightenRulerProps, TextComposer, TextComposerHost, type TextComposerProps, TextPanel, type TextSessionController, ThemeContext, ToolPanelHost, ToolRail, TopBar, type TopBarProps, UiStateProvider, type UiStateStore, type UseTextSessionOptions, canvasSizeForAspect, cellToTransformPatch, centeredCropForAspect, createAddPhotoController, createDrawController, createGestureController, createUiStateStore, defaultTheme, fitImageToLayoutCell, layoutCellBounds, layoutCells, mergeSlots, mergeTheme, radiansToStraighten, resolveGestureSurface, resolvePanel, straightenToRadians, useBaseImageLayer, useBaseMediaLayer, useHostCallbacks, useInteractionState, useTargetImageLayer, useTextSession, useTheme, useUiState };
|
package/dist/index.d.ts
CHANGED
|
@@ -758,7 +758,7 @@ declare function LayersPanel(): React__default.JSX.Element;
|
|
|
758
758
|
declare function LayoutPanel(): React__default.JSX.Element;
|
|
759
759
|
|
|
760
760
|
/** The bundled multi-photo arrangements, by cell count and split direction. */
|
|
761
|
-
type LayoutPreset = '1' | '2v' | '2h' | '3v' | '4grid';
|
|
761
|
+
type LayoutPreset = '1' | '2v' | '2h' | '3v' | '4grid' | '6grid';
|
|
762
762
|
/** One slot in a layout: where its photo sits, in normalized document units. */
|
|
763
763
|
interface LayoutCell {
|
|
764
764
|
/** centre + scale in normalized document units */
|
|
@@ -773,6 +773,38 @@ interface LayoutCell {
|
|
|
773
773
|
* canvas size works.
|
|
774
774
|
*/
|
|
775
775
|
declare function layoutCells(preset: LayoutPreset, _doc: Size): LayoutCell[];
|
|
776
|
+
/**
|
|
777
|
+
* Axis-aligned cell rectangles, row-major, normalized to document width/height.
|
|
778
|
+
* x/y are TOP-LEFT coordinates, unlike the centres in legacy LayoutCell.
|
|
779
|
+
* Returns fresh rectangles; no document aspect ratio is assumed.
|
|
780
|
+
*/
|
|
781
|
+
declare function layoutCellBounds(preset: LayoutPreset): Rect[];
|
|
782
|
+
/** Source-window controls; pan is a source-space crop centre, not a layer translation. */
|
|
783
|
+
interface LayoutCropOptions {
|
|
784
|
+
/** Magnification relative to crop-to-fill. Clamped to [1, 32]; default 1. */
|
|
785
|
+
zoom?: number;
|
|
786
|
+
/** Desired source-normalized crop centre; clamped so the crop stays in the source. */
|
|
787
|
+
center?: {
|
|
788
|
+
x: number;
|
|
789
|
+
y: number;
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
/** Crop and complete transform to apply together in one history batch. */
|
|
793
|
+
interface LayoutImageFit {
|
|
794
|
+
crop: Rect;
|
|
795
|
+
transform: Transform;
|
|
796
|
+
/** Apply to ImageLayerData together with crop for seam-free cell edges. */
|
|
797
|
+
pixelSnap: true;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Fill a fixed cell without bleed. Zoom/pan alter only the source crop, never
|
|
801
|
+
* the cell bounds. intrinsic must describe the decoded, orientation-corrected
|
|
802
|
+
* source. Recompute after source replacement or document resize.
|
|
803
|
+
* Throws RangeError for non-finite controls, invalid sizes or out-of-document cells.
|
|
804
|
+
* Apply transform with layer/transform and crop + pixelSnap with layer/patchData in one batch.
|
|
805
|
+
* General layer gestures must not subsequently move/rotate/scale a fixed cell.
|
|
806
|
+
*/
|
|
807
|
+
declare function fitImageToLayoutCell(cell: Rect, documentSize: Size, intrinsic: Size, options?: LayoutCropOptions): LayoutImageFit;
|
|
776
808
|
/** The transform patch that moves a layer into a cell, leaving its other fields alone. */
|
|
777
809
|
declare function cellToTransformPatch(cell: LayoutCell): Partial<Transform>;
|
|
778
810
|
|
|
@@ -830,4 +862,4 @@ declare function UiStateProvider({ children }: {
|
|
|
830
862
|
/** Read and write one key of the ephemeral UI state. Throws outside an `<Editor>`. */
|
|
831
863
|
declare function useUiState<T>(key: string, fallback: T): [T, (value: T) => void];
|
|
832
864
|
|
|
833
|
-
export { type AddPhotoController, type AddPhotoControllerOptions, AddPhotoPanel, AdjustPanel, type BrushConfig, CanvasStage, type CanvasStageProps, CropGestureSurface, type CropGestureSurfaceProps, CropGrid, CropPanel, DEFAULT_BRUSH, type DrawController, DrawPanel, DrawingSurface, Editor, EditorGestures, type EditorGesturesProps, type EditorProps, type EditorSlots, type EditorTheme, FilterStrip, type GestureController, type GestureControllerOptions, type GestureMetrics, type GestureSnapEvent, type GestureSurfaceKind, type HostCallbacks, HostCallbacksProvider, InteractionGuides, type InteractionGuidesProps, InteractionProvider, InvalidImageResultError, LayerGestureSurface, type LayerGestureSurfaceProps, LayersPanel, type LayoutCell, LayoutPanel, type LayoutPreset, MediaPanel, type PartialTheme, STRAIGHTEN_LIMIT, Slider, type SliderProps, type StickerAsset, StickerPanel, StoryMediaGestureSurface, type StoryMediaGestureSurfaceProps, StraightenRuler, type StraightenRulerProps, TextComposer, TextComposerHost, type TextComposerProps, TextPanel, type TextSessionController, ThemeContext, ToolPanelHost, ToolRail, TopBar, type TopBarProps, UiStateProvider, type UiStateStore, type UseTextSessionOptions, canvasSizeForAspect, cellToTransformPatch, centeredCropForAspect, createAddPhotoController, createDrawController, createGestureController, createUiStateStore, defaultTheme, layoutCells, mergeSlots, mergeTheme, radiansToStraighten, resolveGestureSurface, resolvePanel, straightenToRadians, useBaseImageLayer, useBaseMediaLayer, useHostCallbacks, useInteractionState, useTargetImageLayer, useTextSession, useTheme, useUiState };
|
|
865
|
+
export { type AddPhotoController, type AddPhotoControllerOptions, AddPhotoPanel, AdjustPanel, type BrushConfig, CanvasStage, type CanvasStageProps, CropGestureSurface, type CropGestureSurfaceProps, CropGrid, CropPanel, DEFAULT_BRUSH, type DrawController, DrawPanel, DrawingSurface, Editor, EditorGestures, type EditorGesturesProps, type EditorProps, type EditorSlots, type EditorTheme, FilterStrip, type GestureController, type GestureControllerOptions, type GestureMetrics, type GestureSnapEvent, type GestureSurfaceKind, type HostCallbacks, HostCallbacksProvider, InteractionGuides, type InteractionGuidesProps, InteractionProvider, InvalidImageResultError, LayerGestureSurface, type LayerGestureSurfaceProps, LayersPanel, type LayoutCell, type LayoutCropOptions, type LayoutImageFit, LayoutPanel, type LayoutPreset, MediaPanel, type PartialTheme, STRAIGHTEN_LIMIT, Slider, type SliderProps, type StickerAsset, StickerPanel, StoryMediaGestureSurface, type StoryMediaGestureSurfaceProps, StraightenRuler, type StraightenRulerProps, TextComposer, TextComposerHost, type TextComposerProps, TextPanel, type TextSessionController, ThemeContext, ToolPanelHost, ToolRail, TopBar, type TopBarProps, UiStateProvider, type UiStateStore, type UseTextSessionOptions, canvasSizeForAspect, cellToTransformPatch, centeredCropForAspect, createAddPhotoController, createDrawController, createGestureController, createUiStateStore, defaultTheme, fitImageToLayoutCell, layoutCellBounds, layoutCells, mergeSlots, mergeTheme, radiansToStraighten, resolveGestureSurface, resolvePanel, straightenToRadians, useBaseImageLayer, useBaseMediaLayer, useHostCallbacks, useInteractionState, useTargetImageLayer, useTextSession, useTheme, useUiState };
|
package/dist/index.js
CHANGED
|
@@ -73,6 +73,8 @@ __export(index_exports, {
|
|
|
73
73
|
createGestureController: () => createGestureController,
|
|
74
74
|
createUiStateStore: () => createUiStateStore,
|
|
75
75
|
defaultTheme: () => defaultTheme,
|
|
76
|
+
fitImageToLayoutCell: () => fitImageToLayoutCell,
|
|
77
|
+
layoutCellBounds: () => layoutCellBounds,
|
|
76
78
|
layoutCells: () => layoutCells,
|
|
77
79
|
mergeSlots: () => mergeSlots,
|
|
78
80
|
mergeTheme: () => mergeTheme,
|
|
@@ -808,10 +810,12 @@ function LayerGestureSurface({ onSnap }) {
|
|
|
808
810
|
);
|
|
809
811
|
const aspect = document.size.height / document.size.width;
|
|
810
812
|
const [measureVersion, setMeasureVersion] = (0, import_react9.useState)(0);
|
|
811
|
-
(0, import_react9.useEffect)(
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
813
|
+
(0, import_react9.useEffect)(() => {
|
|
814
|
+
const refresh = () => setMeasureVersion((v) => v + 1);
|
|
815
|
+
const unsubscribe = renderer.textMeasures.subscribe(refresh);
|
|
816
|
+
refresh();
|
|
817
|
+
return unsubscribe;
|
|
818
|
+
}, [renderer]);
|
|
815
819
|
const hitCandidates = (0, import_react9.useMemo)(
|
|
816
820
|
() => document.layers.map((layer, index) => ({ layer, index })).filter(
|
|
817
821
|
({ layer, index }) => !layer.hidden && !layer.locked && (0, import_core8.isDirectManipulationLayer)(layer, index, profile.interaction?.layers)
|
|
@@ -2829,38 +2833,70 @@ var import_react_native16 = require("react-native");
|
|
|
2829
2833
|
|
|
2830
2834
|
// src/panels/layoutMath.ts
|
|
2831
2835
|
function layoutCells(preset, _doc) {
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
return [{ x: 0.5, y: 0.5, scale: 1 }];
|
|
2836
|
+
return layoutCellBounds(preset).map((cell) => ({
|
|
2837
|
+
x: (cell.x / cell.width + 0.5) * cell.width,
|
|
2838
|
+
y: (cell.y / cell.height + 0.5) * cell.height,
|
|
2839
|
+
scale: cell.width
|
|
2840
|
+
}));
|
|
2841
|
+
}
|
|
2842
|
+
function layoutCellBounds(preset) {
|
|
2843
|
+
const dimensions = {
|
|
2844
|
+
"1": [1, 1],
|
|
2845
|
+
"2v": [1, 2],
|
|
2846
|
+
"2h": [2, 1],
|
|
2847
|
+
"3v": [1, 3],
|
|
2848
|
+
"4grid": [2, 2],
|
|
2849
|
+
"6grid": [2, 3]
|
|
2850
|
+
};
|
|
2851
|
+
const grid = dimensions[preset];
|
|
2852
|
+
if (!grid) throw new RangeError("Unknown layout preset");
|
|
2853
|
+
const [columns, rows] = grid;
|
|
2854
|
+
return Array.from({ length: columns * rows }, (_, index) => ({
|
|
2855
|
+
x: index % columns / columns,
|
|
2856
|
+
y: Math.floor(index / columns) / rows,
|
|
2857
|
+
width: 1 / columns,
|
|
2858
|
+
height: 1 / rows
|
|
2859
|
+
}));
|
|
2860
|
+
}
|
|
2861
|
+
function fitImageToLayoutCell(cell, documentSize, intrinsic, options = {}) {
|
|
2862
|
+
for (const size of [documentSize, intrinsic]) {
|
|
2863
|
+
if (![size.width, size.height].every((v) => Number.isFinite(v) && v > 0)) {
|
|
2864
|
+
throw new RangeError("Layout sizes must be finite and positive");
|
|
2862
2865
|
}
|
|
2863
2866
|
}
|
|
2867
|
+
if (![cell.x, cell.y, cell.width, cell.height].every(Number.isFinite) || cell.x < 0 || cell.y < 0 || cell.width <= 0 || cell.height <= 0 || cell.x + cell.width > 1 + 1e-12 || cell.y + cell.height > 1 + 1e-12) {
|
|
2868
|
+
throw new RangeError("Layout cell must lie inside the document");
|
|
2869
|
+
}
|
|
2870
|
+
const zoom = options.zoom ?? 1;
|
|
2871
|
+
const center = options.center ?? { x: 0.5, y: 0.5 };
|
|
2872
|
+
if (![zoom, center.x, center.y].every(Number.isFinite)) {
|
|
2873
|
+
throw new RangeError("Layout controls must be finite");
|
|
2874
|
+
}
|
|
2875
|
+
const base = centeredCropForAspect(
|
|
2876
|
+
intrinsic,
|
|
2877
|
+
cell.width * documentSize.width / (cell.height * documentSize.height)
|
|
2878
|
+
);
|
|
2879
|
+
const factor = Math.max(1, Math.min(32, zoom));
|
|
2880
|
+
const width = base.width / factor;
|
|
2881
|
+
const height = base.height / factor;
|
|
2882
|
+
return {
|
|
2883
|
+
pixelSnap: true,
|
|
2884
|
+
crop: {
|
|
2885
|
+
x: Math.max(0, Math.min(1 - width, center.x - width / 2)),
|
|
2886
|
+
y: Math.max(0, Math.min(1 - height, center.y - height / 2)),
|
|
2887
|
+
width,
|
|
2888
|
+
height
|
|
2889
|
+
},
|
|
2890
|
+
transform: {
|
|
2891
|
+
x: cell.x + cell.width / 2,
|
|
2892
|
+
y: cell.y + cell.height / 2,
|
|
2893
|
+
scale: cell.width,
|
|
2894
|
+
rotation: 0,
|
|
2895
|
+
anchor: { x: 0.5, y: 0.5 },
|
|
2896
|
+
flipX: false,
|
|
2897
|
+
flipY: false
|
|
2898
|
+
}
|
|
2899
|
+
};
|
|
2864
2900
|
}
|
|
2865
2901
|
function cellToTransformPatch(cell) {
|
|
2866
2902
|
return { x: cell.x, y: cell.y, scale: cell.scale, rotation: 0 };
|
|
@@ -2873,17 +2909,23 @@ var PRESETS = [
|
|
|
2873
2909
|
{ id: "2v", label: "2 rows" },
|
|
2874
2910
|
{ id: "2h", label: "2 cols" },
|
|
2875
2911
|
{ id: "3v", label: "3 rows" },
|
|
2876
|
-
{ id: "4grid", label: "Grid" }
|
|
2912
|
+
{ id: "4grid", label: "Grid" },
|
|
2913
|
+
{ id: "6grid", label: "6 grid" }
|
|
2877
2914
|
];
|
|
2878
2915
|
function LayoutPanel() {
|
|
2879
2916
|
const { document, dispatch } = (0, import_core18.useEditor)();
|
|
2880
2917
|
const theme = useTheme();
|
|
2881
2918
|
const apply = (preset) => {
|
|
2882
|
-
const cells =
|
|
2919
|
+
const cells = layoutCellBounds(preset);
|
|
2883
2920
|
const images = document.layers.filter((l) => l.type === "image");
|
|
2921
|
+
const fits = images.slice(0, cells.length).map((layer, i) => ({
|
|
2922
|
+
layer,
|
|
2923
|
+
fit: fitImageToLayoutCell(cells[i], document.size, layer.data.intrinsic)
|
|
2924
|
+
}));
|
|
2884
2925
|
dispatch({ type: "history/beginBatch", label: "layout" });
|
|
2885
|
-
|
|
2886
|
-
dispatch({ type: "layer/transform", id: layer.id, patch:
|
|
2926
|
+
fits.forEach(({ layer, fit }) => {
|
|
2927
|
+
dispatch({ type: "layer/transform", id: layer.id, patch: fit.transform });
|
|
2928
|
+
dispatch({ type: "layer/patchData", id: layer.id, patch: { crop: fit.crop, pixelSnap: fit.pixelSnap } });
|
|
2887
2929
|
});
|
|
2888
2930
|
dispatch({ type: "history/endBatch" });
|
|
2889
2931
|
};
|
|
@@ -4601,6 +4643,8 @@ function TextPanel() {
|
|
|
4601
4643
|
createGestureController,
|
|
4602
4644
|
createUiStateStore,
|
|
4603
4645
|
defaultTheme,
|
|
4646
|
+
fitImageToLayoutCell,
|
|
4647
|
+
layoutCellBounds,
|
|
4604
4648
|
layoutCells,
|
|
4605
4649
|
mergeSlots,
|
|
4606
4650
|
mergeTheme,
|