@activecollab/components 2.0.372 → 2.0.374
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/cjs/components/StackedCard/StackedCard.js +103 -19
- package/dist/cjs/components/StackedCard/StackedCard.js.map +1 -1
- package/dist/cjs/components/StackedCard/Styles.js +22 -17
- package/dist/cjs/components/StackedCard/Styles.js.map +1 -1
- package/dist/cjs/components/StackedCard/index.js +22 -0
- package/dist/cjs/components/StackedCard/index.js.map +1 -1
- package/dist/cjs/components/StackedCard/resizePolicy.js +238 -0
- package/dist/cjs/components/StackedCard/resizePolicy.js.map +1 -0
- package/dist/cjs/components/StackedCard/resizePolicy.test.js +474 -0
- package/dist/cjs/components/StackedCard/resizePolicy.test.js.map +1 -0
- package/dist/cjs/components/StackedCard/useStackedCardResize.js +145 -0
- package/dist/cjs/components/StackedCard/useStackedCardResize.js.map +1 -0
- package/dist/esm/components/StackedCard/StackedCard.d.ts +44 -3
- package/dist/esm/components/StackedCard/StackedCard.d.ts.map +1 -1
- package/dist/esm/components/StackedCard/StackedCard.js +102 -19
- package/dist/esm/components/StackedCard/StackedCard.js.map +1 -1
- package/dist/esm/components/StackedCard/Styles.d.ts +4 -1
- package/dist/esm/components/StackedCard/Styles.d.ts.map +1 -1
- package/dist/esm/components/StackedCard/Styles.js +22 -17
- package/dist/esm/components/StackedCard/Styles.js.map +1 -1
- package/dist/esm/components/StackedCard/index.d.ts +2 -0
- package/dist/esm/components/StackedCard/index.d.ts.map +1 -1
- package/dist/esm/components/StackedCard/index.js +2 -0
- package/dist/esm/components/StackedCard/index.js.map +1 -1
- package/dist/esm/components/StackedCard/resizePolicy.d.ts +111 -0
- package/dist/esm/components/StackedCard/resizePolicy.d.ts.map +1 -0
- package/dist/esm/{presentation/stackedCard → components/StackedCard}/resizePolicy.js +93 -48
- package/dist/esm/components/StackedCard/resizePolicy.js.map +1 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.d.ts +2 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.d.ts.map +1 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.js +470 -0
- package/dist/esm/components/StackedCard/resizePolicy.test.js.map +1 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.d.ts +62 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.d.ts.map +1 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.js +137 -0
- package/dist/esm/components/StackedCard/useStackedCardResize.js.map +1 -0
- package/dist/index.js +500 -36
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/presentation/stackedCard/resizePolicy.js +0 -183
- package/dist/cjs/presentation/stackedCard/resizePolicy.js.map +0 -1
- package/dist/esm/presentation/stackedCard/resizePolicy.d.ts +0 -97
- package/dist/esm/presentation/stackedCard/resizePolicy.d.ts.map +0 -1
- package/dist/esm/presentation/stackedCard/resizePolicy.js.map +0 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.snap = exports.measurePercent = exports.makeStart = exports.keyboardResize = exports.isResizeKey = exports.effectiveBounds = exports.clamp = exports.applyResize = exports.SHIFT_STEP_MULTIPLIER = exports.RESIZE_KEYS = exports.DEFAULT_KEYBOARD_STEP = void 0;
|
|
7
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
8
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
10
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
11
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
12
|
+
/**
|
|
13
|
+
* StackedCard resize policy — pure math.
|
|
14
|
+
*
|
|
15
|
+
* The card reports intent; the HOST applies a resize policy (spec §7). This
|
|
16
|
+
* module is that policy, packaged as pure functions so the SAME code path
|
|
17
|
+
* serves the pointer drag and the keyboard resize. Nothing here touches the
|
|
18
|
+
* DOM, React or the card's content: it takes a start size, a delta and a
|
|
19
|
+
* policy, and returns a clamped size. `useStackedCardResize` wires events to
|
|
20
|
+
* it; the card's intrinsic content minimum is measured by the host and passed
|
|
21
|
+
* in as `contentMin`, so this module knows nothing about heroes or footers.
|
|
22
|
+
*
|
|
23
|
+
* The policy has four parts:
|
|
24
|
+
* - bounds — optional min/max per axis; unset means unbounded.
|
|
25
|
+
* - proportional — lock the aspect ratio captured at the start of the gesture;
|
|
26
|
+
* the scale is clamped by the BINDING axis so the ratio never
|
|
27
|
+
* distorts at a bound.
|
|
28
|
+
* - step — optional grid snap; proportion wins over the grid.
|
|
29
|
+
* - content min — the effective min is max(policyMin, contentMin) per axis,
|
|
30
|
+
* so a card can never be crushed below what its content needs.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** The card's intrinsic minimum, measured from its real content. */
|
|
34
|
+
|
|
35
|
+
/** The size captured at the start of a gesture (pointer down or a key press). */
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `width` locks the vertical axis: an auto-height card takes a width and lets
|
|
39
|
+
* its rows set the height, so the gesture's vertical component is ignored.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/** Which input drove a resize event. Hosts log undo entries per source. */
|
|
43
|
+
|
|
44
|
+
/** Keyboard resize nudges by the policy step, or this when no step is set. */
|
|
45
|
+
var DEFAULT_KEYBOARD_STEP = exports.DEFAULT_KEYBOARD_STEP = 8;
|
|
46
|
+
|
|
47
|
+
/** Shift + arrow resizes by a larger increment (the familiar coarse nudge). */
|
|
48
|
+
var SHIFT_STEP_MULTIPLIER = exports.SHIFT_STEP_MULTIPLIER = 4;
|
|
49
|
+
|
|
50
|
+
/** Keys the separator handles; everything else falls through to the browser. */
|
|
51
|
+
var RESIZE_KEYS = exports.RESIZE_KEYS = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"];
|
|
52
|
+
var isResizeKey = exports.isResizeKey = function isResizeKey(key) {
|
|
53
|
+
return RESIZE_KEYS.includes(key);
|
|
54
|
+
};
|
|
55
|
+
var clamp = exports.clamp = function clamp(v, lo, hi) {
|
|
56
|
+
return Math.min(hi !== null && hi !== void 0 ? hi : Number.POSITIVE_INFINITY, Math.max(lo, v));
|
|
57
|
+
};
|
|
58
|
+
var snap = exports.snap = function snap(v, step) {
|
|
59
|
+
return step && step > 0 ? Math.round(v / step) * step : v;
|
|
60
|
+
};
|
|
61
|
+
var makeStart = exports.makeStart = function makeStart(size, contentMin) {
|
|
62
|
+
return {
|
|
63
|
+
w: size.w,
|
|
64
|
+
h: size.h,
|
|
65
|
+
contentMin
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The effective bounds a size is clamped to: the policy min floored by the
|
|
71
|
+
* content min, and the policy max (unbounded when unset). Independent of any
|
|
72
|
+
* live gesture, so a host can also use it for the aria value and Home/End.
|
|
73
|
+
*/
|
|
74
|
+
var effectiveBounds = exports.effectiveBounds = function effectiveBounds(policy, contentMin) {
|
|
75
|
+
var _policy$minW, _policy$minH, _policy$maxW, _policy$maxH;
|
|
76
|
+
return {
|
|
77
|
+
wMin: Math.max((_policy$minW = policy.minW) !== null && _policy$minW !== void 0 ? _policy$minW : 0, contentMin.w),
|
|
78
|
+
hMin: Math.max((_policy$minH = policy.minH) !== null && _policy$minH !== void 0 ? _policy$minH : 0, contentMin.h),
|
|
79
|
+
wMax: (_policy$maxW = policy.maxW) !== null && _policy$maxW !== void 0 ? _policy$maxW : Number.POSITIVE_INFINITY,
|
|
80
|
+
hMax: (_policy$maxH = policy.maxH) !== null && _policy$maxH !== void 0 ? _policy$maxH : Number.POSITIVE_INFINITY
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Whether an axis has a floor anyone asked for. `effectiveBounds` reports 0 for
|
|
86
|
+
* an unset minimum — correct as a clamp, but not something Home should jump to:
|
|
87
|
+
* an axis nobody gave a minimum must not collapse to nothing.
|
|
88
|
+
*/
|
|
89
|
+
var hasFloor = function hasFloor(policyMin, contentMin) {
|
|
90
|
+
return policyMin !== undefined || contentMin > 0;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Apply a delta to the start size under the policy — the single path for both
|
|
95
|
+
* inputs.
|
|
96
|
+
*
|
|
97
|
+
* `constrain` is the transient Shift-to-constrain lock: a free-form policy
|
|
98
|
+
* behaves proportionally for that one gesture; a proportional policy is already
|
|
99
|
+
* locked and ignores it. `axis: "width"` drops the gesture's vertical component;
|
|
100
|
+
* the height then holds still in free-form mode, and still follows the ratio in
|
|
101
|
+
* proportional mode (that is what proportional means).
|
|
102
|
+
*/
|
|
103
|
+
var applyResize = exports.applyResize = function applyResize(start, delta, policy) {
|
|
104
|
+
var opts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
105
|
+
var _effectiveBounds = effectiveBounds(policy, start.contentMin),
|
|
106
|
+
wMin = _effectiveBounds.wMin,
|
|
107
|
+
hMin = _effectiveBounds.hMin,
|
|
108
|
+
wMax = _effectiveBounds.wMax,
|
|
109
|
+
hMax = _effectiveBounds.hMax;
|
|
110
|
+
var widthOnly = opts.axis === "width";
|
|
111
|
+
var dx = delta.dx;
|
|
112
|
+
var dy = widthOnly ? 0 : delta.dy;
|
|
113
|
+
|
|
114
|
+
// A ratio needs two non-zero sides to be a ratio at all; a width-only card
|
|
115
|
+
// parks a placeholder height, so fall back to free-form rather than dividing
|
|
116
|
+
// by zero.
|
|
117
|
+
var proportional = (policy.proportional || opts.constrain === true) && start.w > 0 && start.h > 0;
|
|
118
|
+
var w;
|
|
119
|
+
var h;
|
|
120
|
+
if (proportional) {
|
|
121
|
+
// one scale drives both axes; the corner's dominant direction wins, so a
|
|
122
|
+
// vertical drag is as effective as a horizontal one
|
|
123
|
+
var sW = (start.w + dx) / start.w;
|
|
124
|
+
var sH = (start.h + dy) / start.h;
|
|
125
|
+
var scale = Math.abs(sW - 1) >= Math.abs(sH - 1) ? sW : sH;
|
|
126
|
+
|
|
127
|
+
// step: proportion wins over the grid. Snap through the SCALE (driven off
|
|
128
|
+
// the width edge) so both axes move together and the ratio survives; the
|
|
129
|
+
// grid yields whenever honouring it would cost the ratio.
|
|
130
|
+
if (policy.step) {
|
|
131
|
+
scale = snap(start.w * scale, policy.step) / start.w;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Then clamp the scale so both axes stay in bounds (the binding constraint):
|
|
135
|
+
// the ratio can never break at a bound — whichever edge is limiting stops
|
|
136
|
+
// both. The clamp comes last on purpose: a bound is a hard stop, so the card
|
|
137
|
+
// sits exactly on it rather than at the nearest grid line inside it.
|
|
138
|
+
var scaleMin = Math.max(wMin / start.w, hMin / start.h);
|
|
139
|
+
var scaleMax = Math.min(wMax / start.w, hMax / start.h);
|
|
140
|
+
scale = clamp(scale, scaleMin, Math.max(scaleMin, scaleMax));
|
|
141
|
+
w = start.w * scale;
|
|
142
|
+
h = start.h * scale;
|
|
143
|
+
} else {
|
|
144
|
+
w = clamp(snap(start.w + dx, policy.step), wMin, wMax);
|
|
145
|
+
h = widthOnly ? start.h : clamp(snap(start.h + dy, policy.step), hMin, hMax);
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
w: Math.round(w),
|
|
149
|
+
h: Math.round(h)
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Translate a resize key into the next size, reusing `applyResize` so the
|
|
155
|
+
* keyboard clamps exactly like the pointer. Arrows nudge by the step (Shift ×4);
|
|
156
|
+
* Home/End jump to the min/max of the allowed range, leaving any axis without
|
|
157
|
+
* that bound where it is. Returns null for a key the handle does not own, and
|
|
158
|
+
* for a vertical key on a width-only card.
|
|
159
|
+
*/
|
|
160
|
+
var keyboardResize = exports.keyboardResize = function keyboardResize(key, size, policy, contentMin) {
|
|
161
|
+
var opts = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
|
|
162
|
+
var widthOnly = opts.axis === "width";
|
|
163
|
+
if (widthOnly && (key === "ArrowUp" || key === "ArrowDown")) return null;
|
|
164
|
+
var base = policy.step && policy.step > 0 ? policy.step : DEFAULT_KEYBOARD_STEP;
|
|
165
|
+
var step = base * (opts.shiftKey ? SHIFT_STEP_MULTIPLIER : 1);
|
|
166
|
+
var start = makeStart(size, contentMin);
|
|
167
|
+
var b = effectiveBounds(policy, contentMin);
|
|
168
|
+
var apply = function apply(delta) {
|
|
169
|
+
return applyResize(start, delta, policy, {
|
|
170
|
+
axis: opts.axis
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Home and End are absolute jumps to a bound, not nudges, so they ignore the
|
|
176
|
+
* grid: landing 4px off the minimum because that is where the nearest grid
|
|
177
|
+
* line fell would mean the keyboard could never reach the bound the pointer
|
|
178
|
+
* stops at.
|
|
179
|
+
*/
|
|
180
|
+
var jump = function jump(delta) {
|
|
181
|
+
return applyResize(start, delta, _objectSpread(_objectSpread({}, policy), {}, {
|
|
182
|
+
step: 0
|
|
183
|
+
}), {
|
|
184
|
+
axis: opts.axis
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
switch (key) {
|
|
188
|
+
case "ArrowRight":
|
|
189
|
+
return apply({
|
|
190
|
+
dx: step,
|
|
191
|
+
dy: 0
|
|
192
|
+
});
|
|
193
|
+
case "ArrowLeft":
|
|
194
|
+
return apply({
|
|
195
|
+
dx: -step,
|
|
196
|
+
dy: 0
|
|
197
|
+
});
|
|
198
|
+
case "ArrowDown":
|
|
199
|
+
return apply({
|
|
200
|
+
dx: 0,
|
|
201
|
+
dy: step
|
|
202
|
+
});
|
|
203
|
+
case "ArrowUp":
|
|
204
|
+
return apply({
|
|
205
|
+
dx: 0,
|
|
206
|
+
dy: -step
|
|
207
|
+
});
|
|
208
|
+
case "Home":
|
|
209
|
+
// jump to the min corner; an axis with no floor of its own stays put
|
|
210
|
+
return jump({
|
|
211
|
+
dx: hasFloor(policy.minW, contentMin.w) ? b.wMin - size.w : 0,
|
|
212
|
+
dy: !widthOnly && hasFloor(policy.minH, contentMin.h) ? b.hMin - size.h : 0
|
|
213
|
+
});
|
|
214
|
+
case "End":
|
|
215
|
+
// jump to the max corner; an unbounded axis simply doesn't move
|
|
216
|
+
return jump({
|
|
217
|
+
dx: Number.isFinite(b.wMax) ? b.wMax - size.w : 0,
|
|
218
|
+
dy: !widthOnly && Number.isFinite(b.hMax) ? b.hMax - size.h : 0
|
|
219
|
+
});
|
|
220
|
+
default:
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* The handle's `aria-valuenow`: the current size as a percent (0–100) of its
|
|
227
|
+
* allowed range. The corner resizes both axes, but the value must be a single
|
|
228
|
+
* number, so it reports the WIDTH axis — the one axis the fixed-box and the
|
|
229
|
+
* width-only cards share. Returns 0 when the range isn't finite (no max bound).
|
|
230
|
+
*/
|
|
231
|
+
var measurePercent = exports.measurePercent = function measurePercent(size, policy, contentMin) {
|
|
232
|
+
var _effectiveBounds2 = effectiveBounds(policy, contentMin),
|
|
233
|
+
wMin = _effectiveBounds2.wMin,
|
|
234
|
+
wMax = _effectiveBounds2.wMax;
|
|
235
|
+
if (!Number.isFinite(wMax) || wMax <= wMin) return 0;
|
|
236
|
+
return Math.round(clamp((size.w - wMin) / (wMax - wMin) * 100, 0, 100));
|
|
237
|
+
};
|
|
238
|
+
//# sourceMappingURL=resizePolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizePolicy.js","names":["DEFAULT_KEYBOARD_STEP","exports","SHIFT_STEP_MULTIPLIER","RESIZE_KEYS","isResizeKey","key","includes","clamp","v","lo","hi","Math","min","Number","POSITIVE_INFINITY","max","snap","step","round","makeStart","size","contentMin","w","h","effectiveBounds","policy","_policy$minW","_policy$minH","_policy$maxW","_policy$maxH","wMin","minW","hMin","minH","wMax","maxW","hMax","maxH","hasFloor","policyMin","undefined","applyResize","start","delta","opts","arguments","length","_effectiveBounds","widthOnly","axis","dx","dy","proportional","constrain","sW","sH","scale","abs","scaleMin","scaleMax","keyboardResize","base","shiftKey","b","apply","jump","_objectSpread","isFinite","measurePercent","_effectiveBounds2"],"sources":["../../../../src/components/StackedCard/resizePolicy.ts"],"sourcesContent":["/**\n * StackedCard resize policy — pure math.\n *\n * The card reports intent; the HOST applies a resize policy (spec §7). This\n * module is that policy, packaged as pure functions so the SAME code path\n * serves the pointer drag and the keyboard resize. Nothing here touches the\n * DOM, React or the card's content: it takes a start size, a delta and a\n * policy, and returns a clamped size. `useStackedCardResize` wires events to\n * it; the card's intrinsic content minimum is measured by the host and passed\n * in as `contentMin`, so this module knows nothing about heroes or footers.\n *\n * The policy has four parts:\n * - bounds — optional min/max per axis; unset means unbounded.\n * - proportional — lock the aspect ratio captured at the start of the gesture;\n * the scale is clamped by the BINDING axis so the ratio never\n * distorts at a bound.\n * - step — optional grid snap; proportion wins over the grid.\n * - content min — the effective min is max(policyMin, contentMin) per axis,\n * so a card can never be crushed below what its content needs.\n */\n\nexport interface StackedCardSize {\n w: number;\n h: number;\n}\n\n/** The card's intrinsic minimum, measured from its real content. */\nexport interface StackedCardContentMin {\n w: number;\n h: number;\n}\n\nexport interface StackedCardResizePolicy {\n minW?: number;\n maxW?: number;\n minH?: number;\n maxH?: number;\n /** Lock the aspect ratio for the whole gesture. */\n proportional: boolean;\n /** Grid snap increment in px; omitted / 0 means continuous. */\n step?: number;\n}\n\n/** The size captured at the start of a gesture (pointer down or a key press). */\nexport interface StackedCardResizeStart {\n w: number;\n h: number;\n contentMin: StackedCardContentMin;\n}\n\nexport interface StackedCardResizeDelta {\n dx: number;\n dy: number;\n}\n\nexport interface StackedCardResizeBounds {\n wMin: number;\n wMax: number;\n hMin: number;\n hMax: number;\n}\n\n/**\n * `width` locks the vertical axis: an auto-height card takes a width and lets\n * its rows set the height, so the gesture's vertical component is ignored.\n */\nexport type StackedCardResizeAxis = \"both\" | \"width\";\n\n/** Which input drove a resize event. Hosts log undo entries per source. */\nexport type StackedCardResizeSource = \"pointer\" | \"keyboard\";\n\n/** Keyboard resize nudges by the policy step, or this when no step is set. */\nexport const DEFAULT_KEYBOARD_STEP = 8;\n\n/** Shift + arrow resizes by a larger increment (the familiar coarse nudge). */\nexport const SHIFT_STEP_MULTIPLIER = 4;\n\n/** Keys the separator handles; everything else falls through to the browser. */\nexport const RESIZE_KEYS: ReadonlyArray<string> = [\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"Home\",\n \"End\",\n];\n\nexport const isResizeKey = (key: string): boolean => RESIZE_KEYS.includes(key);\n\nexport const clamp = (v: number, lo: number, hi?: number): number =>\n Math.min(hi ?? Number.POSITIVE_INFINITY, Math.max(lo, v));\n\nexport const snap = (v: number, step?: number): number =>\n step && step > 0 ? Math.round(v / step) * step : v;\n\nexport const makeStart = (\n size: StackedCardSize,\n contentMin: StackedCardContentMin\n): StackedCardResizeStart => ({\n w: size.w,\n h: size.h,\n contentMin,\n});\n\n/**\n * The effective bounds a size is clamped to: the policy min floored by the\n * content min, and the policy max (unbounded when unset). Independent of any\n * live gesture, so a host can also use it for the aria value and Home/End.\n */\nexport const effectiveBounds = (\n policy: StackedCardResizePolicy,\n contentMin: StackedCardContentMin\n): StackedCardResizeBounds => ({\n wMin: Math.max(policy.minW ?? 0, contentMin.w),\n hMin: Math.max(policy.minH ?? 0, contentMin.h),\n wMax: policy.maxW ?? Number.POSITIVE_INFINITY,\n hMax: policy.maxH ?? Number.POSITIVE_INFINITY,\n});\n\n/**\n * Whether an axis has a floor anyone asked for. `effectiveBounds` reports 0 for\n * an unset minimum — correct as a clamp, but not something Home should jump to:\n * an axis nobody gave a minimum must not collapse to nothing.\n */\nconst hasFloor = (policyMin: number | undefined, contentMin: number): boolean =>\n policyMin !== undefined || contentMin > 0;\n\n/**\n * Apply a delta to the start size under the policy — the single path for both\n * inputs.\n *\n * `constrain` is the transient Shift-to-constrain lock: a free-form policy\n * behaves proportionally for that one gesture; a proportional policy is already\n * locked and ignores it. `axis: \"width\"` drops the gesture's vertical component;\n * the height then holds still in free-form mode, and still follows the ratio in\n * proportional mode (that is what proportional means).\n */\nexport const applyResize = (\n start: StackedCardResizeStart,\n delta: StackedCardResizeDelta,\n policy: StackedCardResizePolicy,\n opts: { constrain?: boolean; axis?: StackedCardResizeAxis } = {}\n): StackedCardSize => {\n const { wMin, hMin, wMax, hMax } = effectiveBounds(policy, start.contentMin);\n const widthOnly = opts.axis === \"width\";\n const dx = delta.dx;\n const dy = widthOnly ? 0 : delta.dy;\n\n // A ratio needs two non-zero sides to be a ratio at all; a width-only card\n // parks a placeholder height, so fall back to free-form rather than dividing\n // by zero.\n const proportional =\n (policy.proportional || opts.constrain === true) &&\n start.w > 0 &&\n start.h > 0;\n\n let w: number;\n let h: number;\n\n if (proportional) {\n // one scale drives both axes; the corner's dominant direction wins, so a\n // vertical drag is as effective as a horizontal one\n const sW = (start.w + dx) / start.w;\n const sH = (start.h + dy) / start.h;\n let scale = Math.abs(sW - 1) >= Math.abs(sH - 1) ? sW : sH;\n\n // step: proportion wins over the grid. Snap through the SCALE (driven off\n // the width edge) so both axes move together and the ratio survives; the\n // grid yields whenever honouring it would cost the ratio.\n if (policy.step) {\n scale = snap(start.w * scale, policy.step) / start.w;\n }\n\n // Then clamp the scale so both axes stay in bounds (the binding constraint):\n // the ratio can never break at a bound — whichever edge is limiting stops\n // both. The clamp comes last on purpose: a bound is a hard stop, so the card\n // sits exactly on it rather than at the nearest grid line inside it.\n const scaleMin = Math.max(wMin / start.w, hMin / start.h);\n const scaleMax = Math.min(wMax / start.w, hMax / start.h);\n scale = clamp(scale, scaleMin, Math.max(scaleMin, scaleMax));\n\n w = start.w * scale;\n h = start.h * scale;\n } else {\n w = clamp(snap(start.w + dx, policy.step), wMin, wMax);\n h = widthOnly\n ? start.h\n : clamp(snap(start.h + dy, policy.step), hMin, hMax);\n }\n\n return { w: Math.round(w), h: Math.round(h) };\n};\n\n/**\n * Translate a resize key into the next size, reusing `applyResize` so the\n * keyboard clamps exactly like the pointer. Arrows nudge by the step (Shift ×4);\n * Home/End jump to the min/max of the allowed range, leaving any axis without\n * that bound where it is. Returns null for a key the handle does not own, and\n * for a vertical key on a width-only card.\n */\nexport const keyboardResize = (\n key: string,\n size: StackedCardSize,\n policy: StackedCardResizePolicy,\n contentMin: StackedCardContentMin,\n opts: { shiftKey?: boolean; axis?: StackedCardResizeAxis } = {}\n): StackedCardSize | null => {\n const widthOnly = opts.axis === \"width\";\n if (widthOnly && (key === \"ArrowUp\" || key === \"ArrowDown\")) return null;\n\n const base =\n policy.step && policy.step > 0 ? policy.step : DEFAULT_KEYBOARD_STEP;\n const step = base * (opts.shiftKey ? SHIFT_STEP_MULTIPLIER : 1);\n const start = makeStart(size, contentMin);\n const b = effectiveBounds(policy, contentMin);\n const apply = (delta: StackedCardResizeDelta): StackedCardSize =>\n applyResize(start, delta, policy, { axis: opts.axis });\n\n /**\n * Home and End are absolute jumps to a bound, not nudges, so they ignore the\n * grid: landing 4px off the minimum because that is where the nearest grid\n * line fell would mean the keyboard could never reach the bound the pointer\n * stops at.\n */\n const jump = (delta: StackedCardResizeDelta): StackedCardSize =>\n applyResize(start, delta, { ...policy, step: 0 }, { axis: opts.axis });\n\n switch (key) {\n case \"ArrowRight\":\n return apply({ dx: step, dy: 0 });\n case \"ArrowLeft\":\n return apply({ dx: -step, dy: 0 });\n case \"ArrowDown\":\n return apply({ dx: 0, dy: step });\n case \"ArrowUp\":\n return apply({ dx: 0, dy: -step });\n case \"Home\":\n // jump to the min corner; an axis with no floor of its own stays put\n return jump({\n dx: hasFloor(policy.minW, contentMin.w) ? b.wMin - size.w : 0,\n dy:\n !widthOnly && hasFloor(policy.minH, contentMin.h)\n ? b.hMin - size.h\n : 0,\n });\n case \"End\":\n // jump to the max corner; an unbounded axis simply doesn't move\n return jump({\n dx: Number.isFinite(b.wMax) ? b.wMax - size.w : 0,\n dy: !widthOnly && Number.isFinite(b.hMax) ? b.hMax - size.h : 0,\n });\n default:\n return null;\n }\n};\n\n/**\n * The handle's `aria-valuenow`: the current size as a percent (0–100) of its\n * allowed range. The corner resizes both axes, but the value must be a single\n * number, so it reports the WIDTH axis — the one axis the fixed-box and the\n * width-only cards share. Returns 0 when the range isn't finite (no max bound).\n */\nexport const measurePercent = (\n size: StackedCardSize,\n policy: StackedCardResizePolicy,\n contentMin: StackedCardContentMin\n): number => {\n const { wMin, wMax } = effectiveBounds(policy, contentMin);\n if (!Number.isFinite(wMax) || wMax <= wMin) return 0;\n return Math.round(clamp(((size.w - wMin) / (wMax - wMin)) * 100, 0, 100));\n};\n"],"mappings":";;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAOA;;AAiBA;;AAmBA;AACA;AACA;AACA;;AAGA;;AAGA;AACO,IAAMA,qBAAqB,GAAAC,OAAA,CAAAD,qBAAA,GAAG,CAAC;;AAEtC;AACO,IAAME,qBAAqB,GAAAD,OAAA,CAAAC,qBAAA,GAAG,CAAC;;AAEtC;AACO,IAAMC,WAAkC,GAAAF,OAAA,CAAAE,WAAA,GAAG,CAChD,WAAW,EACX,YAAY,EACZ,SAAS,EACT,WAAW,EACX,MAAM,EACN,KAAK,CACN;AAEM,IAAMC,WAAW,GAAAH,OAAA,CAAAG,WAAA,GAAG,SAAdA,WAAWA,CAAIC,GAAW;EAAA,OAAcF,WAAW,CAACG,QAAQ,CAACD,GAAG,CAAC;AAAA;AAEvE,IAAME,KAAK,GAAAN,OAAA,CAAAM,KAAA,GAAG,SAARA,KAAKA,CAAIC,CAAS,EAAEC,EAAU,EAAEC,EAAW;EAAA,OACtDC,IAAI,CAACC,GAAG,CAACF,EAAE,aAAFA,EAAE,cAAFA,EAAE,GAAIG,MAAM,CAACC,iBAAiB,EAAEH,IAAI,CAACI,GAAG,CAACN,EAAE,EAAED,CAAC,CAAC,CAAC;AAAA;AAEpD,IAAMQ,IAAI,GAAAf,OAAA,CAAAe,IAAA,GAAG,SAAPA,IAAIA,CAAIR,CAAS,EAAES,IAAa;EAAA,OAC3CA,IAAI,IAAIA,IAAI,GAAG,CAAC,GAAGN,IAAI,CAACO,KAAK,CAACV,CAAC,GAAGS,IAAI,CAAC,GAAGA,IAAI,GAAGT,CAAC;AAAA;AAE7C,IAAMW,SAAS,GAAAlB,OAAA,CAAAkB,SAAA,GAAG,SAAZA,SAASA,CACpBC,IAAqB,EACrBC,UAAiC;EAAA,OACL;IAC5BC,CAAC,EAAEF,IAAI,CAACE,CAAC;IACTC,CAAC,EAAEH,IAAI,CAACG,CAAC;IACTF;EACF,CAAC;AAAA,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACO,IAAMG,eAAe,GAAAvB,OAAA,CAAAuB,eAAA,GAAG,SAAlBA,eAAeA,CAC1BC,MAA+B,EAC/BJ,UAAiC;EAAA,IAAAK,YAAA,EAAAC,YAAA,EAAAC,YAAA,EAAAC,YAAA;EAAA,OACJ;IAC7BC,IAAI,EAAEnB,IAAI,CAACI,GAAG,EAAAW,YAAA,GAACD,MAAM,CAACM,IAAI,cAAAL,YAAA,cAAAA,YAAA,GAAI,CAAC,EAAEL,UAAU,CAACC,CAAC,CAAC;IAC9CU,IAAI,EAAErB,IAAI,CAACI,GAAG,EAAAY,YAAA,GAACF,MAAM,CAACQ,IAAI,cAAAN,YAAA,cAAAA,YAAA,GAAI,CAAC,EAAEN,UAAU,CAACE,CAAC,CAAC;IAC9CW,IAAI,GAAAN,YAAA,GAAEH,MAAM,CAACU,IAAI,cAAAP,YAAA,cAAAA,YAAA,GAAIf,MAAM,CAACC,iBAAiB;IAC7CsB,IAAI,GAAAP,YAAA,GAAEJ,MAAM,CAACY,IAAI,cAAAR,YAAA,cAAAA,YAAA,GAAIhB,MAAM,CAACC;EAC9B,CAAC;AAAA,CAAC;;AAEF;AACA;AACA;AACA;AACA;AACA,IAAMwB,QAAQ,GAAG,SAAXA,QAAQA,CAAIC,SAA6B,EAAElB,UAAkB;EAAA,OACjEkB,SAAS,KAAKC,SAAS,IAAInB,UAAU,GAAG,CAAC;AAAA;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,IAAMoB,WAAW,GAAAxC,OAAA,CAAAwC,WAAA,GAAG,SAAdA,WAAWA,CACtBC,KAA6B,EAC7BC,KAA6B,EAC7BlB,MAA+B,EAEX;EAAA,IADpBmB,IAA2D,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAL,SAAA,GAAAK,SAAA,MAAG,CAAC,CAAC;EAEhE,IAAAE,gBAAA,GAAmCvB,eAAe,CAACC,MAAM,EAAEiB,KAAK,CAACrB,UAAU,CAAC;IAApES,IAAI,GAAAiB,gBAAA,CAAJjB,IAAI;IAAEE,IAAI,GAAAe,gBAAA,CAAJf,IAAI;IAAEE,IAAI,GAAAa,gBAAA,CAAJb,IAAI;IAAEE,IAAI,GAAAW,gBAAA,CAAJX,IAAI;EAC9B,IAAMY,SAAS,GAAGJ,IAAI,CAACK,IAAI,KAAK,OAAO;EACvC,IAAMC,EAAE,GAAGP,KAAK,CAACO,EAAE;EACnB,IAAMC,EAAE,GAAGH,SAAS,GAAG,CAAC,GAAGL,KAAK,CAACQ,EAAE;;EAEnC;EACA;EACA;EACA,IAAMC,YAAY,GAChB,CAAC3B,MAAM,CAAC2B,YAAY,IAAIR,IAAI,CAACS,SAAS,KAAK,IAAI,KAC/CX,KAAK,CAACpB,CAAC,GAAG,CAAC,IACXoB,KAAK,CAACnB,CAAC,GAAG,CAAC;EAEb,IAAID,CAAS;EACb,IAAIC,CAAS;EAEb,IAAI6B,YAAY,EAAE;IAChB;IACA;IACA,IAAME,EAAE,GAAG,CAACZ,KAAK,CAACpB,CAAC,GAAG4B,EAAE,IAAIR,KAAK,CAACpB,CAAC;IACnC,IAAMiC,EAAE,GAAG,CAACb,KAAK,CAACnB,CAAC,GAAG4B,EAAE,IAAIT,KAAK,CAACnB,CAAC;IACnC,IAAIiC,KAAK,GAAG7C,IAAI,CAAC8C,GAAG,CAACH,EAAE,GAAG,CAAC,CAAC,IAAI3C,IAAI,CAAC8C,GAAG,CAACF,EAAE,GAAG,CAAC,CAAC,GAAGD,EAAE,GAAGC,EAAE;;IAE1D;IACA;IACA;IACA,IAAI9B,MAAM,CAACR,IAAI,EAAE;MACfuC,KAAK,GAAGxC,IAAI,CAAC0B,KAAK,CAACpB,CAAC,GAAGkC,KAAK,EAAE/B,MAAM,CAACR,IAAI,CAAC,GAAGyB,KAAK,CAACpB,CAAC;IACtD;;IAEA;IACA;IACA;IACA;IACA,IAAMoC,QAAQ,GAAG/C,IAAI,CAACI,GAAG,CAACe,IAAI,GAAGY,KAAK,CAACpB,CAAC,EAAEU,IAAI,GAAGU,KAAK,CAACnB,CAAC,CAAC;IACzD,IAAMoC,QAAQ,GAAGhD,IAAI,CAACC,GAAG,CAACsB,IAAI,GAAGQ,KAAK,CAACpB,CAAC,EAAEc,IAAI,GAAGM,KAAK,CAACnB,CAAC,CAAC;IACzDiC,KAAK,GAAGjD,KAAK,CAACiD,KAAK,EAAEE,QAAQ,EAAE/C,IAAI,CAACI,GAAG,CAAC2C,QAAQ,EAAEC,QAAQ,CAAC,CAAC;IAE5DrC,CAAC,GAAGoB,KAAK,CAACpB,CAAC,GAAGkC,KAAK;IACnBjC,CAAC,GAAGmB,KAAK,CAACnB,CAAC,GAAGiC,KAAK;EACrB,CAAC,MAAM;IACLlC,CAAC,GAAGf,KAAK,CAACS,IAAI,CAAC0B,KAAK,CAACpB,CAAC,GAAG4B,EAAE,EAAEzB,MAAM,CAACR,IAAI,CAAC,EAAEa,IAAI,EAAEI,IAAI,CAAC;IACtDX,CAAC,GAAGyB,SAAS,GACTN,KAAK,CAACnB,CAAC,GACPhB,KAAK,CAACS,IAAI,CAAC0B,KAAK,CAACnB,CAAC,GAAG4B,EAAE,EAAE1B,MAAM,CAACR,IAAI,CAAC,EAAEe,IAAI,EAAEI,IAAI,CAAC;EACxD;EAEA,OAAO;IAAEd,CAAC,EAAEX,IAAI,CAACO,KAAK,CAACI,CAAC,CAAC;IAAEC,CAAC,EAAEZ,IAAI,CAACO,KAAK,CAACK,CAAC;EAAE,CAAC;AAC/C,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACO,IAAMqC,cAAc,GAAA3D,OAAA,CAAA2D,cAAA,GAAG,SAAjBA,cAAcA,CACzBvD,GAAW,EACXe,IAAqB,EACrBK,MAA+B,EAC/BJ,UAAiC,EAEN;EAAA,IAD3BuB,IAA0D,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAL,SAAA,GAAAK,SAAA,MAAG,CAAC,CAAC;EAE/D,IAAMG,SAAS,GAAGJ,IAAI,CAACK,IAAI,KAAK,OAAO;EACvC,IAAID,SAAS,KAAK3C,GAAG,KAAK,SAAS,IAAIA,GAAG,KAAK,WAAW,CAAC,EAAE,OAAO,IAAI;EAExE,IAAMwD,IAAI,GACRpC,MAAM,CAACR,IAAI,IAAIQ,MAAM,CAACR,IAAI,GAAG,CAAC,GAAGQ,MAAM,CAACR,IAAI,GAAGjB,qBAAqB;EACtE,IAAMiB,IAAI,GAAG4C,IAAI,IAAIjB,IAAI,CAACkB,QAAQ,GAAG5D,qBAAqB,GAAG,CAAC,CAAC;EAC/D,IAAMwC,KAAK,GAAGvB,SAAS,CAACC,IAAI,EAAEC,UAAU,CAAC;EACzC,IAAM0C,CAAC,GAAGvC,eAAe,CAACC,MAAM,EAAEJ,UAAU,CAAC;EAC7C,IAAM2C,KAAK,GAAG,SAARA,KAAKA,CAAIrB,KAA6B;IAAA,OAC1CF,WAAW,CAACC,KAAK,EAAEC,KAAK,EAAElB,MAAM,EAAE;MAAEwB,IAAI,EAAEL,IAAI,CAACK;IAAK,CAAC,CAAC;EAAA;;EAExD;AACF;AACA;AACA;AACA;AACA;EACE,IAAMgB,IAAI,GAAG,SAAPA,IAAIA,CAAItB,KAA6B;IAAA,OACzCF,WAAW,CAACC,KAAK,EAAEC,KAAK,EAAAuB,aAAA,CAAAA,aAAA,KAAOzC,MAAM;MAAER,IAAI,EAAE;IAAC,IAAI;MAAEgC,IAAI,EAAEL,IAAI,CAACK;IAAK,CAAC,CAAC;EAAA;EAExE,QAAQ5C,GAAG;IACT,KAAK,YAAY;MACf,OAAO2D,KAAK,CAAC;QAAEd,EAAE,EAAEjC,IAAI;QAAEkC,EAAE,EAAE;MAAE,CAAC,CAAC;IACnC,KAAK,WAAW;MACd,OAAOa,KAAK,CAAC;QAAEd,EAAE,EAAE,CAACjC,IAAI;QAAEkC,EAAE,EAAE;MAAE,CAAC,CAAC;IACpC,KAAK,WAAW;MACd,OAAOa,KAAK,CAAC;QAAEd,EAAE,EAAE,CAAC;QAAEC,EAAE,EAAElC;MAAK,CAAC,CAAC;IACnC,KAAK,SAAS;MACZ,OAAO+C,KAAK,CAAC;QAAEd,EAAE,EAAE,CAAC;QAAEC,EAAE,EAAE,CAAClC;MAAK,CAAC,CAAC;IACpC,KAAK,MAAM;MACT;MACA,OAAOgD,IAAI,CAAC;QACVf,EAAE,EAAEZ,QAAQ,CAACb,MAAM,CAACM,IAAI,EAAEV,UAAU,CAACC,CAAC,CAAC,GAAGyC,CAAC,CAACjC,IAAI,GAAGV,IAAI,CAACE,CAAC,GAAG,CAAC;QAC7D6B,EAAE,EACA,CAACH,SAAS,IAAIV,QAAQ,CAACb,MAAM,CAACQ,IAAI,EAAEZ,UAAU,CAACE,CAAC,CAAC,GAC7CwC,CAAC,CAAC/B,IAAI,GAAGZ,IAAI,CAACG,CAAC,GACf;MACR,CAAC,CAAC;IACJ,KAAK,KAAK;MACR;MACA,OAAO0C,IAAI,CAAC;QACVf,EAAE,EAAErC,MAAM,CAACsD,QAAQ,CAACJ,CAAC,CAAC7B,IAAI,CAAC,GAAG6B,CAAC,CAAC7B,IAAI,GAAGd,IAAI,CAACE,CAAC,GAAG,CAAC;QACjD6B,EAAE,EAAE,CAACH,SAAS,IAAInC,MAAM,CAACsD,QAAQ,CAACJ,CAAC,CAAC3B,IAAI,CAAC,GAAG2B,CAAC,CAAC3B,IAAI,GAAGhB,IAAI,CAACG,CAAC,GAAG;MAChE,CAAC,CAAC;IACJ;MACE,OAAO,IAAI;EACf;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACO,IAAM6C,cAAc,GAAAnE,OAAA,CAAAmE,cAAA,GAAG,SAAjBA,cAAcA,CACzBhD,IAAqB,EACrBK,MAA+B,EAC/BJ,UAAiC,EACtB;EACX,IAAAgD,iBAAA,GAAuB7C,eAAe,CAACC,MAAM,EAAEJ,UAAU,CAAC;IAAlDS,IAAI,GAAAuC,iBAAA,CAAJvC,IAAI;IAAEI,IAAI,GAAAmC,iBAAA,CAAJnC,IAAI;EAClB,IAAI,CAACrB,MAAM,CAACsD,QAAQ,CAACjC,IAAI,CAAC,IAAIA,IAAI,IAAIJ,IAAI,EAAE,OAAO,CAAC;EACpD,OAAOnB,IAAI,CAACO,KAAK,CAACX,KAAK,CAAE,CAACa,IAAI,CAACE,CAAC,GAAGQ,IAAI,KAAKI,IAAI,GAAGJ,IAAI,CAAC,GAAI,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AAC3E,CAAC","ignoreList":[]}
|