arcy.js 0.1.4 → 0.1.6
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/{arcy.chat.f698fce59921.js → arcy.chat.27fabef680f1.js} +1 -1
- package/dist/arcy.flow.46ba8a96f99e.js +3 -0
- package/dist/{arcy.legacy.061d3b544569.js → arcy.legacy.98a48482777b.js} +2 -2
- package/dist/arcy.loader.js +1 -1
- package/dist/{arcy.modern.d30bb13c138a.js → arcy.modern.2c3fe0b458df.js} +2 -2
- package/dist/arcy.picker.777b2d4d1127.js +95 -0
- package/dist/{chat-VOYR3S25.js → chat-NCTVDXR5.js} +0 -3
- package/dist/{chunk-GDGE3HLE.js → chunk-7S5DA67F.js} +2 -2
- package/dist/{chunk-NY3NXM2V.js → chunk-AW7DHYSA.js} +1 -1
- package/dist/{chunk-NIHUDSWK.js → chunk-QDCO2MRA.js} +1 -1
- package/dist/design-mode.cjs +1 -1
- package/dist/design-mode.d.ts +9 -1
- package/dist/design-mode.js +2 -2
- package/dist/{flow-M7W3H3C5.js → flow-FGTIZOXU.js} +62 -17
- package/dist/index.cjs +490 -95
- package/dist/index.d.ts +21 -6
- package/dist/index.js +16 -12
- package/dist/{picker-GPZ2GHB4.js → picker-6REZLJW3.js} +417 -69
- package/package.json +1 -1
- package/dist/arcy.flow.fef131718e42.js +0 -3
- package/dist/arcy.picker.b7e531503cf2.js +0 -59
package/dist/index.cjs
CHANGED
|
@@ -361,7 +361,7 @@ var init_message = __esm({
|
|
|
361
361
|
DESIGN_MODE_PICK = "arcy:design-mode:pick";
|
|
362
362
|
DESIGN_MODE_EXIT = "arcy:design-mode:exit";
|
|
363
363
|
DESIGN_MODE_SCREENSHOT = "arcy:design-mode:screenshot";
|
|
364
|
-
SCREENSHOT_RENDER_BUDGET_MS =
|
|
364
|
+
SCREENSHOT_RENDER_BUDGET_MS = 5e3;
|
|
365
365
|
}
|
|
366
366
|
});
|
|
367
367
|
|
|
@@ -3992,9 +3992,6 @@ function mount(context) {
|
|
|
3992
3992
|
flowOffers: result.flowsOffered
|
|
3993
3993
|
});
|
|
3994
3994
|
context.touchConversation?.();
|
|
3995
|
-
if (result.isFallback) {
|
|
3996
|
-
context.track?.("fallback_triggered", {}, { question: text });
|
|
3997
|
-
}
|
|
3998
3995
|
for (const offer of result.flowsOffered) {
|
|
3999
3996
|
context.track?.(
|
|
4000
3997
|
"flow_suggested",
|
|
@@ -5639,6 +5636,25 @@ function evaluateCurrentPage(node, href) {
|
|
|
5639
5636
|
if (node.matches.length === 0) return true;
|
|
5640
5637
|
return node.matches.some((pattern) => globMatches(pattern, href));
|
|
5641
5638
|
}
|
|
5639
|
+
function parseInstant(value) {
|
|
5640
|
+
if (!DATE_SHAPED.test(value)) return null;
|
|
5641
|
+
const ms = new Date(value).getTime();
|
|
5642
|
+
return Number.isFinite(ms) ? ms : null;
|
|
5643
|
+
}
|
|
5644
|
+
function compareOrdered(live, expected) {
|
|
5645
|
+
if (live.trim() === "" || expected.trim() === "") return null;
|
|
5646
|
+
const liveNumber = Number(live);
|
|
5647
|
+
const expectedNumber = Number(expected);
|
|
5648
|
+
if (Number.isFinite(liveNumber) && Number.isFinite(expectedNumber)) {
|
|
5649
|
+
return liveNumber - expectedNumber;
|
|
5650
|
+
}
|
|
5651
|
+
const liveInstant = parseInstant(live);
|
|
5652
|
+
const expectedInstant = parseInstant(expected);
|
|
5653
|
+
if (liveInstant !== null && expectedInstant !== null) {
|
|
5654
|
+
return liveInstant - expectedInstant;
|
|
5655
|
+
}
|
|
5656
|
+
return null;
|
|
5657
|
+
}
|
|
5642
5658
|
function compareText(operator, live, expected) {
|
|
5643
5659
|
if (live === void 0) return false;
|
|
5644
5660
|
switch (operator) {
|
|
@@ -5660,16 +5676,14 @@ function compareText(operator, live, expected) {
|
|
|
5660
5676
|
return live === "";
|
|
5661
5677
|
case "is_not_empty":
|
|
5662
5678
|
return live !== "";
|
|
5663
|
-
//
|
|
5664
|
-
// condition cannot hold (never throw, never
|
|
5679
|
+
// Ordered compares read both sides as numbers, then as instants; either
|
|
5680
|
+
// side unreadable means the condition cannot hold (never throw, never
|
|
5681
|
+
// coerce NaN into an answer).
|
|
5665
5682
|
case "greater_than":
|
|
5666
5683
|
case "less_than": {
|
|
5667
|
-
const
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
return false;
|
|
5671
|
-
}
|
|
5672
|
-
return operator === "greater_than" ? liveNumber > expectedNumber : liveNumber < expectedNumber;
|
|
5684
|
+
const ordered = compareOrdered(live, expected);
|
|
5685
|
+
if (ordered === null) return false;
|
|
5686
|
+
return operator === "greater_than" ? ordered > 0 : ordered < 0;
|
|
5673
5687
|
}
|
|
5674
5688
|
// The same `*` glob `current_page` uses, applied to a field value.
|
|
5675
5689
|
case "matches_pattern":
|
|
@@ -5738,15 +5752,22 @@ function evaluateElement(node, ctx) {
|
|
|
5738
5752
|
return false;
|
|
5739
5753
|
}
|
|
5740
5754
|
}
|
|
5755
|
+
function isEmptyValue(live) {
|
|
5756
|
+
if (live === void 0 || live === null || live === "") return true;
|
|
5757
|
+
if (Array.isArray(live)) return live.length === 0;
|
|
5758
|
+
if (typeof live === "object") return Object.keys(live).length === 0;
|
|
5759
|
+
return false;
|
|
5760
|
+
}
|
|
5741
5761
|
function evaluateAttribute(node, ctx) {
|
|
5742
5762
|
const live = ctx.getTrait?.(node.codeName);
|
|
5743
5763
|
switch (node.operator) {
|
|
5744
5764
|
case "has_any_value":
|
|
5745
|
-
return live
|
|
5765
|
+
return !isEmptyValue(live);
|
|
5746
5766
|
case "is_empty":
|
|
5747
|
-
return live
|
|
5767
|
+
return isEmptyValue(live);
|
|
5748
5768
|
}
|
|
5749
5769
|
if (live === void 0) return false;
|
|
5770
|
+
if (typeof live === "object") return false;
|
|
5750
5771
|
const liveText = String(live);
|
|
5751
5772
|
const expected = node.value === void 0 ? "" : String(node.value);
|
|
5752
5773
|
return compareText(node.operator, liveText, expected);
|
|
@@ -5799,7 +5820,7 @@ function needsIdleCheck(node) {
|
|
|
5799
5820
|
if (node.type === "group") return node.children.some(needsIdleCheck);
|
|
5800
5821
|
return false;
|
|
5801
5822
|
}
|
|
5802
|
-
var MAX_CONDITION_DEPTH, CONDITION_TYPES;
|
|
5823
|
+
var MAX_CONDITION_DEPTH, CONDITION_TYPES, DATE_SHAPED;
|
|
5803
5824
|
var init_condition = __esm({
|
|
5804
5825
|
"src/flow/condition.ts"() {
|
|
5805
5826
|
init_matcher();
|
|
@@ -5816,6 +5837,7 @@ var init_condition = __esm({
|
|
|
5816
5837
|
"always_true",
|
|
5817
5838
|
"group"
|
|
5818
5839
|
];
|
|
5840
|
+
DATE_SHAPED = /^\d{4}-\d{2}-\d{2}/;
|
|
5819
5841
|
}
|
|
5820
5842
|
});
|
|
5821
5843
|
|
|
@@ -6027,6 +6049,21 @@ var init_runtime = __esm({
|
|
|
6027
6049
|
/** ADR 0166: true while a fill question is awaiting the end user's
|
|
6028
6050
|
* answer. Suspends trigger evaluation for the duration. */
|
|
6029
6051
|
this.inputPending = false;
|
|
6052
|
+
/**
|
|
6053
|
+
* True from the moment a step is entered until its own action has
|
|
6054
|
+
* settled. Suspends trigger evaluation for exactly that window, the same
|
|
6055
|
+
* posture `inputPending` takes around a fill question.
|
|
6056
|
+
*
|
|
6057
|
+
* **This is what makes a step's type mean anything.** The builder's
|
|
6058
|
+
* default condition for a new trigger is `always_true` with no wait
|
|
6059
|
+
* (`flow-draft.ts`'s `newTrigger`), so the ordinary way to say "then go to
|
|
6060
|
+
* step 2" is a trigger that is true the instant the step mounts. Without
|
|
6061
|
+
* this flag `startWatch`'s initial pass fired that trigger before the step
|
|
6062
|
+
* had clicked, filled or navigated anything, and the action never ran at
|
|
6063
|
+
* all: a two-step flow counted to step 2 and quietly ended, having done
|
|
6064
|
+
* nothing. A step acts first; its triggers are how it is left.
|
|
6065
|
+
*/
|
|
6066
|
+
this.actionPending = false;
|
|
6030
6067
|
/** Extra capture-phase listeners `startWatch` installs alongside the
|
|
6031
6068
|
* click listener (D1297): typing, focus moves and checkbox flips change
|
|
6032
6069
|
* nothing a MutationObserver can see, yet `text_input`, `is_focused`
|
|
@@ -6163,6 +6200,7 @@ var init_runtime = __esm({
|
|
|
6163
6200
|
}
|
|
6164
6201
|
this.activityListeners = [];
|
|
6165
6202
|
this.inputPending = false;
|
|
6203
|
+
this.actionPending = false;
|
|
6166
6204
|
this.trueSince.clear();
|
|
6167
6205
|
this.clicked.clear();
|
|
6168
6206
|
this.initialValues.clear();
|
|
@@ -6252,7 +6290,7 @@ var init_runtime = __esm({
|
|
|
6252
6290
|
}
|
|
6253
6291
|
checkTriggers(step, ctx) {
|
|
6254
6292
|
if (this.stopped) return;
|
|
6255
|
-
|
|
6293
|
+
const mayFire = !this.inputPending && !this.actionPending;
|
|
6256
6294
|
const now = this.now();
|
|
6257
6295
|
for (const trigger of [...step.triggers].sort((a, b) => a.position - b.position)) {
|
|
6258
6296
|
const parsed = this.parsedTrigger(trigger);
|
|
@@ -6266,7 +6304,7 @@ var init_runtime = __esm({
|
|
|
6266
6304
|
const since = this.trueSince.get(key) ?? now;
|
|
6267
6305
|
if (!this.trueSince.has(key)) this.trueSince.set(key, since);
|
|
6268
6306
|
const waitMs = (trigger.waitSeconds ?? 0) * 1e3;
|
|
6269
|
-
if (now - since >= waitMs) {
|
|
6307
|
+
if (now - since >= waitMs && mayFire) {
|
|
6270
6308
|
this.fireTrigger(trigger);
|
|
6271
6309
|
return;
|
|
6272
6310
|
}
|
|
@@ -6352,8 +6390,7 @@ var init_runtime = __esm({
|
|
|
6352
6390
|
}
|
|
6353
6391
|
this.checkTriggers(step, this.conditionContext());
|
|
6354
6392
|
}
|
|
6355
|
-
async runExecutor(step) {
|
|
6356
|
-
const startIndex = this.stepIndex;
|
|
6393
|
+
async runExecutor(step, startIndex) {
|
|
6357
6394
|
try {
|
|
6358
6395
|
const outcome = await this.executor(step, {
|
|
6359
6396
|
doc: this.doc,
|
|
@@ -6365,6 +6402,7 @@ var init_runtime = __esm({
|
|
|
6365
6402
|
}
|
|
6366
6403
|
});
|
|
6367
6404
|
if (this.stopped || this.stepIndex !== startIndex) return;
|
|
6405
|
+
this.actionPending = false;
|
|
6368
6406
|
if (outcome.status === "advance") {
|
|
6369
6407
|
this.emit("flow_step_completed");
|
|
6370
6408
|
if (step.isCompletion) {
|
|
@@ -6409,11 +6447,14 @@ var init_runtime = __esm({
|
|
|
6409
6447
|
);
|
|
6410
6448
|
return;
|
|
6411
6449
|
}
|
|
6450
|
+
this.scheduleCheck(step);
|
|
6412
6451
|
} catch {
|
|
6452
|
+
this.actionPending = false;
|
|
6413
6453
|
}
|
|
6414
6454
|
}
|
|
6415
6455
|
enterStep() {
|
|
6416
6456
|
const step = this.currentStep();
|
|
6457
|
+
const stepIndex = this.stepIndex;
|
|
6417
6458
|
if (!step || this.stopped) {
|
|
6418
6459
|
this.finish(step ? "completed" : "error", step ? void 0 : { reason: "missing_step" });
|
|
6419
6460
|
return;
|
|
@@ -6428,8 +6469,9 @@ var init_runtime = __esm({
|
|
|
6428
6469
|
});
|
|
6429
6470
|
const begin = () => {
|
|
6430
6471
|
if (this.stopped) return;
|
|
6472
|
+
this.actionPending = true;
|
|
6431
6473
|
this.startWatch(step);
|
|
6432
|
-
void this.runExecutor(step);
|
|
6474
|
+
void this.runExecutor(step, stepIndex);
|
|
6433
6475
|
};
|
|
6434
6476
|
this.waitForPageReady(begin);
|
|
6435
6477
|
}
|
|
@@ -8630,6 +8672,208 @@ function computeCropRect(target, viewportWidth, viewportHeight) {
|
|
|
8630
8672
|
if (bottom - top > height) top += (bottom - top - height) / 2;
|
|
8631
8673
|
return { left, top, width: Math.max(0, width), height: Math.max(0, height) };
|
|
8632
8674
|
}
|
|
8675
|
+
function effectiveOpacity(el, view) {
|
|
8676
|
+
let opacity = 1;
|
|
8677
|
+
let current = el;
|
|
8678
|
+
let depth = 0;
|
|
8679
|
+
while (current !== null && depth < 64) {
|
|
8680
|
+
try {
|
|
8681
|
+
const value = Number.parseFloat(view.getComputedStyle(current).opacity);
|
|
8682
|
+
if (!Number.isNaN(value)) opacity *= value;
|
|
8683
|
+
} catch {
|
|
8684
|
+
break;
|
|
8685
|
+
}
|
|
8686
|
+
if (opacity <= 1e-3) return 0;
|
|
8687
|
+
current = parentOrHost(current);
|
|
8688
|
+
depth++;
|
|
8689
|
+
}
|
|
8690
|
+
return opacity;
|
|
8691
|
+
}
|
|
8692
|
+
function waitUntilSettled(el, view) {
|
|
8693
|
+
return new Promise((resolve) => {
|
|
8694
|
+
const raf = view.requestAnimationFrame;
|
|
8695
|
+
if (typeof raf !== "function") {
|
|
8696
|
+
resolve();
|
|
8697
|
+
return;
|
|
8698
|
+
}
|
|
8699
|
+
const start = Date.now();
|
|
8700
|
+
let previous = null;
|
|
8701
|
+
let stable = 0;
|
|
8702
|
+
const check = () => {
|
|
8703
|
+
try {
|
|
8704
|
+
if (Date.now() - start >= SETTLE_MAX_MS) {
|
|
8705
|
+
resolve();
|
|
8706
|
+
return;
|
|
8707
|
+
}
|
|
8708
|
+
const rect = el.getBoundingClientRect();
|
|
8709
|
+
const now = `${Math.round(rect.left)},${Math.round(rect.top)},${Math.round(rect.width)},${Math.round(rect.height)}`;
|
|
8710
|
+
const opaque = effectiveOpacity(el, view) >= 0.99;
|
|
8711
|
+
stable = opaque && now === previous ? stable + 1 : 0;
|
|
8712
|
+
previous = now;
|
|
8713
|
+
if (stable >= SETTLE_STABLE_FRAMES) {
|
|
8714
|
+
resolve();
|
|
8715
|
+
return;
|
|
8716
|
+
}
|
|
8717
|
+
raf.call(view, check);
|
|
8718
|
+
} catch {
|
|
8719
|
+
resolve();
|
|
8720
|
+
}
|
|
8721
|
+
};
|
|
8722
|
+
raf.call(view, check);
|
|
8723
|
+
});
|
|
8724
|
+
}
|
|
8725
|
+
function findRenderRoot(el, crop, root, view) {
|
|
8726
|
+
let covering = null;
|
|
8727
|
+
let cheapest = null;
|
|
8728
|
+
let current = el;
|
|
8729
|
+
let depth = 0;
|
|
8730
|
+
while (current !== null && current !== root && depth < 64) {
|
|
8731
|
+
if (isTransformed(current, view)) {
|
|
8732
|
+
covering = null;
|
|
8733
|
+
cheapest = null;
|
|
8734
|
+
} else {
|
|
8735
|
+
const rect = current.getBoundingClientRect();
|
|
8736
|
+
if (covering === null && covers(rect, crop)) covering = current;
|
|
8737
|
+
if (cheapest === null && keptRatio(rect, crop) >= MIN_CROP_KEPT) {
|
|
8738
|
+
cheapest = current;
|
|
8739
|
+
}
|
|
8740
|
+
}
|
|
8741
|
+
current = parentOrHost(current);
|
|
8742
|
+
depth++;
|
|
8743
|
+
}
|
|
8744
|
+
if (covering !== null && isAffordable(covering, view)) return covering;
|
|
8745
|
+
return cheapest ?? covering ?? root;
|
|
8746
|
+
}
|
|
8747
|
+
function isAffordable(el, view) {
|
|
8748
|
+
if (countElements(el) > NODE_BUDGET) return false;
|
|
8749
|
+
const rect = el.getBoundingClientRect();
|
|
8750
|
+
const viewport = Math.max(1, view.innerWidth * view.innerHeight);
|
|
8751
|
+
return rect.width * rect.height / viewport <= AREA_BUDGET_SCREENS;
|
|
8752
|
+
}
|
|
8753
|
+
function keptRatio(bounds, crop) {
|
|
8754
|
+
const whole = crop.width * crop.height;
|
|
8755
|
+
if (whole <= 0) return 0;
|
|
8756
|
+
const kept = clipCrop(crop, {
|
|
8757
|
+
left: bounds.left,
|
|
8758
|
+
top: bounds.top,
|
|
8759
|
+
width: bounds.width,
|
|
8760
|
+
height: bounds.height
|
|
8761
|
+
});
|
|
8762
|
+
return kept.width * kept.height / whole;
|
|
8763
|
+
}
|
|
8764
|
+
function countElements(el) {
|
|
8765
|
+
try {
|
|
8766
|
+
return el.getElementsByTagName("*").length;
|
|
8767
|
+
} catch {
|
|
8768
|
+
return Number.MAX_SAFE_INTEGER;
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
function clipCrop(crop, bounds) {
|
|
8772
|
+
const left = Math.max(crop.left, bounds.left);
|
|
8773
|
+
const top = Math.max(crop.top, bounds.top);
|
|
8774
|
+
const right = Math.min(crop.left + crop.width, bounds.left + bounds.width);
|
|
8775
|
+
const bottom = Math.min(crop.top + crop.height, bounds.top + bounds.height);
|
|
8776
|
+
return {
|
|
8777
|
+
left,
|
|
8778
|
+
top,
|
|
8779
|
+
width: Math.max(0, right - left),
|
|
8780
|
+
height: Math.max(0, bottom - top)
|
|
8781
|
+
};
|
|
8782
|
+
}
|
|
8783
|
+
function isTransformed(el, view) {
|
|
8784
|
+
try {
|
|
8785
|
+
const style2 = view.getComputedStyle(el);
|
|
8786
|
+
return style2.transform !== "" && style2.transform !== "none" || style2.perspective !== "" && style2.perspective !== "none" || style2.translate !== "" && style2.translate !== "none" || style2.rotate !== "" && style2.rotate !== "none" || style2.scale !== "" && style2.scale !== "none";
|
|
8787
|
+
} catch {
|
|
8788
|
+
return false;
|
|
8789
|
+
}
|
|
8790
|
+
}
|
|
8791
|
+
function covers(rect, crop) {
|
|
8792
|
+
return rect.left <= crop.left + 0.5 && rect.top <= crop.top + 0.5 && rect.right >= crop.left + crop.width - 0.5 && rect.bottom >= crop.top + crop.height - 0.5;
|
|
8793
|
+
}
|
|
8794
|
+
function backgroundUnder(root, crop, doc, view) {
|
|
8795
|
+
const points = [
|
|
8796
|
+
[crop.left + crop.width / 2, crop.top + crop.height / 2],
|
|
8797
|
+
[crop.left + 1, crop.top + 1],
|
|
8798
|
+
[crop.left + crop.width - 1, crop.top + crop.height - 1]
|
|
8799
|
+
];
|
|
8800
|
+
for (const [x, y] of points) {
|
|
8801
|
+
let stack = [];
|
|
8802
|
+
try {
|
|
8803
|
+
stack = doc.elementsFromPoint(x, y) ?? [];
|
|
8804
|
+
} catch {
|
|
8805
|
+
break;
|
|
8806
|
+
}
|
|
8807
|
+
for (const candidate of stack) {
|
|
8808
|
+
if (candidate === root || root.contains(candidate)) continue;
|
|
8809
|
+
if (candidate.hasAttribute(HOST_ATTRIBUTE)) continue;
|
|
8810
|
+
const color = opaqueBackground(candidate, view);
|
|
8811
|
+
if (color) return color;
|
|
8812
|
+
}
|
|
8813
|
+
}
|
|
8814
|
+
let current = root;
|
|
8815
|
+
let depth = 0;
|
|
8816
|
+
while (current !== null && depth < 64) {
|
|
8817
|
+
const color = opaqueBackground(current, view);
|
|
8818
|
+
if (color) return color;
|
|
8819
|
+
current = parentOrHost(current);
|
|
8820
|
+
depth++;
|
|
8821
|
+
}
|
|
8822
|
+
return "#ffffff";
|
|
8823
|
+
}
|
|
8824
|
+
function opaqueBackground(el, view) {
|
|
8825
|
+
try {
|
|
8826
|
+
const color = view.getComputedStyle(el).backgroundColor;
|
|
8827
|
+
if (!color || color === "transparent") return null;
|
|
8828
|
+
if (color.replace(/\s/g, "").startsWith("rgba(0,0,0,0)")) return null;
|
|
8829
|
+
return color;
|
|
8830
|
+
} catch {
|
|
8831
|
+
return null;
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
function renderRootStyle(root, rootRect, doc, view, shiftX, shiftY) {
|
|
8835
|
+
const placement = {
|
|
8836
|
+
transform: `translate(${shiftX}px, ${shiftY}px)`,
|
|
8837
|
+
transformOrigin: "top left",
|
|
8838
|
+
margin: "0"
|
|
8839
|
+
};
|
|
8840
|
+
if (root === doc.documentElement) {
|
|
8841
|
+
return {
|
|
8842
|
+
...placement,
|
|
8843
|
+
width: `${view.innerWidth}px`,
|
|
8844
|
+
minHeight: `${view.innerHeight}px`,
|
|
8845
|
+
overflow: "visible"
|
|
8846
|
+
};
|
|
8847
|
+
}
|
|
8848
|
+
return {
|
|
8849
|
+
...placement,
|
|
8850
|
+
position: "static",
|
|
8851
|
+
inset: "auto",
|
|
8852
|
+
float: "none",
|
|
8853
|
+
// The size has to be stated, and this is the line the whole subtree render
|
|
8854
|
+
// stands on. The clone is laid out inside a `foreignObject` the size of
|
|
8855
|
+
// the CROP, and a block element with no width of its own fills its
|
|
8856
|
+
// parent: a 1440px section became 163px wide and the page reflowed into a
|
|
8857
|
+
// column, which is why the hero came back as an empty panel rather than a
|
|
8858
|
+
// misplaced one. `documentElement` was pinned the same way from the start,
|
|
8859
|
+
// which is why nobody met this until the root became something else.
|
|
8860
|
+
// Border-box, because a measured rect is a border box.
|
|
8861
|
+
boxSizing: "border-box",
|
|
8862
|
+
width: `${rootRect.width}px`,
|
|
8863
|
+
minHeight: `${rootRect.height}px`
|
|
8864
|
+
};
|
|
8865
|
+
}
|
|
8866
|
+
function withDeadline(work, ms, view) {
|
|
8867
|
+
return Promise.race([
|
|
8868
|
+
work,
|
|
8869
|
+
new Promise((resolve) => {
|
|
8870
|
+
try {
|
|
8871
|
+
view.setTimeout(() => resolve(null), ms);
|
|
8872
|
+
} catch {
|
|
8873
|
+
}
|
|
8874
|
+
})
|
|
8875
|
+
]);
|
|
8876
|
+
}
|
|
8633
8877
|
function isTextualField(el) {
|
|
8634
8878
|
if (el instanceof HTMLTextAreaElement) return true;
|
|
8635
8879
|
if (!(el instanceof HTMLInputElement)) return false;
|
|
@@ -8639,6 +8883,56 @@ function isTextualField(el) {
|
|
|
8639
8883
|
function isCapturable(node) {
|
|
8640
8884
|
return !(node instanceof Element && node.hasAttribute(HOST_ATTRIBUTE));
|
|
8641
8885
|
}
|
|
8886
|
+
function repairAutoMargins(live, clone, view) {
|
|
8887
|
+
let repaired = 0;
|
|
8888
|
+
const walk = (liveNode, cloneNode2, depth) => {
|
|
8889
|
+
if (depth > 64 || repaired > 2e3) return;
|
|
8890
|
+
const liveKids = liveNode.children;
|
|
8891
|
+
const cloneKids = cloneNode2.children;
|
|
8892
|
+
let l = 0;
|
|
8893
|
+
let c = 0;
|
|
8894
|
+
while (l < liveKids.length && c < cloneKids.length) {
|
|
8895
|
+
const liveKid = liveKids[l];
|
|
8896
|
+
const cloneKid = cloneKids[c];
|
|
8897
|
+
if (liveKid.tagName !== cloneKid.tagName) {
|
|
8898
|
+
l++;
|
|
8899
|
+
continue;
|
|
8900
|
+
}
|
|
8901
|
+
if (applyUsedMargins(liveNode, liveKid, cloneKid, view)) repaired++;
|
|
8902
|
+
walk(liveKid, cloneKid, depth + 1);
|
|
8903
|
+
l++;
|
|
8904
|
+
c++;
|
|
8905
|
+
}
|
|
8906
|
+
};
|
|
8907
|
+
try {
|
|
8908
|
+
walk(live, clone, 0);
|
|
8909
|
+
} catch {
|
|
8910
|
+
}
|
|
8911
|
+
}
|
|
8912
|
+
function applyUsedMargins(liveParent, live, clone, view) {
|
|
8913
|
+
try {
|
|
8914
|
+
const style2 = view.getComputedStyle(live);
|
|
8915
|
+
if (style2.marginLeft !== "0px" || style2.marginRight !== "0px") return false;
|
|
8916
|
+
if (style2.position !== "static" && style2.position !== "relative") return false;
|
|
8917
|
+
if (style2.float !== "none") return false;
|
|
8918
|
+
const parentStyle = view.getComputedStyle(liveParent);
|
|
8919
|
+
if (!BLOCK_DISPLAYS.has(parentStyle.display)) return false;
|
|
8920
|
+
const rect = live.getBoundingClientRect();
|
|
8921
|
+
const parentRect = liveParent.getBoundingClientRect();
|
|
8922
|
+
const contentLeft = parentRect.left + parseFloat(parentStyle.borderLeftWidth || "0") + parseFloat(parentStyle.paddingLeft || "0");
|
|
8923
|
+
const contentRight = parentRect.right - parseFloat(parentStyle.borderRightWidth || "0") - parseFloat(parentStyle.paddingRight || "0");
|
|
8924
|
+
const left = rect.left - contentLeft;
|
|
8925
|
+
const right = contentRight - rect.right;
|
|
8926
|
+
if (left < 0.5 || right < 0.5 || Math.abs(left - right) > 1) return false;
|
|
8927
|
+
const target = clone;
|
|
8928
|
+
if (!target.style) return false;
|
|
8929
|
+
target.style.setProperty("margin-left", `${left}px`);
|
|
8930
|
+
target.style.setProperty("margin-right", `${right}px`);
|
|
8931
|
+
return true;
|
|
8932
|
+
} catch {
|
|
8933
|
+
return false;
|
|
8934
|
+
}
|
|
8935
|
+
}
|
|
8642
8936
|
function maskClone(root) {
|
|
8643
8937
|
const doc = root.ownerDocument ?? root;
|
|
8644
8938
|
const view = doc.defaultView;
|
|
@@ -8671,7 +8965,8 @@ function maskClone(root) {
|
|
|
8671
8965
|
el.value = masked;
|
|
8672
8966
|
}
|
|
8673
8967
|
const placeholder = el.getAttribute("placeholder");
|
|
8674
|
-
if (placeholder)
|
|
8968
|
+
if (placeholder)
|
|
8969
|
+
el.setAttribute("placeholder", maskPiiText(placeholder));
|
|
8675
8970
|
}
|
|
8676
8971
|
}
|
|
8677
8972
|
node = walker.nextNode();
|
|
@@ -8711,6 +9006,8 @@ async function captureElementScreenshot(el) {
|
|
|
8711
9006
|
const doc = el.ownerDocument;
|
|
8712
9007
|
const view = doc.defaultView;
|
|
8713
9008
|
if (!view || !doc.documentElement || !el.isConnected) return null;
|
|
9009
|
+
await waitUntilSettled(el, view);
|
|
9010
|
+
if (!el.isConnected) return null;
|
|
8714
9011
|
const targetRectRaw = el.getBoundingClientRect();
|
|
8715
9012
|
const targetRect = {
|
|
8716
9013
|
left: targetRectRaw.left,
|
|
@@ -8719,31 +9016,54 @@ async function captureElementScreenshot(el) {
|
|
|
8719
9016
|
height: targetRectRaw.height
|
|
8720
9017
|
};
|
|
8721
9018
|
if (targetRect.width <= 0 || targetRect.height <= 0) return null;
|
|
8722
|
-
const
|
|
9019
|
+
const idealCrop = computeCropRect(
|
|
9020
|
+
targetRect,
|
|
9021
|
+
view.innerWidth,
|
|
9022
|
+
view.innerHeight
|
|
9023
|
+
);
|
|
9024
|
+
if (idealCrop.width <= 0 || idealCrop.height <= 0) return null;
|
|
9025
|
+
const renderRoot = findRenderRoot(el, idealCrop, doc.documentElement, view);
|
|
9026
|
+
const rootRect = renderRoot.getBoundingClientRect();
|
|
9027
|
+
const rootBox = {
|
|
9028
|
+
left: rootRect.left,
|
|
9029
|
+
top: rootRect.top,
|
|
9030
|
+
width: rootRect.width,
|
|
9031
|
+
height: rootRect.height
|
|
9032
|
+
};
|
|
9033
|
+
const cropRect = clipCrop(idealCrop, rootBox);
|
|
8723
9034
|
if (cropRect.width <= 0 || cropRect.height <= 0) return null;
|
|
8724
9035
|
const scale = outputScale(view, cropRect);
|
|
8725
|
-
const shiftX = -(cropRect.left
|
|
8726
|
-
const shiftY = -(cropRect.top
|
|
8727
|
-
const canvas = await
|
|
8728
|
-
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8742
|
-
|
|
8743
|
-
|
|
8744
|
-
|
|
8745
|
-
|
|
8746
|
-
|
|
9036
|
+
const shiftX = -(cropRect.left - rootRect.left);
|
|
9037
|
+
const shiftY = -(cropRect.top - rootRect.top);
|
|
9038
|
+
const canvas = await withDeadline(
|
|
9039
|
+
domToCanvas(renderRoot, {
|
|
9040
|
+
width: cropRect.width,
|
|
9041
|
+
height: cropRect.height,
|
|
9042
|
+
scale,
|
|
9043
|
+
backgroundColor: backgroundUnder(renderRoot, cropRect, doc, view),
|
|
9044
|
+
// Per resource, not per capture. `RENDER_TIMEOUT_MS` is the total,
|
|
9045
|
+
// and it is the race around this call that enforces it.
|
|
9046
|
+
timeout: RESOURCE_TIMEOUT_MS,
|
|
9047
|
+
filter: isCapturable,
|
|
9048
|
+
onCloneNode: (cloned) => {
|
|
9049
|
+
if (cloned instanceof Element) {
|
|
9050
|
+
repairAutoMargins(renderRoot, cloned, view);
|
|
9051
|
+
}
|
|
9052
|
+
maskClone(cloned);
|
|
9053
|
+
},
|
|
9054
|
+
// No `preferredFormat`. Asking for woff2 sounds like asking for the
|
|
9055
|
+
// smaller file and is really a filter: a face whose chosen source is
|
|
9056
|
+
// not woff2 is dropped rather than downgraded, and the text renders in
|
|
9057
|
+
// the browser's serif fallback. On our own hero that turned the button
|
|
9058
|
+
// label into Times (D1258). Let the library take whatever each face
|
|
9059
|
+
// actually offers.
|
|
9060
|
+
font: {},
|
|
9061
|
+
style: renderRootStyle(renderRoot, rootBox, doc, view, shiftX, shiftY)
|
|
9062
|
+
}),
|
|
9063
|
+
RENDER_TIMEOUT_MS,
|
|
9064
|
+
view
|
|
9065
|
+
);
|
|
9066
|
+
if (!canvas) return null;
|
|
8747
9067
|
const ctx = canvas.getContext("2d");
|
|
8748
9068
|
if (!ctx) return null;
|
|
8749
9069
|
drawOutline(ctx, targetRect, cropRect, scale);
|
|
@@ -8758,10 +9078,11 @@ async function captureElementScreenshot(el) {
|
|
|
8758
9078
|
return null;
|
|
8759
9079
|
}
|
|
8760
9080
|
}
|
|
8761
|
-
var CROP_MARGIN_RATIO, CROP_MARGIN_MAX_PX, CROP_MARGIN_MIN_PX, CROP_MAX_WIDTH, CROP_MAX_HEIGHT, OUTPUT_MAX_DPR, OUTPUT_MAX_PIXELS, DATA_URL_SOFT_MAX, RENDER_TIMEOUT_MS, PII_PATTERNS2, MASK2, OUTLINE_COLOR;
|
|
9081
|
+
var CROP_MARGIN_RATIO, CROP_MARGIN_MAX_PX, CROP_MARGIN_MIN_PX, CROP_MAX_WIDTH, CROP_MAX_HEIGHT, OUTPUT_MAX_DPR, OUTPUT_MAX_PIXELS, DATA_URL_SOFT_MAX, RENDER_TIMEOUT_MS, RESOURCE_TIMEOUT_MS, PII_PATTERNS2, MASK2, OUTLINE_COLOR, SETTLE_MAX_MS, SETTLE_STABLE_FRAMES, NODE_BUDGET, AREA_BUDGET_SCREENS, MIN_CROP_KEPT, BLOCK_DISPLAYS;
|
|
8762
9082
|
var init_screenshot = __esm({
|
|
8763
9083
|
"src/picker/screenshot.ts"() {
|
|
8764
9084
|
init_dist();
|
|
9085
|
+
init_shadow();
|
|
8765
9086
|
init_host();
|
|
8766
9087
|
init_message();
|
|
8767
9088
|
CROP_MARGIN_RATIO = 0.25;
|
|
@@ -8773,6 +9094,7 @@ var init_screenshot = __esm({
|
|
|
8773
9094
|
OUTPUT_MAX_PIXELS = 26e5;
|
|
8774
9095
|
DATA_URL_SOFT_MAX = 36e5;
|
|
8775
9096
|
RENDER_TIMEOUT_MS = SCREENSHOT_RENDER_BUDGET_MS;
|
|
9097
|
+
RESOURCE_TIMEOUT_MS = 1500;
|
|
8776
9098
|
PII_PATTERNS2 = [
|
|
8777
9099
|
/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
|
|
8778
9100
|
/\b\d{3}-\d{2}-\d{4}\b/g,
|
|
@@ -8780,6 +9102,12 @@ var init_screenshot = __esm({
|
|
|
8780
9102
|
];
|
|
8781
9103
|
MASK2 = "[masked]";
|
|
8782
9104
|
OUTLINE_COLOR = "#f04e23";
|
|
9105
|
+
SETTLE_MAX_MS = 900;
|
|
9106
|
+
SETTLE_STABLE_FRAMES = 2;
|
|
9107
|
+
NODE_BUDGET = 800;
|
|
9108
|
+
AREA_BUDGET_SCREENS = 3;
|
|
9109
|
+
MIN_CROP_KEPT = 0.4;
|
|
9110
|
+
BLOCK_DISPLAYS = /* @__PURE__ */ new Set(["block", "flow-root", "list-item", "table-cell"]);
|
|
8783
9111
|
}
|
|
8784
9112
|
});
|
|
8785
9113
|
|
|
@@ -8791,10 +9119,6 @@ function applySurvivalStyle(el, pointerEvents, offsets = []) {
|
|
|
8791
9119
|
el.style.setProperty(property, value, "important");
|
|
8792
9120
|
}
|
|
8793
9121
|
}
|
|
8794
|
-
function statusLabel(target) {
|
|
8795
|
-
const { text, tag } = target.core;
|
|
8796
|
-
return text ? `Sent "${text}" to ARCY` : `Sent <${tag}> to ARCY`;
|
|
8797
|
-
}
|
|
8798
9122
|
function createPickerOverlay(context) {
|
|
8799
9123
|
let shell = createShell({ id: PICKER_HOST_ID });
|
|
8800
9124
|
if (!shell) return null;
|
|
@@ -8817,28 +9141,36 @@ function createPickerOverlay(context) {
|
|
|
8817
9141
|
for (const [property, value] of BANNER_STYLE) {
|
|
8818
9142
|
banner.style.setProperty(property, value);
|
|
8819
9143
|
}
|
|
8820
|
-
const
|
|
8821
|
-
|
|
8822
|
-
|
|
9144
|
+
const mark = doc.createElement("span");
|
|
9145
|
+
mark.className = `${BANNER_CLASS}__mark`;
|
|
9146
|
+
const brand = doc.createElement("span");
|
|
9147
|
+
brand.className = `${BANNER_CLASS}__brand`;
|
|
9148
|
+
brand.textContent = "ARCY";
|
|
9149
|
+
const label = doc.createElement("span");
|
|
9150
|
+
label.className = `${BANNER_CLASS}__label`;
|
|
9151
|
+
label.textContent = "Element picker";
|
|
9152
|
+
mark.append(brand, label);
|
|
9153
|
+
const modes = doc.createElement("span");
|
|
9154
|
+
modes.className = `${BANNER_CLASS}__modes`;
|
|
9155
|
+
applySurvivalStyle(modes, "auto");
|
|
9156
|
+
modes.style.setProperty("position", "relative", "important");
|
|
8823
9157
|
const pickButton = doc.createElement("button");
|
|
8824
9158
|
pickButton.type = "button";
|
|
8825
9159
|
pickButton.textContent = "Pick";
|
|
8826
9160
|
const browseButton = doc.createElement("button");
|
|
8827
9161
|
browseButton.type = "button";
|
|
8828
9162
|
browseButton.textContent = "Browse";
|
|
8829
|
-
|
|
8830
|
-
status.className = `${BANNER_CLASS}__status`;
|
|
8831
|
-
status.textContent = "Click the element you want this step to target.";
|
|
9163
|
+
modes.append(pickButton, browseButton);
|
|
8832
9164
|
const exitButton = doc.createElement("button");
|
|
8833
9165
|
exitButton.type = "button";
|
|
9166
|
+
exitButton.className = `${BANNER_CLASS}__exit`;
|
|
8834
9167
|
exitButton.textContent = "Exit";
|
|
8835
|
-
banner.append(
|
|
9168
|
+
banner.append(mark, modes, exitButton);
|
|
8836
9169
|
shell.root.append(highlight, banner);
|
|
8837
9170
|
function setMode(next) {
|
|
8838
9171
|
mode = next;
|
|
8839
9172
|
pickButton.classList.toggle("is-active", next === "pick");
|
|
8840
9173
|
browseButton.classList.toggle("is-active", next === "browse");
|
|
8841
|
-
status.textContent = next === "pick" ? "Click the element you want this step to target." : "Browsing. Clicks work normally; switch back to pick.";
|
|
8842
9174
|
if (next === "browse") hideHighlight();
|
|
8843
9175
|
}
|
|
8844
9176
|
function hideHighlight() {
|
|
@@ -8921,7 +9253,6 @@ function createPickerOverlay(context) {
|
|
|
8921
9253
|
const ranked = rankSelectors(el);
|
|
8922
9254
|
fingerprint.selector = ranked.autoSelector;
|
|
8923
9255
|
fingerprint.selectorCandidates = ranked.candidates;
|
|
8924
|
-
status.textContent = statusLabel(fingerprint);
|
|
8925
9256
|
hovered = el;
|
|
8926
9257
|
moveHighlight(el);
|
|
8927
9258
|
let matchCount = 0;
|
|
@@ -8932,17 +9263,29 @@ function createPickerOverlay(context) {
|
|
|
8932
9263
|
context.onPick(fingerprint, matchCount);
|
|
8933
9264
|
if (context.screenshotsEnabled === false) return;
|
|
8934
9265
|
const token = ++screenshotToken;
|
|
8935
|
-
|
|
8936
|
-
if (
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8940
|
-
|
|
9266
|
+
afterNextPaint(() => {
|
|
9267
|
+
if (destroyed || token !== screenshotToken) return;
|
|
9268
|
+
void captureElementScreenshot(el).then((screenshot) => {
|
|
9269
|
+
if (!screenshot || destroyed || token !== screenshotToken) return;
|
|
9270
|
+
try {
|
|
9271
|
+
context.onScreenshot?.(screenshot);
|
|
9272
|
+
} catch {
|
|
9273
|
+
}
|
|
9274
|
+
});
|
|
8941
9275
|
});
|
|
8942
9276
|
} catch (error) {
|
|
8943
9277
|
warn(`The element picker could not read that element. ${String(error)}`);
|
|
8944
9278
|
}
|
|
8945
9279
|
};
|
|
9280
|
+
function afterNextPaint(fn) {
|
|
9281
|
+
const view = doc.defaultView;
|
|
9282
|
+
const raf = view?.requestAnimationFrame;
|
|
9283
|
+
if (typeof raf !== "function") {
|
|
9284
|
+
setTimeout(fn, 0);
|
|
9285
|
+
return;
|
|
9286
|
+
}
|
|
9287
|
+
raf.call(view, () => raf.call(view, fn));
|
|
9288
|
+
}
|
|
8946
9289
|
function isEditable(target) {
|
|
8947
9290
|
if (!(target instanceof Element)) return false;
|
|
8948
9291
|
const tag = target.tagName;
|
|
@@ -9008,7 +9351,7 @@ function createPickerOverlay(context) {
|
|
|
9008
9351
|
setMode("pick");
|
|
9009
9352
|
return { destroy };
|
|
9010
9353
|
}
|
|
9011
|
-
var PICKER_HOST_ID, BANNER_CLASS, HIGHLIGHT_CLASS, PICKER_CSS, HIGHLIGHT_STYLE, BANNER_OFFSET, BANNER_STYLE;
|
|
9354
|
+
var PICKER_HOST_ID, BANNER_CLASS, HIGHLIGHT_CLASS, INK, SURFACE, HAIRLINE, TEXT, MUTED, ACCENT, ON_ACCENT, PICKER_CSS, HIGHLIGHT_STYLE, BANNER_OFFSET, BANNER_STYLE;
|
|
9012
9355
|
var init_overlay = __esm({
|
|
9013
9356
|
"src/picker/overlay.ts"() {
|
|
9014
9357
|
init_capture();
|
|
@@ -9022,54 +9365,102 @@ var init_overlay = __esm({
|
|
|
9022
9365
|
PICKER_HOST_ID = "arcy-picker";
|
|
9023
9366
|
BANNER_CLASS = "arcy-picker-banner";
|
|
9024
9367
|
HIGHLIGHT_CLASS = "arcy-picker-highlight";
|
|
9368
|
+
INK = "#17131A";
|
|
9369
|
+
SURFACE = "#201B23";
|
|
9370
|
+
HAIRLINE = "#332B33";
|
|
9371
|
+
TEXT = "#F3EEE8";
|
|
9372
|
+
MUTED = "#9E959A";
|
|
9373
|
+
ACCENT = "#FF5A3C";
|
|
9374
|
+
ON_ACCENT = "#17131A";
|
|
9025
9375
|
PICKER_CSS = `
|
|
9026
9376
|
.${BANNER_CLASS} {
|
|
9027
9377
|
display: flex;
|
|
9028
9378
|
align-items: center;
|
|
9029
|
-
gap:
|
|
9030
|
-
padding:
|
|
9379
|
+
gap: 12px;
|
|
9380
|
+
padding: 7px 8px 7px 16px;
|
|
9031
9381
|
border-radius: 999px;
|
|
9032
|
-
background:
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9382
|
+
background: ${INK};
|
|
9383
|
+
border: 1px solid ${HAIRLINE};
|
|
9384
|
+
color: ${TEXT};
|
|
9385
|
+
font: 400 14px/1.2 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
9386
|
+
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.38);
|
|
9036
9387
|
white-space: nowrap;
|
|
9037
9388
|
}
|
|
9038
|
-
.${BANNER_CLASS}
|
|
9389
|
+
.${BANNER_CLASS}__mark {
|
|
9390
|
+
display: flex;
|
|
9391
|
+
align-items: baseline;
|
|
9392
|
+
gap: 7px;
|
|
9393
|
+
}
|
|
9394
|
+
.${BANNER_CLASS}__brand {
|
|
9039
9395
|
font-weight: 600;
|
|
9040
|
-
|
|
9396
|
+
letter-spacing: 0.02em;
|
|
9041
9397
|
}
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9046
|
-
|
|
9398
|
+
/* The label role from DESIGN.md: 600, 12px, uppercase, tracked wide. */
|
|
9399
|
+
.${BANNER_CLASS}__label {
|
|
9400
|
+
font-size: 12px;
|
|
9401
|
+
font-weight: 600;
|
|
9402
|
+
letter-spacing: 0.14em;
|
|
9403
|
+
text-transform: uppercase;
|
|
9404
|
+
color: ${MUTED};
|
|
9405
|
+
}
|
|
9406
|
+
/* Pick and Browse are one control with two states, not two buttons that
|
|
9407
|
+
* happen to disagree. The old bar drew both as outlines and coloured whichever
|
|
9408
|
+
* was on, which reads as two things you can press rather than as a switch. */
|
|
9409
|
+
.${BANNER_CLASS}__modes {
|
|
9410
|
+
display: flex;
|
|
9411
|
+
align-items: center;
|
|
9412
|
+
gap: 2px;
|
|
9413
|
+
padding: 3px;
|
|
9414
|
+
border-radius: 999px;
|
|
9415
|
+
background: ${SURFACE};
|
|
9047
9416
|
}
|
|
9048
9417
|
.${BANNER_CLASS} button {
|
|
9049
9418
|
appearance: none;
|
|
9050
|
-
border: 1px solid
|
|
9419
|
+
border: 1px solid transparent;
|
|
9051
9420
|
border-radius: 999px;
|
|
9052
9421
|
background: transparent;
|
|
9053
|
-
color:
|
|
9422
|
+
color: ${MUTED};
|
|
9054
9423
|
font: inherit;
|
|
9055
|
-
|
|
9424
|
+
font-weight: 500;
|
|
9425
|
+
padding: 5px 14px;
|
|
9056
9426
|
cursor: pointer;
|
|
9427
|
+
transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
|
|
9057
9428
|
}
|
|
9058
9429
|
.${BANNER_CLASS} button:hover {
|
|
9059
|
-
|
|
9430
|
+
color: ${TEXT};
|
|
9431
|
+
}
|
|
9432
|
+
.${BANNER_CLASS} button:focus-visible {
|
|
9433
|
+
outline: 2px solid ${ACCENT};
|
|
9434
|
+
outline-offset: 2px;
|
|
9060
9435
|
}
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9436
|
+
/* The one filled control on the bar (DESIGN.md, one accent fill per surface). */
|
|
9437
|
+
.${BANNER_CLASS}__modes button.is-active {
|
|
9438
|
+
background: ${ACCENT};
|
|
9439
|
+
color: ${ON_ACCENT};
|
|
9440
|
+
font-weight: 600;
|
|
9441
|
+
}
|
|
9442
|
+
.${BANNER_CLASS}__modes button.is-active:hover {
|
|
9443
|
+
color: ${ON_ACCENT};
|
|
9444
|
+
}
|
|
9445
|
+
.${BANNER_CLASS}__exit {
|
|
9446
|
+
border-color: ${HAIRLINE} !important;
|
|
9447
|
+
}
|
|
9448
|
+
.${BANNER_CLASS}__exit:hover {
|
|
9449
|
+
background: ${SURFACE};
|
|
9064
9450
|
}
|
|
9065
9451
|
.${HIGHLIGHT_CLASS} {
|
|
9066
|
-
border-radius:
|
|
9452
|
+
border-radius: 4px;
|
|
9067
9453
|
}
|
|
9068
9454
|
`;
|
|
9069
9455
|
HIGHLIGHT_STYLE = [
|
|
9070
9456
|
["box-sizing", "border-box"],
|
|
9071
|
-
[
|
|
9072
|
-
|
|
9457
|
+
[
|
|
9458
|
+
"border",
|
|
9459
|
+
// ADR 0171's accent border rule: an edge, not a fill. The tint behind it
|
|
9460
|
+
// is what keeps a thin outline readable on a busy page.
|
|
9461
|
+
`2px solid ${ACCENT}`
|
|
9462
|
+
],
|
|
9463
|
+
["background", "rgba(255, 90, 60, 0.1)"]
|
|
9073
9464
|
];
|
|
9074
9465
|
BANNER_OFFSET = [
|
|
9075
9466
|
["left", "50%"],
|
|
@@ -13485,15 +13876,19 @@ function createArcyInternals(internalOptions = {}) {
|
|
|
13485
13876
|
token,
|
|
13486
13877
|
sessionToken,
|
|
13487
13878
|
sessionId: telemetry?.sessionId(),
|
|
13488
|
-
// Slice 18.1's trigger conditions read
|
|
13489
|
-
//
|
|
13490
|
-
//
|
|
13491
|
-
//
|
|
13879
|
+
// Slice 18.1's trigger conditions read attributes set via identify().
|
|
13880
|
+
// Every present, non-null value is reported as it is and judged here
|
|
13881
|
+
// not at all (ADR 0205). Filtering lists out used to report a written
|
|
13882
|
+
// key as absent, which made `has_any_value` false for a list the
|
|
13883
|
+
// customer had sent; what a value *means* is `condition.ts`'s call and
|
|
13884
|
+
// is made in one place there.
|
|
13885
|
+
//
|
|
13886
|
+
// Nothing becomes comparable by arriving: `condition.ts` refuses every
|
|
13887
|
+
// comparison on an object or an array (ADR 0198's opaque rule), so no
|
|
13888
|
+
// value here can become `is "[object Object]"`.
|
|
13492
13889
|
getTrait: (codeName) => {
|
|
13493
13890
|
const value = identity.attributes[codeName];
|
|
13494
|
-
if (value === void 0 || value === null
|
|
13495
|
-
return void 0;
|
|
13496
|
-
}
|
|
13891
|
+
if (value === void 0 || value === null) return void 0;
|
|
13497
13892
|
return value;
|
|
13498
13893
|
},
|
|
13499
13894
|
// D1299: absent entirely (rather than answering false) when storage
|