@activecollab/components
Version:
ActiveCollab Components
111 lines • 5.29 kB
TypeScript
/**
* StackedCard resize policy — pure math.
*
* The card reports intent; the HOST applies a resize policy (spec §7). This
* module is that policy, packaged as pure functions so the SAME code path
* serves the pointer drag and the keyboard resize. Nothing here touches the
* DOM, React or the card's content: it takes a start size, a delta and a
* policy, and returns a clamped size. `useStackedCardResize` wires events to
* it; the card's intrinsic content minimum is measured by the host and passed
* in as `contentMin`, so this module knows nothing about heroes or footers.
*
* The policy has four parts:
* - bounds — optional min/max per axis; unset means unbounded.
* - proportional — lock the aspect ratio captured at the start of the gesture;
* the scale is clamped by the BINDING axis so the ratio never
* distorts at a bound.
* - step — optional grid snap; proportion wins over the grid.
* - content min — the effective min is max(policyMin, contentMin) per axis,
* so a card can never be crushed below what its content needs.
*/
export interface StackedCardSize {
w: number;
h: number;
}
/** The card's intrinsic minimum, measured from its real content. */
export interface StackedCardContentMin {
w: number;
h: number;
}
export interface StackedCardResizePolicy {
minW?: number;
maxW?: number;
minH?: number;
maxH?: number;
/** Lock the aspect ratio for the whole gesture. */
proportional: boolean;
/** Grid snap increment in px; omitted / 0 means continuous. */
step?: number;
}
/** The size captured at the start of a gesture (pointer down or a key press). */
export interface StackedCardResizeStart {
w: number;
h: number;
contentMin: StackedCardContentMin;
}
export interface StackedCardResizeDelta {
dx: number;
dy: number;
}
export interface StackedCardResizeBounds {
wMin: number;
wMax: number;
hMin: number;
hMax: number;
}
/**
* `width` locks the vertical axis: an auto-height card takes a width and lets
* its rows set the height, so the gesture's vertical component is ignored.
*/
export type StackedCardResizeAxis = "both" | "width";
/** Which input drove a resize event. Hosts log undo entries per source. */
export type StackedCardResizeSource = "pointer" | "keyboard";
/** Keyboard resize nudges by the policy step, or this when no step is set. */
export declare const DEFAULT_KEYBOARD_STEP = 8;
/** Shift + arrow resizes by a larger increment (the familiar coarse nudge). */
export declare const SHIFT_STEP_MULTIPLIER = 4;
/** Keys the separator handles; everything else falls through to the browser. */
export declare const RESIZE_KEYS: ReadonlyArray<string>;
export declare const isResizeKey: (key: string) => boolean;
export declare const clamp: (v: number, lo: number, hi?: number) => number;
export declare const snap: (v: number, step?: number) => number;
export declare const makeStart: (size: StackedCardSize, contentMin: StackedCardContentMin) => StackedCardResizeStart;
/**
* The effective bounds a size is clamped to: the policy min floored by the
* content min, and the policy max (unbounded when unset). Independent of any
* live gesture, so a host can also use it for the aria value and Home/End.
*/
export declare const effectiveBounds: (policy: StackedCardResizePolicy, contentMin: StackedCardContentMin) => StackedCardResizeBounds;
/**
* Apply a delta to the start size under the policy — the single path for both
* inputs.
*
* `constrain` is the transient Shift-to-constrain lock: a free-form policy
* behaves proportionally for that one gesture; a proportional policy is already
* locked and ignores it. `axis: "width"` drops the gesture's vertical component;
* the height then holds still in free-form mode, and still follows the ratio in
* proportional mode (that is what proportional means).
*/
export declare const applyResize: (start: StackedCardResizeStart, delta: StackedCardResizeDelta, policy: StackedCardResizePolicy, opts?: {
constrain?: boolean;
axis?: StackedCardResizeAxis;
}) => StackedCardSize;
/**
* Translate a resize key into the next size, reusing `applyResize` so the
* keyboard clamps exactly like the pointer. Arrows nudge by the step (Shift ×4);
* Home/End jump to the min/max of the allowed range, leaving any axis without
* that bound where it is. Returns null for a key the handle does not own, and
* for a vertical key on a width-only card.
*/
export declare const keyboardResize: (key: string, size: StackedCardSize, policy: StackedCardResizePolicy, contentMin: StackedCardContentMin, opts?: {
shiftKey?: boolean;
axis?: StackedCardResizeAxis;
}) => StackedCardSize | null;
/**
* The handle's `aria-valuenow`: the current size as a percent (0–100) of its
* allowed range. The corner resizes both axes, but the value must be a single
* number, so it reports the WIDTH axis — the one axis the fixed-box and the
* width-only cards share. Returns 0 when the range isn't finite (no max bound).
*/
export declare const measurePercent: (size: StackedCardSize, policy: StackedCardResizePolicy, contentMin: StackedCardContentMin) => number;
//# sourceMappingURL=resizePolicy.d.ts.map