@pictor-sdk/ui 0.1.0 → 0.2.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.
package/dist/index.mjs CHANGED
@@ -2795,38 +2795,70 @@ import { Pressable as Pressable7, ScrollView as ScrollView6, Text as Text10 } fr
2795
2795
 
2796
2796
  // src/panels/layoutMath.ts
2797
2797
  function layoutCells(preset, _doc) {
2798
- switch (preset) {
2799
- case "1":
2800
- return [{ x: 0.5, y: 0.5, scale: 1 }];
2801
- case "2v":
2802
- return [
2803
- { x: 0.5, y: 0.25, scale: 1 },
2804
- { x: 0.5, y: 0.75, scale: 1 }
2805
- ];
2806
- case "2h":
2807
- return [
2808
- { x: 0.25, y: 0.5, scale: 0.5 },
2809
- { x: 0.75, y: 0.5, scale: 0.5 }
2810
- ];
2811
- case "3v":
2812
- return [
2813
- { x: 0.5, y: 1 / 6, scale: 1 },
2814
- { x: 0.5, y: 0.5, scale: 1 },
2815
- { x: 0.5, y: 5 / 6, scale: 1 }
2816
- ];
2817
- case "4grid":
2818
- return [
2819
- { x: 0.25, y: 0.25, scale: 0.5 },
2820
- { x: 0.75, y: 0.25, scale: 0.5 },
2821
- { x: 0.25, y: 0.75, scale: 0.5 },
2822
- { x: 0.75, y: 0.75, scale: 0.5 }
2823
- ];
2824
- default: {
2825
- const _exhaustive = preset;
2826
- void _exhaustive;
2827
- return [{ x: 0.5, y: 0.5, scale: 1 }];
2798
+ return layoutCellBounds(preset).map((cell) => ({
2799
+ x: (cell.x / cell.width + 0.5) * cell.width,
2800
+ y: (cell.y / cell.height + 0.5) * cell.height,
2801
+ scale: cell.width
2802
+ }));
2803
+ }
2804
+ function layoutCellBounds(preset) {
2805
+ const dimensions = {
2806
+ "1": [1, 1],
2807
+ "2v": [1, 2],
2808
+ "2h": [2, 1],
2809
+ "3v": [1, 3],
2810
+ "4grid": [2, 2],
2811
+ "6grid": [2, 3]
2812
+ };
2813
+ const grid = dimensions[preset];
2814
+ if (!grid) throw new RangeError("Unknown layout preset");
2815
+ const [columns, rows] = grid;
2816
+ return Array.from({ length: columns * rows }, (_, index) => ({
2817
+ x: index % columns / columns,
2818
+ y: Math.floor(index / columns) / rows,
2819
+ width: 1 / columns,
2820
+ height: 1 / rows
2821
+ }));
2822
+ }
2823
+ function fitImageToLayoutCell(cell, documentSize, intrinsic, options = {}) {
2824
+ for (const size of [documentSize, intrinsic]) {
2825
+ if (![size.width, size.height].every((v) => Number.isFinite(v) && v > 0)) {
2826
+ throw new RangeError("Layout sizes must be finite and positive");
2828
2827
  }
2829
2828
  }
2829
+ 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) {
2830
+ throw new RangeError("Layout cell must lie inside the document");
2831
+ }
2832
+ const zoom = options.zoom ?? 1;
2833
+ const center = options.center ?? { x: 0.5, y: 0.5 };
2834
+ if (![zoom, center.x, center.y].every(Number.isFinite)) {
2835
+ throw new RangeError("Layout controls must be finite");
2836
+ }
2837
+ const base = centeredCropForAspect(
2838
+ intrinsic,
2839
+ cell.width * documentSize.width / (cell.height * documentSize.height)
2840
+ );
2841
+ const factor = Math.max(1, Math.min(32, zoom));
2842
+ const width = base.width / factor;
2843
+ const height = base.height / factor;
2844
+ return {
2845
+ pixelSnap: true,
2846
+ crop: {
2847
+ x: Math.max(0, Math.min(1 - width, center.x - width / 2)),
2848
+ y: Math.max(0, Math.min(1 - height, center.y - height / 2)),
2849
+ width,
2850
+ height
2851
+ },
2852
+ transform: {
2853
+ x: cell.x + cell.width / 2,
2854
+ y: cell.y + cell.height / 2,
2855
+ scale: cell.width,
2856
+ rotation: 0,
2857
+ anchor: { x: 0.5, y: 0.5 },
2858
+ flipX: false,
2859
+ flipY: false
2860
+ }
2861
+ };
2830
2862
  }
2831
2863
  function cellToTransformPatch(cell) {
2832
2864
  return { x: cell.x, y: cell.y, scale: cell.scale, rotation: 0 };
@@ -2839,17 +2871,23 @@ var PRESETS = [
2839
2871
  { id: "2v", label: "2 rows" },
2840
2872
  { id: "2h", label: "2 cols" },
2841
2873
  { id: "3v", label: "3 rows" },
2842
- { id: "4grid", label: "Grid" }
2874
+ { id: "4grid", label: "Grid" },
2875
+ { id: "6grid", label: "6 grid" }
2843
2876
  ];
2844
2877
  function LayoutPanel() {
2845
2878
  const { document, dispatch } = useEditor13();
2846
2879
  const theme = useTheme();
2847
2880
  const apply = (preset) => {
2848
- const cells = layoutCells(preset, document.size);
2881
+ const cells = layoutCellBounds(preset);
2849
2882
  const images = document.layers.filter((l) => l.type === "image");
2883
+ const fits = images.slice(0, cells.length).map((layer, i) => ({
2884
+ layer,
2885
+ fit: fitImageToLayoutCell(cells[i], document.size, layer.data.intrinsic)
2886
+ }));
2850
2887
  dispatch({ type: "history/beginBatch", label: "layout" });
2851
- images.slice(0, cells.length).forEach((layer, i) => {
2852
- dispatch({ type: "layer/transform", id: layer.id, patch: cellToTransformPatch(cells[i]) });
2888
+ fits.forEach(({ layer, fit }) => {
2889
+ dispatch({ type: "layer/transform", id: layer.id, patch: fit.transform });
2890
+ dispatch({ type: "layer/patchData", id: layer.id, patch: { crop: fit.crop, pixelSnap: fit.pixelSnap } });
2853
2891
  });
2854
2892
  dispatch({ type: "history/endBatch" });
2855
2893
  };
@@ -4624,6 +4662,8 @@ export {
4624
4662
  createGestureController,
4625
4663
  createUiStateStore,
4626
4664
  defaultTheme,
4665
+ fitImageToLayoutCell,
4666
+ layoutCellBounds,
4627
4667
  layoutCells,
4628
4668
  mergeSlots,
4629
4669
  mergeTheme,