UNPKG

@activecollab/components

Version:

ActiveCollab Components

145 lines (141 loc) 5.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useStackedCardResize = void 0; var _react = require("react"); var _resizePolicy = require("./resizePolicy"); /** * The one place pointer and keyboard input meet the resize policy. * * `StackedCard`'s built-in grip reports raw deltas and knows no policy — enough * for a host that just tracks a width. This hook is the full contract: it * captures the gesture start, funnels both inputs through the pure policy in * `resizePolicy.ts`, streams preview events and fires exactly ONE commit per * gesture. It returns the props to spread on the grip, including the live * separator ARIA. * * Preview versus commit (spec §7e): the continuous stream is live feedback * only. A host creates an undo entry on the COMMIT, never on a preview — and a * gesture that never changed the size commits nothing at all, so a bare click * on the grip is not a change. * * The hook never touches the card's content: the intrinsic minimum is read * through `contentMin`, which may be a getter so a card that measures its own * footer can answer at the moment it is asked. */ /** The props to spread on the grip — `StackedCard`'s `resizeHandleProps`. */ var sameSize = function sameSize(a, b) { return a.w === b.w && a.h === b.h; }; var useStackedCardResize = exports.useStackedCardResize = function useStackedCardResize(_ref) { var size = _ref.size, policy = _ref.policy, cardId = _ref.cardId, contentMin = _ref.contentMin, _ref$axis = _ref.axis, axis = _ref$axis === void 0 ? "both" : _ref$axis, _ref$scale = _ref.scale, scale = _ref$scale === void 0 ? 1 : _ref$scale, _ref$label = _ref.label, label = _ref$label === void 0 ? "Resize card" : _ref$label, onResize = _ref.onResize, onResizeCommit = _ref.onResizeCommit; // The pointer gesture's anchor: the size + content-min captured on pointer // down, plus the pointer origin the delta is measured from. var pointerStart = (0, _react.useRef)(null); // Mirrors the latest emitted size so pointer-up / key-up can commit exactly // what preview last showed, without a stale closure. var latest = (0, _react.useRef)(size); latest.current = size; // Whether this gesture actually moved the card. A bare click, or a Home on an // axis with no floor, leaves it false and commits nothing. var dirty = (0, _react.useRef)(false); // Read through refs so the handlers below can stay stable across renders // while still seeing the current policy, axis and zoom. var policyRef = (0, _react.useRef)(policy); policyRef.current = policy; var axisRef = (0, _react.useRef)(axis); axisRef.current = axis; var scaleRef = (0, _react.useRef)(scale); scaleRef.current = scale; var contentMinRef = (0, _react.useRef)(contentMin); contentMinRef.current = contentMin; var readContentMin = (0, _react.useCallback)(function () { var source = contentMinRef.current; return typeof source === "function" ? source() : source; }, []); var emitPreview = (0, _react.useCallback)(function (next, source) { // Nothing changed — not a preview, and not something to commit later. if (sameSize(next, latest.current)) return; latest.current = next; dirty.current = true; onResize(next, source); }, [onResize]); var handlePointerDown = (0, _react.useCallback)(function (e) { var _setPointerCapture, _ref2; pointerStart.current = { start: (0, _resizePolicy.makeStart)(latest.current, readContentMin()), x: e.clientX, y: e.clientY }; dirty.current = false; (_setPointerCapture = (_ref2 = e.target).setPointerCapture) === null || _setPointerCapture === void 0 || _setPointerCapture.call(_ref2, e.pointerId); e.preventDefault(); }, [readContentMin]); var handlePointerMove = (0, _react.useCallback)(function (e) { var ps = pointerStart.current; if (!ps) return; var z = scaleRef.current || 1; var next = (0, _resizePolicy.applyResize)(ps.start, { dx: (e.clientX - ps.x) / z, dy: (e.clientY - ps.y) / z }, policyRef.current, // Shift held during a free-form drag = temporary proportional lock. { constrain: e.shiftKey, axis: axisRef.current }); emitPreview(next, "pointer"); }, [emitPreview]); var endPointer = (0, _react.useCallback)(function () { if (!pointerStart.current) return; pointerStart.current = null; if (dirty.current) onResizeCommit(latest.current, "pointer"); dirty.current = false; }, [onResizeCommit]); var handleKeyDown = (0, _react.useCallback)(function (e) { var next = (0, _resizePolicy.keyboardResize)(e.key, latest.current, policyRef.current, readContentMin(), { shiftKey: e.shiftKey, axis: axisRef.current }); if (!next) return; // The key is ours even when it resolves to no movement (already pinned at // a bound), so the browser must not also scroll the surface. e.preventDefault(); emitPreview(next, "keyboard"); }, [emitPreview, readContentMin]); var handleKeyUp = (0, _react.useCallback)(function (e) { if (!(0, _resizePolicy.isResizeKey)(e.key)) return; // The gesture end for the keyboard is the key release: one commit per // hold, mirroring pointer-up after a stream of moves. if (dirty.current) onResizeCommit(latest.current, "keyboard"); dirty.current = false; }, [onResizeCommit]); return { role: "separator", tabIndex: 0, "aria-label": label, "aria-controls": cardId, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": (0, _resizePolicy.measurePercent)(size, policy, readContentMin()), onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: endPointer, onLostPointerCapture: endPointer, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }; }; //# sourceMappingURL=useStackedCardResize.js.map