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