isotone 1.1.2 → 1.1.3
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/AGENTS.md +5 -1
- package/CHANGELOG.md +12 -0
- package/dist/chunk-BDTB3DFR.js +100 -0
- package/dist/chunk-BDTB3DFR.js.map +1 -0
- package/dist/{chunk-TGAU3WTF.js → chunk-BRBXIGZP.js} +56 -12
- package/dist/chunk-BRBXIGZP.js.map +1 -0
- package/dist/{chunk-FKEKBZ3E.js → chunk-K5RAC2BT.js} +94 -6
- package/dist/chunk-K5RAC2BT.js.map +1 -0
- package/dist/{chunk-X6V2AKJL.js → chunk-LXW6WFOC.js} +33 -6
- package/dist/chunk-LXW6WFOC.js.map +1 -0
- package/dist/{chunk-PUXQGUMQ.js → chunk-RKZWO37H.js} +20 -5
- package/dist/chunk-RKZWO37H.js.map +1 -0
- package/dist/{chunk-I7CZUPDO.js → chunk-YTEUMO3O.js} +2 -2
- package/dist/{chunk-I7CZUPDO.js.map → chunk-YTEUMO3O.js.map} +1 -1
- package/dist/cli.js +46 -7
- package/dist/cli.js.map +1 -1
- package/dist/core.d.ts +44 -9
- package/dist/core.js +4 -2
- package/dist/index.js +37 -29
- package/dist/index.js.map +1 -1
- package/dist/isotone.global.js +20 -20
- package/dist/serve.js +2 -2
- package/dist/server.js +3 -3
- package/dist/vite-plugin.js +29 -113
- package/dist/vite-plugin.js.map +1 -1
- package/docs/variants.md +37 -2
- package/package.json +1 -1
- package/dist/chunk-FKEKBZ3E.js.map +0 -1
- package/dist/chunk-PUXQGUMQ.js.map +0 -1
- package/dist/chunk-TGAU3WTF.js.map +0 -1
- package/dist/chunk-X6V2AKJL.js.map +0 -1
package/dist/core.d.ts
CHANGED
|
@@ -212,7 +212,7 @@ interface OverlayVariantStatus extends OverlayVariant {
|
|
|
212
212
|
missing: string[];
|
|
213
213
|
}
|
|
214
214
|
/**
|
|
215
|
-
* A knob: a range or
|
|
215
|
+
* A knob: a range, colour or select axis the host declares in `.isotone/knobs.json`
|
|
216
216
|
* next to its overlay variants. The panel renders it as a slider (or a colour
|
|
217
217
|
* pick) on the routes it names, and the value reaches the page as a CSS
|
|
218
218
|
* custom property on `<html>`, `--knob-<id>`, with the axis unit appended
|
|
@@ -220,8 +220,12 @@ interface OverlayVariantStatus extends OverlayVariant {
|
|
|
220
220
|
* committed default: `var(--knob-fade-from, 0%)`. "Save as defaults" files
|
|
221
221
|
* the moved knobs in the same `[set-defaults]` note as the variant picks, so
|
|
222
222
|
* the agent writes the numbers into the source and the knob file.
|
|
223
|
+
*
|
|
224
|
+
* A select knob's value is its option id, which CSS cannot branch on through a
|
|
225
|
+
* custom property, so it also lands as `data-knob-<id>` on `<html>`. Code that
|
|
226
|
+
* draws for itself listens for {@link KNOBS_EVENT} on the document.
|
|
223
227
|
*/
|
|
224
|
-
type KnobAxis = (RangeVariantAxis | ColorVariantAxis) & {
|
|
228
|
+
type KnobAxis = (RangeVariantAxis | ColorVariantAxis | SelectVariantAxis) & {
|
|
225
229
|
/** Route pattern(s) the knob belongs on, like a variant's `route`; absent means every route. */
|
|
226
230
|
route?: string | string[];
|
|
227
231
|
};
|
|
@@ -235,7 +239,11 @@ interface OverlayVariantsList {
|
|
|
235
239
|
}
|
|
236
240
|
/** The custom property a knob writes: `--knob-<id>`. */
|
|
237
241
|
declare function knobVar(id: string): string;
|
|
238
|
-
/**
|
|
242
|
+
/** Fired on `<html>`, bubbling, when a knob's value changes. `detail` is
|
|
243
|
+
* `{ id, value }` with the same value the custom property holds, or `null`
|
|
244
|
+
* when the knob went back to its default. */
|
|
245
|
+
declare const KNOBS_EVENT = "isotone:knob";
|
|
246
|
+
/** The property's value: a range carries its unit, a colour is its hex, a select is the option id. */
|
|
239
247
|
declare function knobCssValue(axis: KnobAxis, value: string): string;
|
|
240
248
|
/** The knobs that belong on `route`. */
|
|
241
249
|
declare function knobsFor(knobs: KnobAxis[] | undefined, route: string): KnobAxis[];
|
|
@@ -245,6 +253,10 @@ declare function applyKnobValues(knobs: KnobAxis[], values: VariantSelections, r
|
|
|
245
253
|
setProperty(name: string, value: string): void;
|
|
246
254
|
removeProperty(name: string): void;
|
|
247
255
|
};
|
|
256
|
+
setAttribute?(name: string, value: string): void;
|
|
257
|
+
removeAttribute?(name: string): void;
|
|
258
|
+
getAttribute?(name: string): string | null;
|
|
259
|
+
dispatchEvent?(event: Event): boolean;
|
|
248
260
|
}): void;
|
|
249
261
|
/** The knobs that sit off their default, with the value the panel showed. */
|
|
250
262
|
declare function knobDelta(knobs: KnobAxis[], values: VariantSelections): {
|
|
@@ -344,8 +356,25 @@ interface IterationElement {
|
|
|
344
356
|
tag: string;
|
|
345
357
|
/** Trimmed text-content snippet (may be empty for visual elements). */
|
|
346
358
|
text: string;
|
|
347
|
-
/**
|
|
359
|
+
/** CSS path to the element. A pin made in a browser matches only this element. */
|
|
348
360
|
selector: string;
|
|
361
|
+
/** Identifying attributes: role, name, aria-label, data-*, class and so on. */
|
|
362
|
+
attributes?: Record<string, string>;
|
|
363
|
+
/** React components around the element, outermost first. */
|
|
364
|
+
component?: string[];
|
|
365
|
+
/** `file:line` of the JSX, where the host's React still records it. */
|
|
366
|
+
source?: string;
|
|
367
|
+
/** Labelled or headed ancestors, outermost first. */
|
|
368
|
+
within?: string[];
|
|
369
|
+
/** The closest ancestor's text, for an element with none of its own. */
|
|
370
|
+
near?: string;
|
|
371
|
+
/** Where it sat on the page when pinned, in CSS pixels from the document's corner. */
|
|
372
|
+
rect?: {
|
|
373
|
+
x: number;
|
|
374
|
+
y: number;
|
|
375
|
+
w: number;
|
|
376
|
+
h: number;
|
|
377
|
+
};
|
|
349
378
|
}
|
|
350
379
|
/** A durable reference to a selector or one of its options, not a DOM path. */
|
|
351
380
|
interface VariantReference {
|
|
@@ -399,12 +428,18 @@ interface NodeLike {
|
|
|
399
428
|
textContent?: string | null;
|
|
400
429
|
/** One-based child position, when the adapter can provide it cheaply. */
|
|
401
430
|
indexInParent?: number;
|
|
431
|
+
/** Whether a selector finds this node and nothing else. Without one, the
|
|
432
|
+
* path stops at an id or the depth cap, unchecked. */
|
|
433
|
+
isOnlyMatch?(selector: string): boolean;
|
|
434
|
+
/** What else identifies the node, beyond its path. */
|
|
435
|
+
context?(): Partial<IterationElement>;
|
|
402
436
|
}
|
|
403
437
|
/**
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
438
|
+
* Descriptor of a picked element for locating it in code. Walks up the tree
|
|
439
|
+
* collecting `#id` (preferred) or `tag:nth-child(n)` segments. The panel finds
|
|
440
|
+
* pins again with `querySelector`, which takes the first match, so with a real
|
|
441
|
+
* DOM the walk goes on past `maxDepth` until the path matches this element
|
|
442
|
+
* alone. Kept framework-free so it is unit-testable.
|
|
408
443
|
*/
|
|
409
444
|
declare function describeIterationElement(el: NodeLike, maxDepth?: number): IterationElement;
|
|
410
445
|
declare function elementAsNode(el: Element): NodeLike;
|
|
@@ -451,4 +486,4 @@ declare function createIterationStore(cfg?: IterationStoreConfig): {
|
|
|
451
486
|
readonly hasUnsyncedNotes: boolean;
|
|
452
487
|
};
|
|
453
488
|
|
|
454
|
-
export { type ColorSwatch, type ColorVariantAxis, type IterationElement, type IterationNote, type IterationStoreConfig, KNOBS_STORAGE_KEY, type KnobAxis, type LiveVariantSelection, type NodeLike, type NoteContext, OVERLAY_DEFAULT_OPTION, OVERLAY_GROUP_ID, type OverlayGroup, type OverlayVariant, type OverlayVariantStatus, type OverlayVariantsList, type RangeVariantAxis, type RouteGateOptions, type SaveLocation, type SelectVariantAxis, VARIANTS_ENDPOINT, type VariantAction, type VariantAxis, type VariantAxisCondition, type VariantOption, type VariantReference, type VariantRemoval, type VariantSelections, type VariantsSource, applyKnobValues, axisDefault, createIterationStore, createOverlayVariantsSource, createVariantsSource, defaultSelections, describeIterationElement, elementAsNode, formatRangeValue, isAxisVisible, isDirty, isRouteVisible, isValidSelection, knobCssValue, knobDelta, knobVar, knobsFor, overlayAxes, overlayGroups, parseVariantParam, serializeVariantParam, variantAppliesTo, visibleAxes };
|
|
489
|
+
export { type ColorSwatch, type ColorVariantAxis, type IterationElement, type IterationNote, type IterationStoreConfig, KNOBS_EVENT, KNOBS_STORAGE_KEY, type KnobAxis, type LiveVariantSelection, type NodeLike, type NoteContext, OVERLAY_DEFAULT_OPTION, OVERLAY_GROUP_ID, type OverlayGroup, type OverlayVariant, type OverlayVariantStatus, type OverlayVariantsList, type RangeVariantAxis, type RouteGateOptions, type SaveLocation, type SelectVariantAxis, VARIANTS_ENDPOINT, type VariantAction, type VariantAxis, type VariantAxisCondition, type VariantOption, type VariantReference, type VariantRemoval, type VariantSelections, type VariantsSource, applyKnobValues, axisDefault, createIterationStore, createOverlayVariantsSource, createVariantsSource, defaultSelections, describeIterationElement, elementAsNode, formatRangeValue, isAxisVisible, isDirty, isRouteVisible, isValidSelection, knobCssValue, knobDelta, knobVar, knobsFor, overlayAxes, overlayGroups, parseVariantParam, serializeVariantParam, variantAppliesTo, visibleAxes };
|
package/dist/core.js
CHANGED
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
describeIterationElement,
|
|
4
4
|
elementAsNode,
|
|
5
5
|
isRouteVisible
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-K5RAC2BT.js";
|
|
7
7
|
import {
|
|
8
|
+
KNOBS_EVENT,
|
|
8
9
|
KNOBS_STORAGE_KEY,
|
|
9
10
|
OVERLAY_DEFAULT_OPTION,
|
|
10
11
|
OVERLAY_GROUP_ID,
|
|
@@ -28,9 +29,10 @@ import {
|
|
|
28
29
|
serializeVariantParam,
|
|
29
30
|
variantAppliesTo,
|
|
30
31
|
visibleAxes
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-RKZWO37H.js";
|
|
32
33
|
import "./chunk-A4DX2V4C.js";
|
|
33
34
|
export {
|
|
35
|
+
KNOBS_EVENT,
|
|
34
36
|
KNOBS_STORAGE_KEY,
|
|
35
37
|
OVERLAY_DEFAULT_OPTION,
|
|
36
38
|
OVERLAY_GROUP_ID,
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
describeIterationElement,
|
|
5
5
|
elementAsNode,
|
|
6
6
|
isRouteVisible
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-K5RAC2BT.js";
|
|
8
8
|
import {
|
|
9
9
|
FEEDBACK_STORAGE_KEY,
|
|
10
10
|
KNOBS_STORAGE_KEY,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
serializeVariantParam,
|
|
33
33
|
visibleAxes,
|
|
34
34
|
writeBrowserStorage
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-RKZWO37H.js";
|
|
36
36
|
import {
|
|
37
37
|
MAX_FEEDBACK_LENGTH
|
|
38
38
|
} from "./chunk-A4DX2V4C.js";
|
|
@@ -1887,6 +1887,16 @@ function IterationPanel({
|
|
|
1887
1887
|
);
|
|
1888
1888
|
const [hoverRect, setHoverRect] = useState3(null);
|
|
1889
1889
|
const [rects, setRects] = useState3([]);
|
|
1890
|
+
const pinnedElements = useRef4(/* @__PURE__ */ new Map());
|
|
1891
|
+
const locate = useCallback((selector) => {
|
|
1892
|
+
const pinned = pinnedElements.current.get(selector);
|
|
1893
|
+
if (pinned?.isConnected) return pinned;
|
|
1894
|
+
try {
|
|
1895
|
+
return document.querySelector(selector);
|
|
1896
|
+
} catch {
|
|
1897
|
+
return null;
|
|
1898
|
+
}
|
|
1899
|
+
}, []);
|
|
1890
1900
|
const [text, setText] = useState3("");
|
|
1891
1901
|
const [notes, setNotes] = useState3([]);
|
|
1892
1902
|
const [scope, setScope] = useState3(null);
|
|
@@ -2358,6 +2368,7 @@ function IterationPanel({
|
|
|
2358
2368
|
};
|
|
2359
2369
|
const toggleTarget = (el) => {
|
|
2360
2370
|
const target = describeIterationElement(elementAsNode(el));
|
|
2371
|
+
pinnedElements.current.set(target.selector, el);
|
|
2361
2372
|
const added = !targetsRef.current.some((t) => t.selector === target.selector);
|
|
2362
2373
|
setTargets(
|
|
2363
2374
|
(prev) => prev.some((t) => t.selector === target.selector) ? prev.filter((t) => t.selector !== target.selector) : prev.length < 50 ? [...prev, target] : prev
|
|
@@ -2453,14 +2464,11 @@ function IterationPanel({
|
|
|
2453
2464
|
const place = () => {
|
|
2454
2465
|
frame = void 0;
|
|
2455
2466
|
let { x, y } = anchor;
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
y = r.top + anchor.dy;
|
|
2462
|
-
}
|
|
2463
|
-
} catch {
|
|
2467
|
+
const el = locate(anchor.selector);
|
|
2468
|
+
if (el) {
|
|
2469
|
+
const r = el.getBoundingClientRect();
|
|
2470
|
+
x = r.left + anchor.dx;
|
|
2471
|
+
y = r.top + anchor.dy;
|
|
2464
2472
|
}
|
|
2465
2473
|
const vw = document.documentElement.clientWidth || innerWidth;
|
|
2466
2474
|
const vh = innerHeight;
|
|
@@ -2516,7 +2524,7 @@ function IterationPanel({
|
|
|
2516
2524
|
window.removeEventListener("scroll", schedule, true);
|
|
2517
2525
|
window.removeEventListener("resize", schedule);
|
|
2518
2526
|
};
|
|
2519
|
-
}, [anchor]);
|
|
2527
|
+
}, [anchor, locate]);
|
|
2520
2528
|
useLayoutEffect4(() => {
|
|
2521
2529
|
const last = floatNode.current;
|
|
2522
2530
|
const root = rootRef.current;
|
|
@@ -2543,6 +2551,10 @@ function IterationPanel({
|
|
|
2543
2551
|
ghost.remove();
|
|
2544
2552
|
};
|
|
2545
2553
|
}, [floating]);
|
|
2554
|
+
useEffect3(() => {
|
|
2555
|
+
const kept = new Set(targets.map((t) => t.selector));
|
|
2556
|
+
for (const selector of pinnedElements.current.keys()) if (!kept.has(selector)) pinnedElements.current.delete(selector);
|
|
2557
|
+
}, [targets]);
|
|
2546
2558
|
useEffect3(() => {
|
|
2547
2559
|
if (!picking && !floating) {
|
|
2548
2560
|
setRects([]);
|
|
@@ -2553,22 +2565,18 @@ function IterationPanel({
|
|
|
2553
2565
|
frame = void 0;
|
|
2554
2566
|
setRects(
|
|
2555
2567
|
targets.flatMap((t) => {
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
];
|
|
2569
|
-
} catch {
|
|
2570
|
-
return [];
|
|
2571
|
-
}
|
|
2568
|
+
const el = locate(t.selector);
|
|
2569
|
+
if (!el) return [];
|
|
2570
|
+
const r = el.getBoundingClientRect();
|
|
2571
|
+
return [
|
|
2572
|
+
{
|
|
2573
|
+
top: r.top,
|
|
2574
|
+
left: r.left,
|
|
2575
|
+
width: r.width,
|
|
2576
|
+
height: r.height,
|
|
2577
|
+
selector: t.selector
|
|
2578
|
+
}
|
|
2579
|
+
];
|
|
2572
2580
|
})
|
|
2573
2581
|
);
|
|
2574
2582
|
};
|
|
@@ -2583,7 +2591,7 @@ function IterationPanel({
|
|
|
2583
2591
|
window.removeEventListener("scroll", schedule, true);
|
|
2584
2592
|
window.removeEventListener("resize", schedule);
|
|
2585
2593
|
};
|
|
2586
|
-
}, [targets, picking, floating]);
|
|
2594
|
+
}, [targets, picking, floating, locate]);
|
|
2587
2595
|
const variantsPanel = variants && /* @__PURE__ */ jsxs4(
|
|
2588
2596
|
"section",
|
|
2589
2597
|
{
|
|
@@ -3154,7 +3162,7 @@ function overlaySourceWithSave(getRoute, endpoint, key) {
|
|
|
3154
3162
|
if (!endpoint) return source;
|
|
3155
3163
|
const notes = createIterationStore({ endpoint, key });
|
|
3156
3164
|
source.saveDefaults = async (selections) => {
|
|
3157
|
-
const picked = source.getAxes().filter((axis) => axis.kind === void 0 || axis.kind === "select").flatMap((axis) => {
|
|
3165
|
+
const picked = source.getAxes().filter((axis) => (axis.kind === void 0 || axis.kind === "select") && !source.knobs.axes.includes(axis)).flatMap((axis) => {
|
|
3158
3166
|
const id = selections[axis.id];
|
|
3159
3167
|
if (!id || id === OVERLAY_DEFAULT_OPTION) return [];
|
|
3160
3168
|
const variant = source.list?.variants.find((v) => v.id === id);
|