@xeplr/ui-canvas 1.0.1 → 1.0.2

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 CHANGED
@@ -90,6 +90,7 @@ Edges follow their node **while** it is being dragged, not only after the drop.
90
90
  | `items` | `Array<{ id, x, y, w, h, z?, groupId? }>` | required | `z` sets paint order |
91
91
  | `renderItem` | `(item, { selected }) => ReactNode` | required | the item's content; the canvas positions it |
92
92
  | `units` | `'px' \| 'fraction'` | `'px'` | see above |
93
+ | `pageAspect` | number | — | fraction units only: one page is `width × pageAspect` tall instead of the visible height, so a layout keeps the same proportions at any size |
93
94
  | `features` | `{ drag, resize, snap, grid, marquee }` | `{ drag: true, resize: false, snap: true, grid: 10, marquee: false }` | merged over the defaults |
94
95
  | `onItemChange` | `(id, patch) => void` | — | once per item, on drop, in the item's own units |
95
96
  | `onItemClick` | `(id, event) => void` | — | a press that moved less than 4px |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeplr/ui-canvas",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "One free-placement canvas for every xeplr builder: drag, resize, alignment guides, snapping, marquee select and edges — React controller hooks, pure geometry and a ready-made <XeplrCanvas>",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/pages.jsx CHANGED
@@ -26,6 +26,9 @@ import { CanvasSample } from './designs/index.js'
26
26
  * @prop edgeMinOffset minimum sideways reach of an edge's curve, px (default 60)
27
27
  * @prop padding room beyond the furthest item: number or { x, y }
28
28
  * @prop minWidth, minHeight the smallest the inner canvas gets
29
+ * @prop pageAspect fraction units only: a page is width × pageAspect tall,
30
+ * instead of the visible height — proportions then hold
31
+ * at any size
29
32
  * @prop underlay, overlay extra layers under the edges / over everything
30
33
  * @prop className, style on the scrolling wrapper
31
34
  */
@@ -27,7 +27,7 @@ export function useCanvasController(props) {
27
27
  const {
28
28
  items, units = 'px', features, edges, selection,
29
29
  onItemClick, onRaise, minSizeFor,
30
- padding, minWidth = 0, minHeight = 0
30
+ padding, minWidth = 0, minHeight = 0, pageAspect
31
31
  } = props
32
32
  // onItemChange and onSelectionChange are read through propsRef below, so a
33
33
  // new inline handler from the caller never rebuilds the gestures.
@@ -35,9 +35,16 @@ export function useCanvasController(props) {
35
35
  const f = useMemo(() => ({ ...DEFAULT_FEATURES, ...features }), [features])
36
36
  const fraction = units === 'fraction'
37
37
 
38
- // Measured only for a fractional canvas, where a page IS the visible size.
38
+ // Measured only for a fractional canvas. A page is the visible size — or,
39
+ // with pageAspect, the WIDTH times pageAspect, so a layout keeps its
40
+ // proportions wherever it is shown instead of depending on how tall the
41
+ // wrapper happens to be.
39
42
  const [measured, measureRef] = useCanvasSize()
40
- const canvas = fraction ? measured : null
43
+ const canvas = useMemo(() => {
44
+ if (!fraction || !measured) return null
45
+ if (!(pageAspect > 0)) return measured
46
+ return { width: measured.width, height: measured.width * pageAspect }
47
+ }, [fraction, measured, pageAspect])
41
48
  const canvasRef = useRef(canvas); canvasRef.current = canvas
42
49
  const rootRef = useRef(null)
43
50