@jsenv/navi 0.20.14 → 0.20.16
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/jsenv_navi.js +570 -589
- package/dist/jsenv_navi.js.map +22 -57
- package/dist/jsenv_navi_side_effects.js +49 -17
- package/dist/jsenv_navi_side_effects.js.map +4 -4
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { installImportMetaCssBuild } from "./jsenv_navi_side_effects.js";
|
|
2
2
|
import { isValidElement, h, createContext, toChildArray, render, createRef, cloneElement } from "preact";
|
|
3
3
|
import { useErrorBoundary, useLayoutEffect, useEffect, useMemo, useRef, useState, useCallback, useContext, useImperativeHandle, useId } from "preact/hooks";
|
|
4
4
|
import { jsxs, jsx, Fragment } from "preact/jsx-runtime";
|
|
@@ -71,7 +71,7 @@ const useActionStatus = (action) => {
|
|
|
71
71
|
};
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
75
75
|
.action_error {
|
|
76
76
|
margin-top: 0;
|
|
77
77
|
margin-bottom: 20px;
|
|
@@ -79,7 +79,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
79
79
|
background: #fdd;
|
|
80
80
|
border: 1px solid red;
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
`, "/src/action/action_renderer.jsx"];
|
|
83
83
|
const renderIdleDefault = () => null;
|
|
84
84
|
const renderLoadingDefault = () => null;
|
|
85
85
|
const renderAbortedDefault = () => null;
|
|
@@ -7449,7 +7449,32 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
7449
7449
|
styleKeySetWeakMap.set(element, styleKeySet);
|
|
7450
7450
|
};
|
|
7451
7451
|
|
|
7452
|
-
|
|
7452
|
+
installImportMetaCssBuild(import.meta);/**
|
|
7453
|
+
* Box - A Swiss Army Knife for Layout
|
|
7454
|
+
*
|
|
7455
|
+
* A regular div by default, enhanced with styling props for spacing, sizing,
|
|
7456
|
+
* and layout. The main value is a friendlier API over raw CSS Flexbox.
|
|
7457
|
+
*
|
|
7458
|
+
* ## Display & Layout
|
|
7459
|
+
*
|
|
7460
|
+
* - `flex` — horizontal flex container (items side by side)
|
|
7461
|
+
* - `flex="y"` — vertical flex container (items stacked). The prop name makes
|
|
7462
|
+
* the axis explicit, avoiding the classic CSS trap where `flex-direction: column`
|
|
7463
|
+
* actually stacks items vertically despite "column" feeling horizontal.
|
|
7464
|
+
* - `grid` — grid container
|
|
7465
|
+
* - `inline` — switches to inline display (works with flex and grid too)
|
|
7466
|
+
*
|
|
7467
|
+
* ## Alignment
|
|
7468
|
+
*
|
|
7469
|
+
* Instead of CSS's justify-content/align-items which swap meaning based on flex-direction:
|
|
7470
|
+
* - `alignX` — horizontal alignment, always
|
|
7471
|
+
* - `alignY` — vertical alignment, always
|
|
7472
|
+
*
|
|
7473
|
+
* ## Spacing & Sizing
|
|
7474
|
+
*
|
|
7475
|
+
* Props for margin, padding, gap, width, height, expand, shrink, and more.
|
|
7476
|
+
*/
|
|
7477
|
+
import.meta.css = [/* css */`
|
|
7453
7478
|
[navi-box-flow="inline"] {
|
|
7454
7479
|
display: inline;
|
|
7455
7480
|
}
|
|
@@ -7497,7 +7522,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
7497
7522
|
grid-auto-flow: unset;
|
|
7498
7523
|
}
|
|
7499
7524
|
}
|
|
7500
|
-
|
|
7525
|
+
`, "/src/box/box.jsx"];
|
|
7501
7526
|
const PSEUDO_CLASSES_DEFAULT = [];
|
|
7502
7527
|
const PSEUDO_ELEMENTS_DEFAULT = [];
|
|
7503
7528
|
const STYLE_CSS_VARS_DEFAULT = {};
|
|
@@ -8041,8 +8066,68 @@ const monitorItemsOverflow = (container) => {
|
|
|
8041
8066
|
return destroy;
|
|
8042
8067
|
};
|
|
8043
8068
|
|
|
8044
|
-
|
|
8045
|
-
|
|
8069
|
+
installImportMetaCssBuild(import.meta);/**
|
|
8070
|
+
* UI Transition - Core Implementation
|
|
8071
|
+
* Provides smooth resize transitions with cross-fade effects between content states
|
|
8072
|
+
*
|
|
8073
|
+
* Content Types and Terminology:
|
|
8074
|
+
*
|
|
8075
|
+
* - ui: What the user currently sees rendered in the UI
|
|
8076
|
+
* - dom_nodes: The actual DOM elements that make up the visual representation
|
|
8077
|
+
* - content_id: Unique identifier for a content and its content_phase(s)
|
|
8078
|
+
* - content_phase: Intermediate states (loading spinners, error messages, empty states)
|
|
8079
|
+
* - content: The primary/final content we want to display (e.g., car details, user profile)
|
|
8080
|
+
*
|
|
8081
|
+
* Required HTML structure:
|
|
8082
|
+
*
|
|
8083
|
+
* <div class="ui_transition">
|
|
8084
|
+
* <div class="ui_transition_active_group">
|
|
8085
|
+
* <div class="ui_transition_target_slot"></div>
|
|
8086
|
+
* <div class="ui_transition_outgoing_slot"></div>
|
|
8087
|
+
* </div>
|
|
8088
|
+
* <div class="ui_transition_previous_group">
|
|
8089
|
+
* <div class="ui_transition_previous_target_slot"></div>
|
|
8090
|
+
* <div class="ui_transition_previous_outgoing_slot"></div>
|
|
8091
|
+
* </div>
|
|
8092
|
+
* </div>
|
|
8093
|
+
*
|
|
8094
|
+
* Architecture Overview:
|
|
8095
|
+
*
|
|
8096
|
+
* .ui_transition
|
|
8097
|
+
* The main container that handles dimensional transitions. Its width and height animate
|
|
8098
|
+
* smoothly from current to target dimensions. Has overflow:hidden to clip ui during transitions.
|
|
8099
|
+
*
|
|
8100
|
+
* .active_group
|
|
8101
|
+
* Contains the ui that should be active after the transition completes. Groups both the target
|
|
8102
|
+
* ui (.target_slot) and transitional ui (.outgoing_slot) as a single unit that can
|
|
8103
|
+
* be manipulated together (e.g., applying transforms or slides).
|
|
8104
|
+
*
|
|
8105
|
+
* .target_slot
|
|
8106
|
+
* Always contains the target ui - what should be displayed at the end of the transition.
|
|
8107
|
+
* Whether transitioning to content or content_phase, this slot receives the new dom_nodes.
|
|
8108
|
+
* Receives fade-in transitions (opacity 0 → 1) during all transition types.
|
|
8109
|
+
*
|
|
8110
|
+
* .outgoing_slot
|
|
8111
|
+
* Holds content_phase that's being replaced during content_phase transitions. When transitioning
|
|
8112
|
+
* from one content_phase to another, or from content_phase to content, the old content_phase moves
|
|
8113
|
+
* here for fade-out. Receives fade-out transitions (opacity 1 → 0).
|
|
8114
|
+
*
|
|
8115
|
+
* .previous_group
|
|
8116
|
+
* Used for content-to-content transitions. When switching between content (not phases),
|
|
8117
|
+
* the entire .active_group dom_nodes are cloned here to fade out while the new content fades in.
|
|
8118
|
+
* Can slide out when sliding transitions are enabled, otherwise fades out.
|
|
8119
|
+
*
|
|
8120
|
+
* Transition Scenarios:
|
|
8121
|
+
* - content → content: Car A details → Car B details (clone to previous_group)
|
|
8122
|
+
* - content_phase → content_phase: Loading state → Error state (move to outgoing_slot, same content_id)
|
|
8123
|
+
* - content → content_phase: Car A details → Loading Car B (use outgoing_slot for cross-fade)
|
|
8124
|
+
* - content_phase → content: Loading Car B → Car B details (use outgoing_slot for cross-fade)
|
|
8125
|
+
*
|
|
8126
|
+
* Size Transition Handling:
|
|
8127
|
+
* During dimensional transitions, both .target_slot and .outgoing_slot have their dimensions
|
|
8128
|
+
* explicitly set to prevent dom_nodes reflow and maintain visual consistency.
|
|
8129
|
+
*/
|
|
8130
|
+
import.meta.css = [/* css */`
|
|
8046
8131
|
* {
|
|
8047
8132
|
box-sizing: border-box;
|
|
8048
8133
|
}
|
|
@@ -8144,74 +8229,51 @@ import.meta.css = /* css */ `
|
|
|
8144
8229
|
.ui_transition[data-transitioning] .ui_transition_target_slot_background {
|
|
8145
8230
|
display: block;
|
|
8146
8231
|
}
|
|
8147
|
-
|
|
8148
|
-
|
|
8232
|
+
`, "/src/ui_transition/ui_transition.js"];
|
|
8149
8233
|
const CONTENT_ID_ATTRIBUTE = "data-content-id";
|
|
8150
8234
|
const CONTENT_PHASE_ATTRIBUTE = "data-content-phase";
|
|
8151
8235
|
const UNSET = {
|
|
8152
8236
|
domNodes: [],
|
|
8153
8237
|
domNodesClone: [],
|
|
8154
8238
|
isEmpty: true,
|
|
8155
|
-
|
|
8156
8239
|
type: "unset",
|
|
8157
8240
|
contentId: "unset",
|
|
8158
8241
|
contentPhase: undefined,
|
|
8159
8242
|
isContentPhase: false,
|
|
8160
8243
|
isContent: false,
|
|
8161
|
-
toString: () => "unset"
|
|
8244
|
+
toString: () => "unset"
|
|
8162
8245
|
};
|
|
8163
|
-
|
|
8164
8246
|
const isSameConfiguration = (configA, configB) => {
|
|
8165
8247
|
return configA.toString() === configB.toString();
|
|
8166
8248
|
};
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
onStateChange = () => {},
|
|
8175
|
-
pauseBreakpoints = [],
|
|
8176
|
-
} = {},
|
|
8177
|
-
) => {
|
|
8249
|
+
const createUITransitionController = (root, {
|
|
8250
|
+
duration = 300,
|
|
8251
|
+
alignX = "center",
|
|
8252
|
+
alignY = "center",
|
|
8253
|
+
onStateChange = () => {},
|
|
8254
|
+
pauseBreakpoints = []
|
|
8255
|
+
} = {}) => {
|
|
8178
8256
|
const debugConfig = {
|
|
8179
8257
|
detection: root.hasAttribute("data-debug-detection"),
|
|
8180
|
-
size: root.hasAttribute("data-debug-size")
|
|
8258
|
+
size: root.hasAttribute("data-debug-size")
|
|
8181
8259
|
};
|
|
8182
8260
|
const hasDebugLogs = debugConfig.size;
|
|
8183
|
-
const debugDetection =
|
|
8261
|
+
const debugDetection = message => {
|
|
8184
8262
|
if (!debugConfig.detection) return;
|
|
8185
8263
|
console.debug(`[detection]`, message);
|
|
8186
8264
|
};
|
|
8187
|
-
const debugSize =
|
|
8265
|
+
const debugSize = message => {
|
|
8188
8266
|
if (!debugConfig.size) return;
|
|
8189
8267
|
console.debug(`[size]`, message);
|
|
8190
8268
|
};
|
|
8191
|
-
|
|
8192
8269
|
const activeGroup = root.querySelector(".ui_transition_active_group");
|
|
8193
8270
|
const targetSlot = root.querySelector(".ui_transition_target_slot");
|
|
8194
8271
|
const outgoingSlot = root.querySelector(".ui_transition_outgoing_slot");
|
|
8195
8272
|
const previousGroup = root.querySelector(".ui_transition_previous_group");
|
|
8196
|
-
const previousTargetSlot = previousGroup?.querySelector(
|
|
8197
|
-
|
|
8198
|
-
)
|
|
8199
|
-
|
|
8200
|
-
".ui_transition_previous_outgoing_slot",
|
|
8201
|
-
);
|
|
8202
|
-
|
|
8203
|
-
if (
|
|
8204
|
-
!root ||
|
|
8205
|
-
!activeGroup ||
|
|
8206
|
-
!targetSlot ||
|
|
8207
|
-
!outgoingSlot ||
|
|
8208
|
-
!previousGroup ||
|
|
8209
|
-
!previousTargetSlot ||
|
|
8210
|
-
!previousOutgoingSlot
|
|
8211
|
-
) {
|
|
8212
|
-
throw new Error(
|
|
8213
|
-
"createUITransitionController requires element with .active_group, .target_slot, .outgoing_slot, .previous_group, .previous_target_slot, and .previous_outgoing_slot elements",
|
|
8214
|
-
);
|
|
8273
|
+
const previousTargetSlot = previousGroup?.querySelector(".ui_transition_previous_target_slot");
|
|
8274
|
+
const previousOutgoingSlot = previousGroup?.querySelector(".ui_transition_previous_outgoing_slot");
|
|
8275
|
+
if (!root || !activeGroup || !targetSlot || !outgoingSlot || !previousGroup || !previousTargetSlot || !previousOutgoingSlot) {
|
|
8276
|
+
throw new Error("createUITransitionController requires element with .active_group, .target_slot, .outgoing_slot, .previous_group, .previous_target_slot, and .previous_outgoing_slot elements");
|
|
8215
8277
|
}
|
|
8216
8278
|
|
|
8217
8279
|
// we maintain a background copy behind target slot to avoid showing
|
|
@@ -8219,17 +8281,17 @@ const createUITransitionController = (
|
|
|
8219
8281
|
const targetSlotBackground = document.createElement("div");
|
|
8220
8282
|
targetSlotBackground.className = "ui_transition_target_slot_background";
|
|
8221
8283
|
activeGroup.insertBefore(targetSlotBackground, targetSlot);
|
|
8222
|
-
|
|
8223
8284
|
root.style.setProperty("--x-transition-duration", `${duration}ms`);
|
|
8224
8285
|
outgoingSlot.setAttribute("inert", "");
|
|
8225
8286
|
previousGroup.setAttribute("inert", "");
|
|
8226
|
-
|
|
8227
|
-
|
|
8287
|
+
const detectConfiguration = (slot, {
|
|
8288
|
+
contentId,
|
|
8289
|
+
contentPhase
|
|
8290
|
+
} = {}) => {
|
|
8228
8291
|
const domNodes = Array.from(slot.childNodes);
|
|
8229
8292
|
if (!domNodes) {
|
|
8230
8293
|
return UNSET;
|
|
8231
8294
|
}
|
|
8232
|
-
|
|
8233
8295
|
const isEmpty = domNodes.length === 0;
|
|
8234
8296
|
let textNodeCount = 0;
|
|
8235
8297
|
let elementNodeCount = 0;
|
|
@@ -8250,7 +8312,6 @@ const createUITransitionController = (
|
|
|
8250
8312
|
firstElementNode = domNode;
|
|
8251
8313
|
}
|
|
8252
8314
|
elementNodeCount++;
|
|
8253
|
-
|
|
8254
8315
|
if (domNode.hasAttribute("data-content-phase")) {
|
|
8255
8316
|
const contentPhaseAttr = domNode.getAttribute("data-content-phase");
|
|
8256
8317
|
contentPhase = contentPhaseAttr || "attr";
|
|
@@ -8262,11 +8323,8 @@ const createUITransitionController = (
|
|
|
8262
8323
|
const domNodeClone = domNode.cloneNode(true);
|
|
8263
8324
|
domNodesClone.push(domNodeClone);
|
|
8264
8325
|
}
|
|
8265
|
-
|
|
8266
8326
|
if (contentIdSlotAttr && contentIdChildAttr) {
|
|
8267
|
-
console.warn(
|
|
8268
|
-
`Slot and slot child both have a [${CONTENT_ID_ATTRIBUTE}]. Slot is ${contentIdSlotAttr} and child is ${contentIdChildAttr}, using the child.`,
|
|
8269
|
-
);
|
|
8327
|
+
console.warn(`Slot and slot child both have a [${CONTENT_ID_ATTRIBUTE}]. Slot is ${contentIdSlotAttr} and child is ${contentIdChildAttr}, using the child.`);
|
|
8270
8328
|
}
|
|
8271
8329
|
if (contentId === undefined) {
|
|
8272
8330
|
contentId = contentIdChildAttr || contentIdSlotAttr || undefined;
|
|
@@ -8274,7 +8332,6 @@ const createUITransitionController = (
|
|
|
8274
8332
|
}
|
|
8275
8333
|
const isOnlyTextNodes = elementNodeCount === 0 && textNodeCount > 1;
|
|
8276
8334
|
const singleElementNode = elementNodeCount === 1 ? firstElementNode : null;
|
|
8277
|
-
|
|
8278
8335
|
contentId = contentId || getElementSignature(domNodes[0]);
|
|
8279
8336
|
if (!contentPhase && isEmpty) {
|
|
8280
8337
|
// Imagine code rendering null while switching to a new content
|
|
@@ -8285,22 +8342,16 @@ const createUITransitionController = (
|
|
|
8285
8342
|
// intermediate states.
|
|
8286
8343
|
contentPhase = "empty";
|
|
8287
8344
|
}
|
|
8288
|
-
|
|
8289
8345
|
let width;
|
|
8290
8346
|
let height;
|
|
8291
8347
|
let borderRadius;
|
|
8292
8348
|
let border;
|
|
8293
8349
|
let background;
|
|
8294
|
-
|
|
8295
8350
|
if (isEmpty) {
|
|
8296
8351
|
debugSize(`measureSlot(".${slot.className}") -> it is empty`);
|
|
8297
8352
|
} else if (singleElementNode) {
|
|
8298
|
-
const visualSelector = singleElementNode.getAttribute(
|
|
8299
|
-
|
|
8300
|
-
);
|
|
8301
|
-
const visualElement = visualSelector
|
|
8302
|
-
? singleElementNode.querySelector(visualSelector) || singleElementNode
|
|
8303
|
-
: singleElementNode;
|
|
8353
|
+
const visualSelector = singleElementNode.getAttribute("data-visual-selector");
|
|
8354
|
+
const visualElement = visualSelector ? singleElementNode.querySelector(visualSelector) || singleElementNode : singleElementNode;
|
|
8304
8355
|
const rect = visualElement.getBoundingClientRect();
|
|
8305
8356
|
width = rect.width;
|
|
8306
8357
|
height = rect.height;
|
|
@@ -8315,23 +8366,19 @@ const createUITransitionController = (
|
|
|
8315
8366
|
height = rect.height;
|
|
8316
8367
|
debugSize(`measureSlot(".${slot.className}") -> [${width}x${height}]`);
|
|
8317
8368
|
}
|
|
8318
|
-
|
|
8319
8369
|
const commonProperties = {
|
|
8320
8370
|
domNodes,
|
|
8321
8371
|
domNodesClone,
|
|
8322
8372
|
isEmpty,
|
|
8323
8373
|
isOnlyTextNodes,
|
|
8324
8374
|
singleElementNode,
|
|
8325
|
-
|
|
8326
8375
|
width,
|
|
8327
8376
|
height,
|
|
8328
8377
|
borderRadius,
|
|
8329
8378
|
border,
|
|
8330
8379
|
background,
|
|
8331
|
-
|
|
8332
|
-
contentId,
|
|
8380
|
+
contentId
|
|
8333
8381
|
};
|
|
8334
|
-
|
|
8335
8382
|
if (contentPhase) {
|
|
8336
8383
|
return {
|
|
8337
8384
|
...commonProperties,
|
|
@@ -8339,7 +8386,7 @@ const createUITransitionController = (
|
|
|
8339
8386
|
contentPhase,
|
|
8340
8387
|
isContentPhase: true,
|
|
8341
8388
|
isContent: false,
|
|
8342
|
-
toString: () => `content(${contentId}).phase(${contentPhase})
|
|
8389
|
+
toString: () => `content(${contentId}).phase(${contentPhase})`
|
|
8343
8390
|
};
|
|
8344
8391
|
}
|
|
8345
8392
|
return {
|
|
@@ -8348,18 +8395,16 @@ const createUITransitionController = (
|
|
|
8348
8395
|
contentPhase: undefined,
|
|
8349
8396
|
isContentPhase: false,
|
|
8350
8397
|
isContent: true,
|
|
8351
|
-
toString: () => `content(${contentId})
|
|
8398
|
+
toString: () => `content(${contentId})`
|
|
8352
8399
|
};
|
|
8353
8400
|
};
|
|
8354
|
-
|
|
8355
8401
|
const targetSlotInitialConfiguration = detectConfiguration(targetSlot);
|
|
8356
8402
|
const outgoingSlotInitialConfiguration = detectConfiguration(outgoingSlot, {
|
|
8357
|
-
contentPhase: "true"
|
|
8403
|
+
contentPhase: "true"
|
|
8358
8404
|
});
|
|
8359
8405
|
let targetSlotConfiguration = targetSlotInitialConfiguration;
|
|
8360
8406
|
let outgoingSlotConfiguration = outgoingSlotInitialConfiguration;
|
|
8361
8407
|
let previousTargetSlotConfiguration = UNSET;
|
|
8362
|
-
|
|
8363
8408
|
const updateSlotAttributes = () => {
|
|
8364
8409
|
if (targetSlotConfiguration.isEmpty && outgoingSlotConfiguration.isEmpty) {
|
|
8365
8410
|
root.setAttribute("data-only-previous-group", "");
|
|
@@ -8372,7 +8417,6 @@ const createUITransitionController = (
|
|
|
8372
8417
|
root.setAttribute("data-align-x", alignX);
|
|
8373
8418
|
root.setAttribute("data-align-y", alignY);
|
|
8374
8419
|
};
|
|
8375
|
-
|
|
8376
8420
|
const moveConfigurationIntoSlot = (configuration, slot) => {
|
|
8377
8421
|
slot.innerHTML = "";
|
|
8378
8422
|
for (const domNode of configuration.domNodesClone) {
|
|
@@ -8390,9 +8434,7 @@ const createUITransitionController = (
|
|
|
8390
8434
|
throw new Error("Unknown slot for applyConfiguration");
|
|
8391
8435
|
}
|
|
8392
8436
|
};
|
|
8393
|
-
|
|
8394
8437
|
updateAlignment();
|
|
8395
|
-
|
|
8396
8438
|
let transitionType = "none";
|
|
8397
8439
|
const groupTransitionOptions = {
|
|
8398
8440
|
// debugBreakpoints: [0.25],
|
|
@@ -8401,21 +8443,22 @@ const createUITransitionController = (
|
|
|
8401
8443
|
setup: () => {
|
|
8402
8444
|
updateSlotAttributes();
|
|
8403
8445
|
root.setAttribute("data-transitioning", "");
|
|
8404
|
-
onStateChange({
|
|
8446
|
+
onStateChange({
|
|
8447
|
+
isTransitioning: true
|
|
8448
|
+
});
|
|
8405
8449
|
return {
|
|
8406
8450
|
teardown: () => {
|
|
8407
8451
|
root.removeAttribute("data-transitioning");
|
|
8408
8452
|
updateSlotAttributes(); // Update positioning after transition
|
|
8409
|
-
onStateChange({
|
|
8410
|
-
|
|
8453
|
+
onStateChange({
|
|
8454
|
+
isTransitioning: false
|
|
8455
|
+
});
|
|
8456
|
+
}
|
|
8411
8457
|
};
|
|
8412
|
-
}
|
|
8413
|
-
}
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
8414
8460
|
};
|
|
8415
|
-
const transitionController = createGroupTransitionController(
|
|
8416
|
-
groupTransitionOptions,
|
|
8417
|
-
);
|
|
8418
|
-
|
|
8461
|
+
const transitionController = createGroupTransitionController(groupTransitionOptions);
|
|
8419
8462
|
const elementToClip = root;
|
|
8420
8463
|
const morphContainerIntoTarget = () => {
|
|
8421
8464
|
const morphTransitions = [];
|
|
@@ -8429,31 +8472,28 @@ const createUITransitionController = (
|
|
|
8429
8472
|
const fromHeight = previousTargetSlotConfiguration.height || 0;
|
|
8430
8473
|
const toWidth = targetSlotConfiguration.width || 0;
|
|
8431
8474
|
const toHeight = targetSlotConfiguration.height || 0;
|
|
8432
|
-
debugSize(
|
|
8433
|
-
`transition from [${fromWidth}x${fromHeight}] to [${toWidth}x${toHeight}]`,
|
|
8434
|
-
);
|
|
8475
|
+
debugSize(`transition from [${fromWidth}x${fromHeight}] to [${toWidth}x${toHeight}]`);
|
|
8435
8476
|
const restoreOverflow = preventIntermediateScrollbar(root, {
|
|
8436
8477
|
fromWidth,
|
|
8437
8478
|
fromHeight,
|
|
8438
8479
|
toWidth,
|
|
8439
8480
|
toHeight,
|
|
8440
|
-
onPrevent: ({
|
|
8481
|
+
onPrevent: ({
|
|
8482
|
+
x,
|
|
8483
|
+
y,
|
|
8484
|
+
scrollContainer
|
|
8485
|
+
}) => {
|
|
8441
8486
|
if (x) {
|
|
8442
|
-
debugSize(
|
|
8443
|
-
`Temporarily hiding horizontal overflow during transition on ${getElementSignature(scrollContainer)}`,
|
|
8444
|
-
);
|
|
8487
|
+
debugSize(`Temporarily hiding horizontal overflow during transition on ${getElementSignature(scrollContainer)}`);
|
|
8445
8488
|
}
|
|
8446
8489
|
if (y) {
|
|
8447
|
-
debugSize(
|
|
8448
|
-
`Temporarily hiding vertical overflow during transition on ${getElementSignature(scrollContainer)}`,
|
|
8449
|
-
);
|
|
8490
|
+
debugSize(`Temporarily hiding vertical overflow during transition on ${getElementSignature(scrollContainer)}`);
|
|
8450
8491
|
}
|
|
8451
8492
|
},
|
|
8452
8493
|
onRestore: () => {
|
|
8453
8494
|
debugSize(`Restored overflow after transition`);
|
|
8454
|
-
}
|
|
8495
|
+
}
|
|
8455
8496
|
});
|
|
8456
|
-
|
|
8457
8497
|
const onSizeTransitionFinished = () => {
|
|
8458
8498
|
// Restore overflow when transition is complete
|
|
8459
8499
|
restoreOverflow();
|
|
@@ -8476,95 +8516,63 @@ const createUITransitionController = (
|
|
|
8476
8516
|
}
|
|
8477
8517
|
};
|
|
8478
8518
|
// Position of "from" content within large container
|
|
8479
|
-
const fromLeft = getAlignedPosition(
|
|
8480
|
-
|
|
8481
|
-
fromWidth,
|
|
8482
|
-
alignX,
|
|
8483
|
-
);
|
|
8484
|
-
const fromTop = getAlignedPosition(
|
|
8485
|
-
elementToClipHeight,
|
|
8486
|
-
fromHeight,
|
|
8487
|
-
alignY,
|
|
8488
|
-
);
|
|
8519
|
+
const fromLeft = getAlignedPosition(elementToClipWidth, fromWidth, alignX);
|
|
8520
|
+
const fromTop = getAlignedPosition(elementToClipHeight, fromHeight, alignY);
|
|
8489
8521
|
// Position of target content within large container
|
|
8490
|
-
const targetLeft = getAlignedPosition(
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
alignX,
|
|
8494
|
-
);
|
|
8495
|
-
const targetTop = getAlignedPosition(
|
|
8496
|
-
elementToClipHeight,
|
|
8497
|
-
toHeight,
|
|
8498
|
-
alignY,
|
|
8499
|
-
);
|
|
8500
|
-
debugSize(
|
|
8501
|
-
`Positions in container: from [${fromLeft},${fromTop}] ${fromWidth}x${fromHeight} to [${targetLeft},${targetTop}] ${toWidth}x${toHeight}`,
|
|
8502
|
-
);
|
|
8522
|
+
const targetLeft = getAlignedPosition(elementToClipWidth, toWidth, alignX);
|
|
8523
|
+
const targetTop = getAlignedPosition(elementToClipHeight, toHeight, alignY);
|
|
8524
|
+
debugSize(`Positions in container: from [${fromLeft},${fromTop}] ${fromWidth}x${fromHeight} to [${targetLeft},${targetTop}] ${toWidth}x${toHeight}`);
|
|
8503
8525
|
// Get border-radius values
|
|
8504
|
-
const fromBorderRadius =
|
|
8505
|
-
previousTargetSlotConfiguration.borderRadius || 0;
|
|
8526
|
+
const fromBorderRadius = previousTargetSlotConfiguration.borderRadius || 0;
|
|
8506
8527
|
const toBorderRadius = targetSlotConfiguration.borderRadius || 0;
|
|
8507
8528
|
const startInsetTop = fromTop;
|
|
8508
8529
|
const startInsetRight = elementToClipWidth - (fromLeft + fromWidth);
|
|
8509
8530
|
const startInsetBottom = elementToClipHeight - (fromTop + fromHeight);
|
|
8510
8531
|
const startInsetLeft = fromLeft;
|
|
8511
|
-
|
|
8512
8532
|
const endInsetTop = targetTop;
|
|
8513
8533
|
const endInsetRight = elementToClipWidth - (targetLeft + toWidth);
|
|
8514
8534
|
const endInsetBottom = elementToClipHeight - (targetTop + toHeight);
|
|
8515
8535
|
const endInsetLeft = targetLeft;
|
|
8516
|
-
|
|
8517
8536
|
const startClipPath = `inset(${startInsetTop}px ${startInsetRight}px ${startInsetBottom}px ${startInsetLeft}px round ${fromBorderRadius}px)`;
|
|
8518
8537
|
const endClipPath = `inset(${endInsetTop}px ${endInsetRight}px ${endInsetBottom}px ${endInsetLeft}px round ${toBorderRadius}px)`;
|
|
8519
8538
|
// Create clip-path animation using Web Animations API
|
|
8520
|
-
const clipAnimation = elementToClip.animate(
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8539
|
+
const clipAnimation = elementToClip.animate([{
|
|
8540
|
+
clipPath: startClipPath
|
|
8541
|
+
}, {
|
|
8542
|
+
clipPath: endClipPath
|
|
8543
|
+
}], {
|
|
8544
|
+
duration,
|
|
8545
|
+
easing: "ease",
|
|
8546
|
+
fill: "forwards"
|
|
8547
|
+
});
|
|
8528
8548
|
|
|
8529
8549
|
// Handle finish
|
|
8530
|
-
clipAnimation.finished
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
// Animation was cancelled
|
|
8539
|
-
});
|
|
8550
|
+
clipAnimation.finished.then(() => {
|
|
8551
|
+
// Clear clip-path to restore normal behavior
|
|
8552
|
+
elementToClip.style.clipPath = "";
|
|
8553
|
+
clipAnimation.cancel();
|
|
8554
|
+
onSizeTransitionFinished();
|
|
8555
|
+
}).catch(() => {
|
|
8556
|
+
// Animation was cancelled
|
|
8557
|
+
});
|
|
8540
8558
|
clipAnimation.play();
|
|
8541
8559
|
}
|
|
8542
|
-
|
|
8543
8560
|
return morphTransitions;
|
|
8544
8561
|
};
|
|
8545
8562
|
const fadeInTargetSlot = () => {
|
|
8546
|
-
targetSlotBackground.style.setProperty(
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
);
|
|
8550
|
-
targetSlotBackground.style.setProperty(
|
|
8551
|
-
"--target-slot-width",
|
|
8552
|
-
`${targetSlotConfiguration.width || 0}px`,
|
|
8553
|
-
);
|
|
8554
|
-
targetSlotBackground.style.setProperty(
|
|
8555
|
-
"--target-slot-height",
|
|
8556
|
-
`${targetSlotConfiguration.height || 0}px`,
|
|
8557
|
-
);
|
|
8563
|
+
targetSlotBackground.style.setProperty("--target-slot-background", targetSlotConfiguration.background);
|
|
8564
|
+
targetSlotBackground.style.setProperty("--target-slot-width", `${targetSlotConfiguration.width || 0}px`);
|
|
8565
|
+
targetSlotBackground.style.setProperty("--target-slot-height", `${targetSlotConfiguration.height || 0}px`);
|
|
8558
8566
|
return createOpacityTransition(targetSlot, 1, {
|
|
8559
8567
|
from: 0,
|
|
8560
8568
|
duration,
|
|
8561
8569
|
styleSynchronizer: "inline_style",
|
|
8562
|
-
onFinish:
|
|
8570
|
+
onFinish: targetSlotOpacityTransition => {
|
|
8563
8571
|
targetSlotBackground.style.removeProperty("--target-slot-background");
|
|
8564
8572
|
targetSlotBackground.style.removeProperty("--target-slot-width");
|
|
8565
8573
|
targetSlotBackground.style.removeProperty("--target-slot-height");
|
|
8566
8574
|
targetSlotOpacityTransition.cancel();
|
|
8567
|
-
}
|
|
8575
|
+
}
|
|
8568
8576
|
});
|
|
8569
8577
|
};
|
|
8570
8578
|
const fadeOutPreviousGroup = () => {
|
|
@@ -8572,10 +8580,10 @@ const createUITransitionController = (
|
|
|
8572
8580
|
from: 1,
|
|
8573
8581
|
duration,
|
|
8574
8582
|
styleSynchronizer: "inline_style",
|
|
8575
|
-
onFinish:
|
|
8583
|
+
onFinish: previousGroupOpacityTransition => {
|
|
8576
8584
|
previousGroupOpacityTransition.cancel();
|
|
8577
8585
|
previousGroup.style.opacity = "0"; // keep previous group visually hidden
|
|
8578
|
-
}
|
|
8586
|
+
}
|
|
8579
8587
|
});
|
|
8580
8588
|
};
|
|
8581
8589
|
const fadeOutOutgoingSlot = () => {
|
|
@@ -8583,27 +8591,22 @@ const createUITransitionController = (
|
|
|
8583
8591
|
duration,
|
|
8584
8592
|
from: 1,
|
|
8585
8593
|
styleSynchronizer: "inline_style",
|
|
8586
|
-
onFinish:
|
|
8594
|
+
onFinish: outgoingSlotOpacityTransition => {
|
|
8587
8595
|
outgoingSlotOpacityTransition.cancel();
|
|
8588
8596
|
outgoingSlot.style.opacity = "0"; // keep outgoing slot visually hidden
|
|
8589
|
-
}
|
|
8597
|
+
}
|
|
8590
8598
|
});
|
|
8591
8599
|
};
|
|
8592
8600
|
|
|
8593
8601
|
// content_to_content transition (uses previous_group)
|
|
8594
|
-
const applyContentToContentTransition =
|
|
8602
|
+
const applyContentToContentTransition = toConfiguration => {
|
|
8595
8603
|
// 1. move target slot to previous
|
|
8596
8604
|
moveConfigurationIntoSlot(targetSlotConfiguration, previousTargetSlot);
|
|
8597
8605
|
targetSlotConfiguration = toConfiguration;
|
|
8598
8606
|
// 2. move outgoing slot to previous
|
|
8599
8607
|
moveConfigurationIntoSlot(outgoingSlotConfiguration, previousOutgoingSlot);
|
|
8600
8608
|
moveConfigurationIntoSlot(UNSET, outgoingSlot);
|
|
8601
|
-
|
|
8602
|
-
const transitions = [
|
|
8603
|
-
...morphContainerIntoTarget(),
|
|
8604
|
-
fadeInTargetSlot(),
|
|
8605
|
-
fadeOutPreviousGroup(),
|
|
8606
|
-
];
|
|
8609
|
+
const transitions = [...morphContainerIntoTarget(), fadeInTargetSlot(), fadeOutPreviousGroup()];
|
|
8607
8610
|
const transition = transitionController.update(transitions, {
|
|
8608
8611
|
onFinish: () => {
|
|
8609
8612
|
moveConfigurationIntoSlot(UNSET, previousTargetSlot);
|
|
@@ -8611,29 +8614,23 @@ const createUITransitionController = (
|
|
|
8611
8614
|
if (hasDebugLogs) {
|
|
8612
8615
|
console.groupEnd();
|
|
8613
8616
|
}
|
|
8614
|
-
}
|
|
8617
|
+
}
|
|
8615
8618
|
});
|
|
8616
8619
|
transition.play();
|
|
8617
8620
|
};
|
|
8618
8621
|
// content_phase_to_content_phase transition (uses outgoing_slot)
|
|
8619
|
-
const applyContentPhaseToContentPhaseTransition =
|
|
8622
|
+
const applyContentPhaseToContentPhaseTransition = toConfiguration => {
|
|
8620
8623
|
// 1. Move target slot to outgoing
|
|
8621
8624
|
moveConfigurationIntoSlot(targetSlotConfiguration, outgoingSlot);
|
|
8622
8625
|
targetSlotConfiguration = toConfiguration;
|
|
8623
|
-
|
|
8624
|
-
const transitions = [
|
|
8625
|
-
...morphContainerIntoTarget(),
|
|
8626
|
-
fadeInTargetSlot(),
|
|
8627
|
-
fadeOutOutgoingSlot(),
|
|
8628
|
-
];
|
|
8626
|
+
const transitions = [...morphContainerIntoTarget(), fadeInTargetSlot(), fadeOutOutgoingSlot()];
|
|
8629
8627
|
const transition = transitionController.update(transitions, {
|
|
8630
8628
|
onFinish: () => {
|
|
8631
8629
|
moveConfigurationIntoSlot(UNSET, outgoingSlot);
|
|
8632
|
-
|
|
8633
8630
|
if (hasDebugLogs) {
|
|
8634
8631
|
console.groupEnd();
|
|
8635
8632
|
}
|
|
8636
|
-
}
|
|
8633
|
+
}
|
|
8637
8634
|
});
|
|
8638
8635
|
transition.play();
|
|
8639
8636
|
};
|
|
@@ -8645,7 +8642,6 @@ const createUITransitionController = (
|
|
|
8645
8642
|
// 2. move outgoing slot to previous
|
|
8646
8643
|
moveConfigurationIntoSlot(outgoingSlotConfiguration, previousOutgoingSlot);
|
|
8647
8644
|
outgoingSlotConfiguration = UNSET;
|
|
8648
|
-
|
|
8649
8645
|
const transitions = [...morphContainerIntoTarget(), fadeOutPreviousGroup()];
|
|
8650
8646
|
const transition = transitionController.update(transitions, {
|
|
8651
8647
|
onFinish: () => {
|
|
@@ -8654,15 +8650,15 @@ const createUITransitionController = (
|
|
|
8654
8650
|
if (hasDebugLogs) {
|
|
8655
8651
|
console.groupEnd();
|
|
8656
8652
|
}
|
|
8657
|
-
}
|
|
8653
|
+
}
|
|
8658
8654
|
});
|
|
8659
8655
|
transition.play();
|
|
8660
8656
|
};
|
|
8661
8657
|
// Main transition method
|
|
8662
|
-
const transitionTo = (
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
) => {
|
|
8658
|
+
const transitionTo = (newContentElement, {
|
|
8659
|
+
contentPhase,
|
|
8660
|
+
contentId
|
|
8661
|
+
} = {}) => {
|
|
8666
8662
|
if (contentId) {
|
|
8667
8663
|
targetSlot.setAttribute(CONTENT_ID_ATTRIBUTE, contentId);
|
|
8668
8664
|
} else {
|
|
@@ -8688,8 +8684,7 @@ const createUITransitionController = (
|
|
|
8688
8684
|
moveConfigurationIntoSlot(UNSET, previousTargetSlot);
|
|
8689
8685
|
moveConfigurationIntoSlot(UNSET, previousOutgoingSlot);
|
|
8690
8686
|
};
|
|
8691
|
-
|
|
8692
|
-
const targetSlotEffect = (reasons) => {
|
|
8687
|
+
const targetSlotEffect = reasons => {
|
|
8693
8688
|
if (root.hasAttribute("data-disabled")) {
|
|
8694
8689
|
return;
|
|
8695
8690
|
}
|
|
@@ -8701,9 +8696,7 @@ const createUITransitionController = (
|
|
|
8701
8696
|
console.debug(`- ${reasons.join("\n- ")}`);
|
|
8702
8697
|
}
|
|
8703
8698
|
if (isSameConfiguration(fromConfiguration, toConfiguration)) {
|
|
8704
|
-
debugDetection(
|
|
8705
|
-
`already in desired state (${toConfiguration}) -> early return`,
|
|
8706
|
-
);
|
|
8699
|
+
debugDetection(`already in desired state (${toConfiguration}) -> early return`);
|
|
8707
8700
|
if (hasDebugLogs) {
|
|
8708
8701
|
console.groupEnd();
|
|
8709
8702
|
}
|
|
@@ -8712,9 +8705,7 @@ const createUITransitionController = (
|
|
|
8712
8705
|
const fromConfigType = fromConfiguration.type;
|
|
8713
8706
|
const toConfigType = toConfiguration.type;
|
|
8714
8707
|
transitionType = `${fromConfigType}_to_${toConfigType}`;
|
|
8715
|
-
debugDetection(
|
|
8716
|
-
`Prepare "${transitionType}" transition (${fromConfiguration} -> ${toConfiguration})`,
|
|
8717
|
-
);
|
|
8708
|
+
debugDetection(`Prepare "${transitionType}" transition (${fromConfiguration} -> ${toConfiguration})`);
|
|
8718
8709
|
// content_to_empty / content_phase_to_empty
|
|
8719
8710
|
if (toConfiguration.isEmpty) {
|
|
8720
8711
|
applyToEmptyTransition();
|
|
@@ -8738,10 +8729,9 @@ const createUITransitionController = (
|
|
|
8738
8729
|
// content_to_content (default case)
|
|
8739
8730
|
applyContentToContentTransition(toConfiguration);
|
|
8740
8731
|
};
|
|
8741
|
-
|
|
8742
8732
|
const [teardown, addTeardown] = createPubSub();
|
|
8743
8733
|
{
|
|
8744
|
-
const mutationObserver = new MutationObserver(
|
|
8734
|
+
const mutationObserver = new MutationObserver(mutations => {
|
|
8745
8735
|
const reasonParts = [];
|
|
8746
8736
|
for (const mutation of mutations) {
|
|
8747
8737
|
if (mutation.type === "childList") {
|
|
@@ -8757,33 +8747,25 @@ const createUITransitionController = (
|
|
|
8757
8747
|
continue;
|
|
8758
8748
|
}
|
|
8759
8749
|
if (mutation.type === "attributes") {
|
|
8760
|
-
const {
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8750
|
+
const {
|
|
8751
|
+
attributeName
|
|
8752
|
+
} = mutation;
|
|
8753
|
+
if (attributeName === CONTENT_ID_ATTRIBUTE || attributeName === CONTENT_PHASE_ATTRIBUTE) {
|
|
8754
|
+
const {
|
|
8755
|
+
oldValue
|
|
8756
|
+
} = mutation;
|
|
8766
8757
|
if (oldValue === null) {
|
|
8767
8758
|
const value = targetSlot.getAttribute(attributeName);
|
|
8768
|
-
reasonParts.push(
|
|
8769
|
-
value
|
|
8770
|
-
? `added [${attributeName}=${value}]`
|
|
8771
|
-
: `added [${attributeName}]`,
|
|
8772
|
-
);
|
|
8759
|
+
reasonParts.push(value ? `added [${attributeName}=${value}]` : `added [${attributeName}]`);
|
|
8773
8760
|
} else if (targetSlot.hasAttribute(attributeName)) {
|
|
8774
8761
|
const value = targetSlot.getAttribute(attributeName);
|
|
8775
8762
|
reasonParts.push(`[${attributeName}] ${oldValue} -> ${value}`);
|
|
8776
8763
|
} else {
|
|
8777
|
-
reasonParts.push(
|
|
8778
|
-
oldValue
|
|
8779
|
-
? `removed [${attributeName}=${oldValue}]`
|
|
8780
|
-
: `removed [${attributeName}]`,
|
|
8781
|
-
);
|
|
8764
|
+
reasonParts.push(oldValue ? `removed [${attributeName}=${oldValue}]` : `removed [${attributeName}]`);
|
|
8782
8765
|
}
|
|
8783
8766
|
}
|
|
8784
8767
|
}
|
|
8785
8768
|
}
|
|
8786
|
-
|
|
8787
8769
|
if (reasonParts.length === 0) {
|
|
8788
8770
|
return;
|
|
8789
8771
|
}
|
|
@@ -8793,25 +8775,19 @@ const createUITransitionController = (
|
|
|
8793
8775
|
childList: true,
|
|
8794
8776
|
attributes: true,
|
|
8795
8777
|
attributeFilter: [CONTENT_ID_ATTRIBUTE, CONTENT_PHASE_ATTRIBUTE],
|
|
8796
|
-
characterData: false
|
|
8778
|
+
characterData: false
|
|
8797
8779
|
});
|
|
8798
8780
|
addTeardown(() => {
|
|
8799
8781
|
mutationObserver.disconnect();
|
|
8800
8782
|
});
|
|
8801
8783
|
}
|
|
8802
8784
|
{
|
|
8803
|
-
const slots = [
|
|
8804
|
-
targetSlot,
|
|
8805
|
-
outgoingSlot,
|
|
8806
|
-
previousTargetSlot,
|
|
8807
|
-
previousOutgoingSlot,
|
|
8808
|
-
];
|
|
8785
|
+
const slots = [targetSlot, outgoingSlot, previousTargetSlot, previousOutgoingSlot];
|
|
8809
8786
|
for (const slot of slots) {
|
|
8810
8787
|
addTeardown(monitorItemsOverflow(slot));
|
|
8811
8788
|
}
|
|
8812
8789
|
}
|
|
8813
|
-
|
|
8814
|
-
const setDuration = (newDuration) => {
|
|
8790
|
+
const setDuration = newDuration => {
|
|
8815
8791
|
duration = newDuration;
|
|
8816
8792
|
// Update CSS variable immediately
|
|
8817
8793
|
root.style.setProperty("--x-transition-duration", `${duration}ms`);
|
|
@@ -8821,27 +8797,25 @@ const createUITransitionController = (
|
|
|
8821
8797
|
alignY = newAlignY;
|
|
8822
8798
|
updateAlignment();
|
|
8823
8799
|
};
|
|
8824
|
-
|
|
8825
8800
|
return {
|
|
8826
|
-
updateContentId:
|
|
8801
|
+
updateContentId: value => {
|
|
8827
8802
|
if (value) {
|
|
8828
8803
|
targetSlot.setAttribute(CONTENT_ID_ATTRIBUTE, value);
|
|
8829
8804
|
} else {
|
|
8830
8805
|
targetSlot.removeAttribute(CONTENT_ID_ATTRIBUTE);
|
|
8831
8806
|
}
|
|
8832
8807
|
},
|
|
8833
|
-
|
|
8834
8808
|
transitionTo,
|
|
8835
8809
|
resetContent,
|
|
8836
8810
|
setDuration,
|
|
8837
8811
|
setAlignment,
|
|
8838
8812
|
updateAlignment,
|
|
8839
|
-
setPauseBreakpoints:
|
|
8813
|
+
setPauseBreakpoints: value => {
|
|
8840
8814
|
groupTransitionOptions.pauseBreakpoints = value;
|
|
8841
8815
|
},
|
|
8842
8816
|
cleanup: () => {
|
|
8843
8817
|
teardown();
|
|
8844
|
-
}
|
|
8818
|
+
}
|
|
8845
8819
|
};
|
|
8846
8820
|
};
|
|
8847
8821
|
|
|
@@ -15563,7 +15537,7 @@ const renderIntoCallout = (jsx$1, calloutMessageElement, {
|
|
|
15563
15537
|
render(calloutJsx, calloutMessageElement);
|
|
15564
15538
|
};
|
|
15565
15539
|
|
|
15566
|
-
|
|
15540
|
+
installImportMetaCssBuild(import.meta);
|
|
15567
15541
|
/**
|
|
15568
15542
|
* A callout component that mimics native browser validation messages.
|
|
15569
15543
|
* Features:
|
|
@@ -15574,7 +15548,7 @@ installImportMetaCss(import.meta);
|
|
|
15574
15548
|
* - Centers in viewport when no anchor element provided or anchor is too big
|
|
15575
15549
|
*/
|
|
15576
15550
|
|
|
15577
|
-
import.meta.css = /* css
|
|
15551
|
+
import.meta.css = [/* css */`
|
|
15578
15552
|
@layer navi {
|
|
15579
15553
|
.navi_callout {
|
|
15580
15554
|
--callout-success-color: #4caf50;
|
|
@@ -15716,7 +15690,7 @@ import.meta.css = /* css */ `
|
|
|
15716
15690
|
}
|
|
15717
15691
|
}
|
|
15718
15692
|
}
|
|
15719
|
-
|
|
15693
|
+
`, "/src/field/validation/callout/callout.js"];
|
|
15720
15694
|
|
|
15721
15695
|
/**
|
|
15722
15696
|
* Shows a callout attached to the specified element
|
|
@@ -15734,44 +15708,37 @@ import.meta.css = /* css */ `
|
|
|
15734
15708
|
* - {HTMLElement} element - The callout DOM element
|
|
15735
15709
|
* - {boolean} opened - Whether the callout is currently open
|
|
15736
15710
|
*/
|
|
15737
|
-
const openCallout = (
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
debug = false,
|
|
15752
|
-
} = {},
|
|
15753
|
-
) => {
|
|
15711
|
+
const openCallout = (message, {
|
|
15712
|
+
anchorElement,
|
|
15713
|
+
// status determines visual styling and behavior:
|
|
15714
|
+
// "info" - polite announcement (e.g., "This element cannot be modified")
|
|
15715
|
+
// "warning" - expected failure requiring user action (e.g., "Field is required")
|
|
15716
|
+
// "error" - unexpected failure, may not be actionable (e.g., "Server error")
|
|
15717
|
+
// "success" - positive feedback (e.g., "Changes saved successfully")
|
|
15718
|
+
// "" - neutral information
|
|
15719
|
+
status = "",
|
|
15720
|
+
onClose,
|
|
15721
|
+
closeOnClickOutside = status === "info",
|
|
15722
|
+
showErrorStack,
|
|
15723
|
+
debug = false
|
|
15724
|
+
} = {}) => {
|
|
15754
15725
|
const callout = {
|
|
15755
15726
|
opened: true,
|
|
15756
15727
|
close: null,
|
|
15757
15728
|
status: undefined,
|
|
15758
|
-
|
|
15759
15729
|
update: null,
|
|
15760
15730
|
updatePosition: null,
|
|
15761
|
-
|
|
15762
|
-
element: null,
|
|
15731
|
+
element: null
|
|
15763
15732
|
};
|
|
15764
|
-
|
|
15765
15733
|
if (debug) {
|
|
15766
15734
|
console.debug("open callout", {
|
|
15767
15735
|
anchorElement,
|
|
15768
15736
|
message,
|
|
15769
|
-
status
|
|
15737
|
+
status
|
|
15770
15738
|
});
|
|
15771
15739
|
}
|
|
15772
|
-
|
|
15773
15740
|
const [teardown, addTeardown] = createPubSub(true);
|
|
15774
|
-
const close =
|
|
15741
|
+
const close = reason => {
|
|
15775
15742
|
if (!callout.opened) {
|
|
15776
15743
|
return;
|
|
15777
15744
|
}
|
|
@@ -15784,39 +15751,35 @@ const openCallout = (
|
|
|
15784
15751
|
if (onClose) {
|
|
15785
15752
|
addTeardown(onClose);
|
|
15786
15753
|
}
|
|
15787
|
-
|
|
15788
|
-
const [updateStatus, addStatusEffect, cleanupStatusEffects] =
|
|
15789
|
-
createValueEffect(undefined);
|
|
15754
|
+
const [updateStatus, addStatusEffect, cleanupStatusEffects] = createValueEffect(undefined);
|
|
15790
15755
|
addTeardown(cleanupStatusEffects);
|
|
15791
15756
|
|
|
15792
15757
|
// Create and add callout to document
|
|
15793
15758
|
const calloutElement = createCalloutElement();
|
|
15794
|
-
const calloutMessageElement = calloutElement.querySelector(
|
|
15795
|
-
|
|
15796
|
-
);
|
|
15797
|
-
const calloutCloseButton = calloutElement.querySelector(
|
|
15798
|
-
".navi_callout_close_button",
|
|
15799
|
-
);
|
|
15759
|
+
const calloutMessageElement = calloutElement.querySelector(".navi_callout_message");
|
|
15760
|
+
const calloutCloseButton = calloutElement.querySelector(".navi_callout_close_button");
|
|
15800
15761
|
calloutCloseButton.onclick = () => {
|
|
15801
15762
|
close("click_close_button");
|
|
15802
15763
|
};
|
|
15803
15764
|
const calloutId = `navi_callout_${Date.now()}`;
|
|
15804
15765
|
calloutElement.id = calloutId;
|
|
15805
|
-
calloutStyleController.set(calloutElement, {
|
|
15766
|
+
calloutStyleController.set(calloutElement, {
|
|
15767
|
+
opacity: 0
|
|
15768
|
+
});
|
|
15806
15769
|
const update = (newMessage, options = {}) => {
|
|
15807
15770
|
// Connect callout with target element for accessibility
|
|
15808
15771
|
if (options.status && options.status !== callout.status) {
|
|
15809
15772
|
callout.status = status;
|
|
15810
15773
|
updateStatus(status);
|
|
15811
15774
|
}
|
|
15812
|
-
|
|
15813
15775
|
if (options.closeOnClickOutside) {
|
|
15814
15776
|
closeOnClickOutside = options.closeOnClickOutside;
|
|
15815
15777
|
}
|
|
15816
|
-
|
|
15817
15778
|
if (isValidElement(newMessage)) {
|
|
15818
15779
|
calloutMessageElement.innerHTML = "";
|
|
15819
|
-
renderIntoCallout(newMessage, calloutMessageElement, {
|
|
15780
|
+
renderIntoCallout(newMessage, calloutMessageElement, {
|
|
15781
|
+
close
|
|
15782
|
+
});
|
|
15820
15783
|
} else if (newMessage instanceof Node) {
|
|
15821
15784
|
// Handle DOM node (cloned from CSS selector)
|
|
15822
15785
|
calloutMessageElement.innerHTML = "";
|
|
@@ -15824,9 +15787,10 @@ const openCallout = (
|
|
|
15824
15787
|
} else if (typeof newMessage === "function") {
|
|
15825
15788
|
calloutMessageElement.innerHTML = "";
|
|
15826
15789
|
newMessage({
|
|
15827
|
-
renderIntoCallout: (jsx
|
|
15828
|
-
|
|
15829
|
-
|
|
15790
|
+
renderIntoCallout: jsx => renderIntoCallout(jsx, calloutMessageElement, {
|
|
15791
|
+
close
|
|
15792
|
+
}),
|
|
15793
|
+
close
|
|
15830
15794
|
});
|
|
15831
15795
|
} else {
|
|
15832
15796
|
if (Error.isError(newMessage)) {
|
|
@@ -15855,16 +15819,12 @@ const openCallout = (
|
|
|
15855
15819
|
}
|
|
15856
15820
|
};
|
|
15857
15821
|
{
|
|
15858
|
-
const handleClickOutside =
|
|
15822
|
+
const handleClickOutside = event => {
|
|
15859
15823
|
if (!closeOnClickOutside) {
|
|
15860
15824
|
return;
|
|
15861
15825
|
}
|
|
15862
|
-
|
|
15863
15826
|
const clickTarget = event.target;
|
|
15864
|
-
if (
|
|
15865
|
-
clickTarget === calloutElement ||
|
|
15866
|
-
calloutElement.contains(clickTarget)
|
|
15867
|
-
) {
|
|
15827
|
+
if (clickTarget === calloutElement || calloutElement.contains(clickTarget)) {
|
|
15868
15828
|
return;
|
|
15869
15829
|
}
|
|
15870
15830
|
// if (
|
|
@@ -15884,15 +15844,12 @@ const openCallout = (
|
|
|
15884
15844
|
const handleCustomCloseEvent = () => {
|
|
15885
15845
|
close("custom_event");
|
|
15886
15846
|
};
|
|
15887
|
-
calloutElement.addEventListener(
|
|
15888
|
-
"navi_callout_close",
|
|
15889
|
-
handleCustomCloseEvent,
|
|
15890
|
-
);
|
|
15847
|
+
calloutElement.addEventListener("navi_callout_close", handleCustomCloseEvent);
|
|
15891
15848
|
}
|
|
15892
15849
|
Object.assign(callout, {
|
|
15893
15850
|
element: calloutElement,
|
|
15894
15851
|
update,
|
|
15895
|
-
close
|
|
15852
|
+
close
|
|
15896
15853
|
});
|
|
15897
15854
|
addStatusEffect(() => {
|
|
15898
15855
|
if (status) {
|
|
@@ -15900,7 +15857,6 @@ const openCallout = (
|
|
|
15900
15857
|
} else {
|
|
15901
15858
|
calloutElement.removeAttribute("data-status");
|
|
15902
15859
|
}
|
|
15903
|
-
|
|
15904
15860
|
if (!status || status === "info" || status === "success") {
|
|
15905
15861
|
calloutElement.setAttribute("role", "status");
|
|
15906
15862
|
} else if (status) {
|
|
@@ -15911,39 +15867,31 @@ const openCallout = (
|
|
|
15911
15867
|
addTeardown(() => {
|
|
15912
15868
|
calloutElement.remove();
|
|
15913
15869
|
});
|
|
15914
|
-
|
|
15915
15870
|
if (anchorElement) {
|
|
15916
15871
|
const anchorVisuallyVisibleInfo = getVisuallyVisibleInfo(anchorElement, {
|
|
15917
|
-
countOffscreenAsVisible: true
|
|
15872
|
+
countOffscreenAsVisible: true
|
|
15918
15873
|
});
|
|
15919
15874
|
if (!anchorVisuallyVisibleInfo.visible) {
|
|
15920
|
-
console.warn(
|
|
15921
|
-
`anchor element is not visually visible (${anchorVisuallyVisibleInfo.reason}) -> will be anchored to first visually visible ancestor`,
|
|
15922
|
-
);
|
|
15875
|
+
console.warn(`anchor element is not visually visible (${anchorVisuallyVisibleInfo.reason}) -> will be anchored to first visually visible ancestor`);
|
|
15923
15876
|
anchorElement = getFirstVisuallyVisibleAncestor(anchorElement);
|
|
15924
15877
|
if (!anchorElement) {
|
|
15925
15878
|
// anchorElement is not in the DOM anymore, fallback to body
|
|
15926
15879
|
anchorElement = document.body;
|
|
15927
15880
|
}
|
|
15928
15881
|
}
|
|
15929
|
-
|
|
15930
15882
|
allowWheelThrough(calloutElement, anchorElement);
|
|
15931
15883
|
anchorElement.setAttribute("data-callout", calloutId);
|
|
15932
15884
|
addTeardown(() => {
|
|
15933
15885
|
anchorElement.removeAttribute("data-callout");
|
|
15934
15886
|
});
|
|
15935
|
-
|
|
15936
|
-
addStatusEffect((status) => {
|
|
15887
|
+
addStatusEffect(status => {
|
|
15937
15888
|
if (!status) {
|
|
15938
15889
|
return () => {};
|
|
15939
15890
|
}
|
|
15940
15891
|
// todo:
|
|
15941
15892
|
// - dispatch something on the element to indicate the status
|
|
15942
15893
|
// and that would in turn be used by pseudo styles system to eventually apply styles
|
|
15943
|
-
const statusColor = resolveCSSColor(
|
|
15944
|
-
`var(--callout-${status}-color)`,
|
|
15945
|
-
calloutElement,
|
|
15946
|
-
);
|
|
15894
|
+
const statusColor = resolveCSSColor(`var(--callout-${status}-color)`, calloutElement);
|
|
15947
15895
|
anchorElement.setAttribute("data-callout-status", status);
|
|
15948
15896
|
anchorElement.style.setProperty("--callout-color", statusColor);
|
|
15949
15897
|
return () => {
|
|
@@ -15951,7 +15899,7 @@ const openCallout = (
|
|
|
15951
15899
|
anchorElement.style.removeProperty("--callout-color");
|
|
15952
15900
|
};
|
|
15953
15901
|
});
|
|
15954
|
-
addStatusEffect(
|
|
15902
|
+
addStatusEffect(status => {
|
|
15955
15903
|
if (!status || status === "info" || status === "success") {
|
|
15956
15904
|
anchorElement.setAttribute("aria-describedby", calloutId);
|
|
15957
15905
|
return () => {
|
|
@@ -15965,7 +15913,6 @@ const openCallout = (
|
|
|
15965
15913
|
anchorElement.removeAttribute("aria-invalid");
|
|
15966
15914
|
};
|
|
15967
15915
|
});
|
|
15968
|
-
|
|
15969
15916
|
{
|
|
15970
15917
|
const onfocus = () => {
|
|
15971
15918
|
if (status === "error") {
|
|
@@ -15987,13 +15934,12 @@ const openCallout = (
|
|
|
15987
15934
|
delete anchorElement.callout;
|
|
15988
15935
|
});
|
|
15989
15936
|
}
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15937
|
+
update(message, {
|
|
15938
|
+
status
|
|
15939
|
+
});
|
|
15993
15940
|
{
|
|
15994
15941
|
const documentScrollLeftAtOpen = document.documentElement.scrollLeft;
|
|
15995
15942
|
const documentScrollTopAtOpen = document.documentElement.scrollTop;
|
|
15996
|
-
|
|
15997
15943
|
let positioner;
|
|
15998
15944
|
let strategy;
|
|
15999
15945
|
const determine = () => {
|
|
@@ -16018,7 +15964,7 @@ const openCallout = (
|
|
|
16018
15964
|
if (newStrategy === "centered") {
|
|
16019
15965
|
positioner = centerCalloutInViewport(calloutElement, {
|
|
16020
15966
|
documentScrollLeftAtOpen,
|
|
16021
|
-
documentScrollTopAtOpen
|
|
15967
|
+
documentScrollTopAtOpen
|
|
16022
15968
|
});
|
|
16023
15969
|
} else {
|
|
16024
15970
|
positioner = stickCalloutToAnchor(calloutElement, anchorElement);
|
|
@@ -16040,7 +15986,6 @@ const openCallout = (
|
|
|
16040
15986
|
}
|
|
16041
15987
|
callout.updatePosition = () => positioner.update();
|
|
16042
15988
|
}
|
|
16043
|
-
|
|
16044
15989
|
return callout;
|
|
16045
15990
|
};
|
|
16046
15991
|
|
|
@@ -16052,7 +15997,7 @@ const ARROW_HEIGHT = 8;
|
|
|
16052
15997
|
const ARROW_SPACING = 8;
|
|
16053
15998
|
|
|
16054
15999
|
// HTML template for the callout
|
|
16055
|
-
const calloutTemplate = /* html
|
|
16000
|
+
const calloutTemplate = /* html */`
|
|
16056
16001
|
<div class="navi_callout">
|
|
16057
16002
|
<div class="navi_callout_box">
|
|
16058
16003
|
<div class="navi_callout_frame"></div>
|
|
@@ -16087,7 +16032,6 @@ const calloutTemplate = /* html */ `
|
|
|
16087
16032
|
</div>
|
|
16088
16033
|
</div>
|
|
16089
16034
|
`;
|
|
16090
|
-
|
|
16091
16035
|
const calloutStyleController = createStyleController("callout");
|
|
16092
16036
|
|
|
16093
16037
|
/**
|
|
@@ -16100,20 +16044,15 @@ const createCalloutElement = () => {
|
|
|
16100
16044
|
const calloutElement = div.firstElementChild;
|
|
16101
16045
|
return calloutElement;
|
|
16102
16046
|
};
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
) => {
|
|
16047
|
+
const centerCalloutInViewport = (calloutElement, {
|
|
16048
|
+
documentScrollLeftAtOpen,
|
|
16049
|
+
documentScrollTopAtOpen
|
|
16050
|
+
}) => {
|
|
16108
16051
|
// Set up initial styles for centered positioning
|
|
16109
16052
|
const calloutBoxElement = calloutElement.querySelector(".navi_callout_box");
|
|
16110
|
-
const calloutFrameElement = calloutElement.querySelector(
|
|
16111
|
-
".navi_callout_frame",
|
|
16112
|
-
);
|
|
16053
|
+
const calloutFrameElement = calloutElement.querySelector(".navi_callout_frame");
|
|
16113
16054
|
const calloutBodyElement = calloutElement.querySelector(".navi_callout_body");
|
|
16114
|
-
const calloutMessageElement = calloutElement.querySelector(
|
|
16115
|
-
".navi_callout_message",
|
|
16116
|
-
);
|
|
16055
|
+
const calloutMessageElement = calloutElement.querySelector(".navi_callout_message");
|
|
16117
16056
|
|
|
16118
16057
|
// Remove any margins and set frame positioning for no arrow
|
|
16119
16058
|
calloutBoxElement.style.marginTop = "";
|
|
@@ -16126,9 +16065,10 @@ const centerCalloutInViewport = (
|
|
|
16126
16065
|
|
|
16127
16066
|
// Generate simple rectangle SVG without arrow and position in center
|
|
16128
16067
|
const updateCenteredPosition = () => {
|
|
16129
|
-
const calloutElementClone =
|
|
16130
|
-
|
|
16131
|
-
|
|
16068
|
+
const calloutElementClone = cloneCalloutToMeasureNaturalSize(calloutElement);
|
|
16069
|
+
const {
|
|
16070
|
+
height
|
|
16071
|
+
} = calloutElementClone.getBoundingClientRect();
|
|
16132
16072
|
calloutElementClone.remove();
|
|
16133
16073
|
|
|
16134
16074
|
// Handle content overflow when viewport is too small
|
|
@@ -16139,8 +16079,7 @@ const centerCalloutInViewport = (
|
|
|
16139
16079
|
const paddingSizes = getPaddingSizes(calloutBodyElement);
|
|
16140
16080
|
const paddingY = paddingSizes.top + paddingSizes.bottom;
|
|
16141
16081
|
const spaceNeededAroundContent = BORDER_WIDTH * 2 + paddingY;
|
|
16142
|
-
const spaceAvailableForContent =
|
|
16143
|
-
maxAllowedHeight - spaceNeededAroundContent;
|
|
16082
|
+
const spaceAvailableForContent = maxAllowedHeight - spaceNeededAroundContent;
|
|
16144
16083
|
calloutMessageElement.style.maxHeight = `${spaceAvailableForContent}px`;
|
|
16145
16084
|
calloutMessageElement.style.overflowY = "scroll";
|
|
16146
16085
|
} else {
|
|
@@ -16150,24 +16089,22 @@ const centerCalloutInViewport = (
|
|
|
16150
16089
|
}
|
|
16151
16090
|
|
|
16152
16091
|
// Get final dimensions after potential overflow adjustments
|
|
16153
|
-
const {
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
);
|
|
16092
|
+
const {
|
|
16093
|
+
width: finalWidth,
|
|
16094
|
+
height: finalHeight
|
|
16095
|
+
} = calloutElement.getBoundingClientRect();
|
|
16096
|
+
calloutFrameElement.innerHTML = generateSvgWithoutArrow(finalWidth, finalHeight);
|
|
16159
16097
|
|
|
16160
16098
|
// Center in viewport (accounting for document scroll)
|
|
16161
16099
|
const viewportWidth = window.innerWidth;
|
|
16162
16100
|
const left = documentScrollLeftAtOpen + (viewportWidth - finalWidth) / 2;
|
|
16163
16101
|
const top = documentScrollTopAtOpen + (viewportHeight - finalHeight) / 2;
|
|
16164
|
-
|
|
16165
16102
|
calloutStyleController.set(calloutElement, {
|
|
16166
16103
|
opacity: 1,
|
|
16167
16104
|
transform: {
|
|
16168
16105
|
translateX: left,
|
|
16169
|
-
translateY: top
|
|
16170
|
-
}
|
|
16106
|
+
translateY: top
|
|
16107
|
+
}
|
|
16171
16108
|
});
|
|
16172
16109
|
};
|
|
16173
16110
|
|
|
@@ -16180,7 +16117,7 @@ const centerCalloutInViewport = (
|
|
|
16180
16117
|
update: updateCenteredPosition,
|
|
16181
16118
|
stop: () => {
|
|
16182
16119
|
window.removeEventListener("resize", updateCenteredPosition);
|
|
16183
|
-
}
|
|
16120
|
+
}
|
|
16184
16121
|
};
|
|
16185
16122
|
};
|
|
16186
16123
|
|
|
@@ -16193,156 +16130,127 @@ const centerCalloutInViewport = (
|
|
|
16193
16130
|
const stickCalloutToAnchor = (calloutElement, anchorElement) => {
|
|
16194
16131
|
// Get references to callout parts
|
|
16195
16132
|
const calloutBoxElement = calloutElement.querySelector(".navi_callout_box");
|
|
16196
|
-
const calloutFrameElement = calloutElement.querySelector(
|
|
16197
|
-
".navi_callout_frame",
|
|
16198
|
-
);
|
|
16133
|
+
const calloutFrameElement = calloutElement.querySelector(".navi_callout_frame");
|
|
16199
16134
|
const calloutBodyElement = calloutElement.querySelector(".navi_callout_body");
|
|
16200
|
-
const calloutMessageElement = calloutElement.querySelector(
|
|
16201
|
-
".navi_callout_message",
|
|
16202
|
-
);
|
|
16135
|
+
const calloutMessageElement = calloutElement.querySelector(".navi_callout_message");
|
|
16203
16136
|
|
|
16204
16137
|
// Set initial border styles
|
|
16205
16138
|
calloutBoxElement.style.borderWidth = `${BORDER_WIDTH}px`;
|
|
16206
16139
|
calloutFrameElement.style.left = `-${BORDER_WIDTH}px`;
|
|
16207
16140
|
calloutFrameElement.style.right = `-${BORDER_WIDTH}px`;
|
|
16141
|
+
const anchorVisibleRectEffect = visibleRectEffect(anchorElement, ({
|
|
16142
|
+
left: anchorLeft,
|
|
16143
|
+
right: anchorRight,
|
|
16144
|
+
visibilityRatio
|
|
16145
|
+
}) => {
|
|
16146
|
+
const calloutElementClone = cloneCalloutToMeasureNaturalSize(calloutElement);
|
|
16147
|
+
// Check for preferred and forced position from anchor element
|
|
16148
|
+
const preferredPosition = anchorElement.getAttribute("data-callout-position");
|
|
16149
|
+
const forcedPosition = anchorElement.getAttribute("data-callout-position-force");
|
|
16150
|
+
const {
|
|
16151
|
+
position,
|
|
16152
|
+
left: calloutLeft,
|
|
16153
|
+
top: calloutTop,
|
|
16154
|
+
width: calloutWidth,
|
|
16155
|
+
height: calloutHeight,
|
|
16156
|
+
spaceAboveTarget,
|
|
16157
|
+
spaceBelowTarget
|
|
16158
|
+
} = pickPositionRelativeTo(calloutElementClone, anchorElement, {
|
|
16159
|
+
alignToViewportEdgeWhenTargetNearEdge: 20,
|
|
16160
|
+
// when fully to the left, the border color is collé to the browser window making it hard to see
|
|
16161
|
+
minLeft: 1,
|
|
16162
|
+
positionPreference:
|
|
16163
|
+
// we want to avoid the callout to switch position when it can still fit so
|
|
16164
|
+
// we start with preferredPosition if given but once a position is picked we stick to it
|
|
16165
|
+
// This is implemented by favoring the data attribute of the callout then of the anchor
|
|
16166
|
+
calloutElement.getAttribute("data-position") || preferredPosition,
|
|
16167
|
+
forcePosition: forcedPosition
|
|
16168
|
+
});
|
|
16169
|
+
calloutElementClone.remove();
|
|
16208
16170
|
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16212
|
-
|
|
16213
|
-
|
|
16214
|
-
|
|
16215
|
-
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
const
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
const
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
|
|
16234
|
-
|
|
16235
|
-
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
|
|
16240
|
-
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
|
|
16249
|
-
|
|
16250
|
-
|
|
16251
|
-
|
|
16252
|
-
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
}
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16286
|
-
const spaceAvailable =
|
|
16287
|
-
position === "below" ? spaceBelowTarget : spaceAboveTarget;
|
|
16288
|
-
const paddingSizes = getPaddingSizes(calloutBodyElement);
|
|
16289
|
-
const paddingY = paddingSizes.top + paddingSizes.bottom;
|
|
16290
|
-
const spaceNeededAroundContent =
|
|
16291
|
-
ARROW_HEIGHT + BORDER_WIDTH * 2 + paddingY;
|
|
16292
|
-
const spaceAvailableForContent =
|
|
16293
|
-
spaceAvailable - spaceNeededAroundContent;
|
|
16294
|
-
const contentHeight = calloutHeight - spaceNeededAroundContent;
|
|
16295
|
-
const spaceRemainingAfterContent =
|
|
16296
|
-
spaceAvailableForContent - contentHeight;
|
|
16297
|
-
if (spaceRemainingAfterContent < 2) {
|
|
16298
|
-
const maxHeight = spaceAvailableForContent;
|
|
16299
|
-
calloutMessageElement.style.maxHeight = `${maxHeight}px`;
|
|
16300
|
-
calloutMessageElement.style.overflowY = "scroll";
|
|
16301
|
-
} else {
|
|
16302
|
-
calloutMessageElement.style.maxHeight = "";
|
|
16303
|
-
calloutMessageElement.style.overflowY = "";
|
|
16304
|
-
}
|
|
16305
|
-
|
|
16306
|
-
const { width, height } = calloutElement.getBoundingClientRect();
|
|
16307
|
-
if (position === "above") {
|
|
16308
|
-
// Position above target element
|
|
16309
|
-
calloutBoxElement.style.marginTop = "";
|
|
16310
|
-
calloutBoxElement.style.marginBottom = `${ARROW_HEIGHT}px`;
|
|
16311
|
-
calloutFrameElement.style.top = `-${BORDER_WIDTH}px`;
|
|
16312
|
-
calloutFrameElement.style.bottom = `-${BORDER_WIDTH + ARROW_HEIGHT - 0.5}px`;
|
|
16313
|
-
calloutFrameElement.innerHTML = generateSvgWithBottomArrow(
|
|
16314
|
-
width,
|
|
16315
|
-
height,
|
|
16316
|
-
arrowLeftPosOnCallout,
|
|
16317
|
-
);
|
|
16318
|
-
} else {
|
|
16319
|
-
calloutBoxElement.style.marginTop = `${ARROW_HEIGHT}px`;
|
|
16320
|
-
calloutBoxElement.style.marginBottom = "";
|
|
16321
|
-
calloutFrameElement.style.top = `-${BORDER_WIDTH + ARROW_HEIGHT - 0.5}px`;
|
|
16322
|
-
calloutFrameElement.style.bottom = `-${BORDER_WIDTH}px`;
|
|
16323
|
-
calloutFrameElement.innerHTML = generateSvgWithTopArrow(
|
|
16324
|
-
width,
|
|
16325
|
-
height,
|
|
16326
|
-
arrowLeftPosOnCallout,
|
|
16327
|
-
);
|
|
16171
|
+
// Calculate arrow position to point at anchorElement element
|
|
16172
|
+
let arrowLeftPosOnCallout;
|
|
16173
|
+
// Determine arrow target position based on attribute
|
|
16174
|
+
const arrowPositionAttribute = anchorElement.getAttribute("data-callout-arrow-x");
|
|
16175
|
+
let arrowAnchorLeft;
|
|
16176
|
+
if (arrowPositionAttribute === "center") {
|
|
16177
|
+
// Target the center of the anchorElement element
|
|
16178
|
+
arrowAnchorLeft = (anchorLeft + anchorRight) / 2;
|
|
16179
|
+
} else if (arrowPositionAttribute === "end") {
|
|
16180
|
+
const anchorBorderSizes = getBorderSizes(anchorElement);
|
|
16181
|
+
// Target the right edge of the anchorElement element (before borders)
|
|
16182
|
+
arrowAnchorLeft = anchorRight - anchorBorderSizes.right;
|
|
16183
|
+
} else {
|
|
16184
|
+
const anchorBorderSizes = getBorderSizes(anchorElement);
|
|
16185
|
+
// Default behavior: target the left edge of the anchorElement element (after borders)
|
|
16186
|
+
arrowAnchorLeft = anchorLeft + anchorBorderSizes.left;
|
|
16187
|
+
}
|
|
16188
|
+
|
|
16189
|
+
// Calculate arrow position within the callout
|
|
16190
|
+
if (calloutLeft < arrowAnchorLeft) {
|
|
16191
|
+
// Callout is left of the target point, move arrow right
|
|
16192
|
+
const diff = arrowAnchorLeft - calloutLeft;
|
|
16193
|
+
arrowLeftPosOnCallout = diff;
|
|
16194
|
+
} else if (calloutLeft + calloutWidth < arrowAnchorLeft) {
|
|
16195
|
+
// Edge case: target point is beyond right edge of callout
|
|
16196
|
+
arrowLeftPosOnCallout = calloutWidth - ARROW_WIDTH;
|
|
16197
|
+
} else {
|
|
16198
|
+
// Target point is within callout width
|
|
16199
|
+
arrowLeftPosOnCallout = arrowAnchorLeft - calloutLeft;
|
|
16200
|
+
}
|
|
16201
|
+
|
|
16202
|
+
// Ensure arrow stays within callout bounds with some padding
|
|
16203
|
+
const minArrowPos = CORNER_RADIUS + ARROW_WIDTH / 2 + ARROW_SPACING;
|
|
16204
|
+
const maxArrowPos = calloutWidth - minArrowPos;
|
|
16205
|
+
arrowLeftPosOnCallout = Math.max(minArrowPos, Math.min(arrowLeftPosOnCallout, maxArrowPos));
|
|
16206
|
+
|
|
16207
|
+
// Force content overflow when there is not enough space to display
|
|
16208
|
+
// the entirety of the callout
|
|
16209
|
+
const spaceAvailable = position === "below" ? spaceBelowTarget : spaceAboveTarget;
|
|
16210
|
+
const paddingSizes = getPaddingSizes(calloutBodyElement);
|
|
16211
|
+
const paddingY = paddingSizes.top + paddingSizes.bottom;
|
|
16212
|
+
const spaceNeededAroundContent = ARROW_HEIGHT + BORDER_WIDTH * 2 + paddingY;
|
|
16213
|
+
const spaceAvailableForContent = spaceAvailable - spaceNeededAroundContent;
|
|
16214
|
+
const contentHeight = calloutHeight - spaceNeededAroundContent;
|
|
16215
|
+
const spaceRemainingAfterContent = spaceAvailableForContent - contentHeight;
|
|
16216
|
+
if (spaceRemainingAfterContent < 2) {
|
|
16217
|
+
const maxHeight = spaceAvailableForContent;
|
|
16218
|
+
calloutMessageElement.style.maxHeight = `${maxHeight}px`;
|
|
16219
|
+
calloutMessageElement.style.overflowY = "scroll";
|
|
16220
|
+
} else {
|
|
16221
|
+
calloutMessageElement.style.maxHeight = "";
|
|
16222
|
+
calloutMessageElement.style.overflowY = "";
|
|
16223
|
+
}
|
|
16224
|
+
const {
|
|
16225
|
+
width,
|
|
16226
|
+
height
|
|
16227
|
+
} = calloutElement.getBoundingClientRect();
|
|
16228
|
+
if (position === "above") {
|
|
16229
|
+
// Position above target element
|
|
16230
|
+
calloutBoxElement.style.marginTop = "";
|
|
16231
|
+
calloutBoxElement.style.marginBottom = `${ARROW_HEIGHT}px`;
|
|
16232
|
+
calloutFrameElement.style.top = `-${BORDER_WIDTH}px`;
|
|
16233
|
+
calloutFrameElement.style.bottom = `-${BORDER_WIDTH + ARROW_HEIGHT - 0.5}px`;
|
|
16234
|
+
calloutFrameElement.innerHTML = generateSvgWithBottomArrow(width, height, arrowLeftPosOnCallout);
|
|
16235
|
+
} else {
|
|
16236
|
+
calloutBoxElement.style.marginTop = `${ARROW_HEIGHT}px`;
|
|
16237
|
+
calloutBoxElement.style.marginBottom = "";
|
|
16238
|
+
calloutFrameElement.style.top = `-${BORDER_WIDTH + ARROW_HEIGHT - 0.5}px`;
|
|
16239
|
+
calloutFrameElement.style.bottom = `-${BORDER_WIDTH}px`;
|
|
16240
|
+
calloutFrameElement.innerHTML = generateSvgWithTopArrow(width, height, arrowLeftPosOnCallout);
|
|
16241
|
+
}
|
|
16242
|
+
calloutElement.setAttribute("data-position", position);
|
|
16243
|
+
calloutStyleController.set(calloutElement, {
|
|
16244
|
+
opacity: visibilityRatio ? 1 : 0,
|
|
16245
|
+
transform: {
|
|
16246
|
+
translateX: calloutLeft,
|
|
16247
|
+
translateY: calloutTop
|
|
16328
16248
|
}
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
translateX: calloutLeft,
|
|
16335
|
-
translateY: calloutTop,
|
|
16336
|
-
},
|
|
16337
|
-
});
|
|
16338
|
-
},
|
|
16339
|
-
);
|
|
16340
|
-
const calloutSizeChangeObserver = observeCalloutSizeChange(
|
|
16341
|
-
calloutMessageElement,
|
|
16342
|
-
(width, height) => {
|
|
16343
|
-
anchorVisibleRectEffect.check(`callout_size_change (${width}x${height})`);
|
|
16344
|
-
},
|
|
16345
|
-
);
|
|
16249
|
+
});
|
|
16250
|
+
});
|
|
16251
|
+
const calloutSizeChangeObserver = observeCalloutSizeChange(calloutMessageElement, (width, height) => {
|
|
16252
|
+
anchorVisibleRectEffect.check(`callout_size_change (${width}x${height})`);
|
|
16253
|
+
});
|
|
16346
16254
|
anchorVisibleRectEffect.onBeforeAutoCheck(() => {
|
|
16347
16255
|
// prevent feedback loop because check triggers size change which triggers check...
|
|
16348
16256
|
calloutSizeChangeObserver.disable();
|
|
@@ -16350,22 +16258,23 @@ const stickCalloutToAnchor = (calloutElement, anchorElement) => {
|
|
|
16350
16258
|
calloutSizeChangeObserver.enable();
|
|
16351
16259
|
};
|
|
16352
16260
|
});
|
|
16353
|
-
|
|
16354
16261
|
return {
|
|
16355
16262
|
update: anchorVisibleRectEffect.check,
|
|
16356
16263
|
stop: () => {
|
|
16357
16264
|
calloutSizeChangeObserver.disconnect();
|
|
16358
16265
|
anchorVisibleRectEffect.disconnect();
|
|
16359
|
-
}
|
|
16266
|
+
}
|
|
16360
16267
|
};
|
|
16361
16268
|
};
|
|
16362
|
-
|
|
16363
16269
|
const observeCalloutSizeChange = (elementSizeToObserve, callback) => {
|
|
16364
16270
|
let lastContentWidth;
|
|
16365
16271
|
let lastContentHeight;
|
|
16366
|
-
const resizeObserver = new ResizeObserver(
|
|
16272
|
+
const resizeObserver = new ResizeObserver(entries => {
|
|
16367
16273
|
const [entry] = entries;
|
|
16368
|
-
const {
|
|
16274
|
+
const {
|
|
16275
|
+
width,
|
|
16276
|
+
height
|
|
16277
|
+
} = entry.contentRect;
|
|
16369
16278
|
// Debounce tiny changes that are likely sub-pixel rounding
|
|
16370
16279
|
if (lastContentWidth !== undefined) {
|
|
16371
16280
|
const widthDiff = Math.abs(width - lastContentWidth);
|
|
@@ -16380,7 +16289,6 @@ const observeCalloutSizeChange = (elementSizeToObserve, callback) => {
|
|
|
16380
16289
|
callback(width, height);
|
|
16381
16290
|
});
|
|
16382
16291
|
resizeObserver.observe(elementSizeToObserve);
|
|
16383
|
-
|
|
16384
16292
|
return {
|
|
16385
16293
|
disable: () => {
|
|
16386
16294
|
resizeObserver.unobserve(elementSizeToObserve);
|
|
@@ -16390,17 +16298,11 @@ const observeCalloutSizeChange = (elementSizeToObserve, callback) => {
|
|
|
16390
16298
|
},
|
|
16391
16299
|
disconnect: () => {
|
|
16392
16300
|
resizeObserver.disconnect();
|
|
16393
|
-
}
|
|
16301
|
+
}
|
|
16394
16302
|
};
|
|
16395
16303
|
};
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
return string
|
|
16399
|
-
.replace(/&/g, "&")
|
|
16400
|
-
.replace(/</g, "<")
|
|
16401
|
-
.replace(/>/g, ">")
|
|
16402
|
-
.replace(/"/g, """)
|
|
16403
|
-
.replace(/'/g, "'");
|
|
16304
|
+
const escapeHtml = string => {
|
|
16305
|
+
return string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
16404
16306
|
};
|
|
16405
16307
|
|
|
16406
16308
|
/**
|
|
@@ -16408,7 +16310,7 @@ const escapeHtml = (string) => {
|
|
|
16408
16310
|
* @param {string} content - The content to check
|
|
16409
16311
|
* @returns {boolean} - True if it looks like a complete HTML document
|
|
16410
16312
|
*/
|
|
16411
|
-
const isHtmlDocument =
|
|
16313
|
+
const isHtmlDocument = content => {
|
|
16412
16314
|
if (typeof content !== "string") {
|
|
16413
16315
|
return false;
|
|
16414
16316
|
}
|
|
@@ -16418,20 +16320,17 @@ const isHtmlDocument = (content) => {
|
|
|
16418
16320
|
};
|
|
16419
16321
|
|
|
16420
16322
|
// It's ok to do this because the element is absolutely positioned
|
|
16421
|
-
const cloneCalloutToMeasureNaturalSize =
|
|
16323
|
+
const cloneCalloutToMeasureNaturalSize = calloutElement => {
|
|
16422
16324
|
// Create invisible clone to measure natural size
|
|
16423
16325
|
const calloutElementClone = calloutElement.cloneNode(true);
|
|
16424
16326
|
calloutElementClone.style.visibility = "hidden";
|
|
16425
|
-
const calloutMessageElementClone = calloutElementClone.querySelector(
|
|
16426
|
-
".navi_callout_message",
|
|
16427
|
-
);
|
|
16327
|
+
const calloutMessageElementClone = calloutElementClone.querySelector(".navi_callout_message");
|
|
16428
16328
|
// Reset any overflow constraints on the clone
|
|
16429
16329
|
calloutMessageElementClone.style.maxHeight = "";
|
|
16430
16330
|
calloutMessageElementClone.style.overflowY = "";
|
|
16431
16331
|
|
|
16432
16332
|
// Add clone to DOM to measure
|
|
16433
16333
|
calloutElement.parentNode.appendChild(calloutElementClone);
|
|
16434
|
-
|
|
16435
16334
|
return calloutElementClone;
|
|
16436
16335
|
};
|
|
16437
16336
|
|
|
@@ -16444,14 +16343,10 @@ const cloneCalloutToMeasureNaturalSize = (calloutElement) => {
|
|
|
16444
16343
|
*/
|
|
16445
16344
|
const generateSvgWithTopArrow = (width, height, arrowPosition) => {
|
|
16446
16345
|
// Calculate valid arrow position range
|
|
16447
|
-
const arrowLeft =
|
|
16448
|
-
ARROW_WIDTH / 2 + CORNER_RADIUS + BORDER_WIDTH + ARROW_SPACING;
|
|
16346
|
+
const arrowLeft = ARROW_WIDTH / 2 + CORNER_RADIUS + BORDER_WIDTH + ARROW_SPACING;
|
|
16449
16347
|
const minArrowPos = arrowLeft;
|
|
16450
16348
|
const maxArrowPos = width - arrowLeft;
|
|
16451
|
-
const constrainedArrowPos = Math.max(
|
|
16452
|
-
minArrowPos,
|
|
16453
|
-
Math.min(arrowPosition, maxArrowPos),
|
|
16454
|
-
);
|
|
16349
|
+
const constrainedArrowPos = Math.max(minArrowPos, Math.min(arrowPosition, maxArrowPos));
|
|
16455
16350
|
|
|
16456
16351
|
// Calculate content height
|
|
16457
16352
|
const contentHeight = height - ARROW_HEIGHT;
|
|
@@ -16495,8 +16390,7 @@ const generateSvgWithTopArrow = (width, height, arrowPosition) => {
|
|
|
16495
16390
|
V${ARROW_HEIGHT + innerRadius + BORDER_WIDTH}
|
|
16496
16391
|
Q${BORDER_WIDTH},${ARROW_HEIGHT + BORDER_WIDTH} ${innerRadius + BORDER_WIDTH},${ARROW_HEIGHT + BORDER_WIDTH}
|
|
16497
16392
|
`;
|
|
16498
|
-
|
|
16499
|
-
return /* html */ `
|
|
16393
|
+
return /* html */`
|
|
16500
16394
|
<svg
|
|
16501
16395
|
width="${adjustedWidth}"
|
|
16502
16396
|
height="${adjustedHeight}"
|
|
@@ -16520,14 +16414,10 @@ const generateSvgWithTopArrow = (width, height, arrowPosition) => {
|
|
|
16520
16414
|
*/
|
|
16521
16415
|
const generateSvgWithBottomArrow = (width, height, arrowPosition) => {
|
|
16522
16416
|
// Calculate valid arrow position range
|
|
16523
|
-
const arrowLeft =
|
|
16524
|
-
ARROW_WIDTH / 2 + CORNER_RADIUS + BORDER_WIDTH + ARROW_SPACING;
|
|
16417
|
+
const arrowLeft = ARROW_WIDTH / 2 + CORNER_RADIUS + BORDER_WIDTH + ARROW_SPACING;
|
|
16525
16418
|
const minArrowPos = arrowLeft;
|
|
16526
16419
|
const maxArrowPos = width - arrowLeft;
|
|
16527
|
-
const constrainedArrowPos = Math.max(
|
|
16528
|
-
minArrowPos,
|
|
16529
|
-
Math.min(arrowPosition, maxArrowPos),
|
|
16530
|
-
);
|
|
16420
|
+
const constrainedArrowPos = Math.max(minArrowPos, Math.min(arrowPosition, maxArrowPos));
|
|
16531
16421
|
|
|
16532
16422
|
// Calculate content height
|
|
16533
16423
|
const contentHeight = height - ARROW_HEIGHT;
|
|
@@ -16571,8 +16461,7 @@ const generateSvgWithBottomArrow = (width, height, arrowPosition) => {
|
|
|
16571
16461
|
V${innerRadius + BORDER_WIDTH}
|
|
16572
16462
|
Q${BORDER_WIDTH},${BORDER_WIDTH} ${innerRadius + BORDER_WIDTH},${BORDER_WIDTH}
|
|
16573
16463
|
`;
|
|
16574
|
-
|
|
16575
|
-
return /* html */ `
|
|
16464
|
+
return /* html */`
|
|
16576
16465
|
<svg
|
|
16577
16466
|
width="${adjustedWidth}"
|
|
16578
16467
|
height="${adjustedHeight}"
|
|
@@ -16594,7 +16483,7 @@ const generateSvgWithBottomArrow = (width, height, arrowPosition) => {
|
|
|
16594
16483
|
* @returns {string} - SVG markup
|
|
16595
16484
|
*/
|
|
16596
16485
|
const generateSvgWithoutArrow = (width, height) => {
|
|
16597
|
-
return /* html
|
|
16486
|
+
return /* html */`
|
|
16598
16487
|
<svg
|
|
16599
16488
|
width="${width}"
|
|
16600
16489
|
height="${height}"
|
|
@@ -18894,7 +18783,8 @@ const selectByTextStrings = (element, range, startText, endText) => {
|
|
|
18894
18783
|
}
|
|
18895
18784
|
};
|
|
18896
18785
|
|
|
18897
|
-
|
|
18786
|
+
installImportMetaCssBuild(import.meta);/* eslint-disable jsenv/no-unknown-params */
|
|
18787
|
+
import.meta.css = [/* css */`
|
|
18898
18788
|
*[data-navi-space] {
|
|
18899
18789
|
/* user-select: none; */
|
|
18900
18790
|
padding-left: 0.25em;
|
|
@@ -19003,7 +18893,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
19003
18893
|
transition-timing-function: ease;
|
|
19004
18894
|
}
|
|
19005
18895
|
}
|
|
19006
|
-
|
|
18896
|
+
`, "/src/text/text.jsx"];
|
|
19007
18897
|
|
|
19008
18898
|
// We could use <span data-navi-space=""> </span>
|
|
19009
18899
|
// but we prefer to use zero width space as it has the nice side effects of
|
|
@@ -19150,6 +19040,7 @@ const TextOverflow = ({
|
|
|
19150
19040
|
pre: !noWrap
|
|
19151
19041
|
// For paragraph we prefer to keep lines and only hide unbreakable long sections
|
|
19152
19042
|
,
|
|
19043
|
+
|
|
19153
19044
|
preLine: rest.as === "p",
|
|
19154
19045
|
...rest,
|
|
19155
19046
|
"data-text-overflow": true,
|
|
@@ -19268,7 +19159,7 @@ const TextBasic = ({
|
|
|
19268
19159
|
});
|
|
19269
19160
|
};
|
|
19270
19161
|
|
|
19271
|
-
|
|
19162
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
19272
19163
|
@layer navi {
|
|
19273
19164
|
/* Ensure data attributes from box.jsx can win to update display */
|
|
19274
19165
|
.navi_icon {
|
|
@@ -19343,7 +19234,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
19343
19234
|
width: 100%;
|
|
19344
19235
|
height: 100%;
|
|
19345
19236
|
}
|
|
19346
|
-
|
|
19237
|
+
`, "/src/graphic/icon.jsx"];
|
|
19347
19238
|
const Icon = ({
|
|
19348
19239
|
href,
|
|
19349
19240
|
children,
|
|
@@ -19637,7 +19528,23 @@ const setupNetworkMonitoring = () => {
|
|
|
19637
19528
|
};
|
|
19638
19529
|
setupNetworkMonitoring();
|
|
19639
19530
|
|
|
19640
|
-
|
|
19531
|
+
installImportMetaCssBuild(import.meta);/**
|
|
19532
|
+
* RectangleLoading Component
|
|
19533
|
+
*
|
|
19534
|
+
* A responsive loading indicator that dynamically adjusts to fit its container.
|
|
19535
|
+
* Displays an animated outline with a traveling dot that follows the container's shape.
|
|
19536
|
+
*
|
|
19537
|
+
* Features:
|
|
19538
|
+
* - Adapts to any container dimensions using ResizeObserver
|
|
19539
|
+
* - Scales stroke width, margins and corner radius proportionally
|
|
19540
|
+
* - Animates using native SVG animations for smooth performance
|
|
19541
|
+
* - High-quality SVG rendering with proper path calculations
|
|
19542
|
+
*
|
|
19543
|
+
* @param {Object} props - Component props
|
|
19544
|
+
* @param {string} [props.color="#383a36"] - Color of the loading indicator
|
|
19545
|
+
* @param {number} [props.radius=0] - Corner radius of the rectangle (px)
|
|
19546
|
+
*/
|
|
19547
|
+
import.meta.css = [/* css */`
|
|
19641
19548
|
.navi_rectangle_loading {
|
|
19642
19549
|
position: relative;
|
|
19643
19550
|
display: flex;
|
|
@@ -19649,7 +19556,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
19649
19556
|
.navi_rectangle_loading[data-visible] {
|
|
19650
19557
|
opacity: 1;
|
|
19651
19558
|
}
|
|
19652
|
-
|
|
19559
|
+
`, "/src/graphic/loader/rectangle_loading.jsx"];
|
|
19653
19560
|
const RectangleLoading = ({
|
|
19654
19561
|
shouldShowSpinner,
|
|
19655
19562
|
color = "currentColor",
|
|
@@ -19836,7 +19743,7 @@ const RectangleLoadingSvg = ({
|
|
|
19836
19743
|
});
|
|
19837
19744
|
};
|
|
19838
19745
|
|
|
19839
|
-
|
|
19746
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
19840
19747
|
.navi_loading_rectangle_wrapper {
|
|
19841
19748
|
position: absolute;
|
|
19842
19749
|
top: var(--rectangle-top, 0);
|
|
@@ -19851,7 +19758,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
19851
19758
|
opacity: 1;
|
|
19852
19759
|
}
|
|
19853
19760
|
}
|
|
19854
|
-
|
|
19761
|
+
`, "/src/graphic/loader/loader_background.jsx"];
|
|
19855
19762
|
const LoaderBackground = ({
|
|
19856
19763
|
loading,
|
|
19857
19764
|
containerRef,
|
|
@@ -21213,7 +21120,7 @@ const useUIState = (uiStateController) => {
|
|
|
21213
21120
|
return trackedUIState;
|
|
21214
21121
|
};
|
|
21215
21122
|
|
|
21216
|
-
|
|
21123
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
21217
21124
|
@layer navi {
|
|
21218
21125
|
.navi_button {
|
|
21219
21126
|
--button-outline-width: 1px;
|
|
@@ -21448,7 +21355,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
21448
21355
|
--x-button-border-color: var(--callout-color);
|
|
21449
21356
|
}
|
|
21450
21357
|
}
|
|
21451
|
-
|
|
21358
|
+
`, "/src/field/button.jsx"];
|
|
21452
21359
|
const Button = props => {
|
|
21453
21360
|
return renderActionableComponent(props, {
|
|
21454
21361
|
Basic: ButtonBasic,
|
|
@@ -21537,6 +21444,7 @@ const ButtonBasic = props => {
|
|
|
21537
21444
|
"aria-busy": innerLoading
|
|
21538
21445
|
// style management
|
|
21539
21446
|
,
|
|
21447
|
+
|
|
21540
21448
|
baseClassName: "navi_button",
|
|
21541
21449
|
styleCSSVars: ButtonStyleCSSVars,
|
|
21542
21450
|
pseudoClasses: ButtonPseudoClasses,
|
|
@@ -21714,7 +21622,7 @@ const WarningSvg = () => {
|
|
|
21714
21622
|
});
|
|
21715
21623
|
};
|
|
21716
21624
|
|
|
21717
|
-
|
|
21625
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
21718
21626
|
@layer navi {
|
|
21719
21627
|
.navi_message_box {
|
|
21720
21628
|
--background-color-info: var(--navi-info-color-light);
|
|
@@ -21757,7 +21665,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
21757
21665
|
border-top-left-radius: 6px;
|
|
21758
21666
|
border-bottom-left-radius: 6px;
|
|
21759
21667
|
}
|
|
21760
|
-
|
|
21668
|
+
`, "/src/text/message_box.jsx"];
|
|
21761
21669
|
const MessageBoxPseudoClasses = [":-navi-status-info", ":-navi-status-success", ":-navi-status-warning", ":-navi-status-error"];
|
|
21762
21670
|
const MessageBoxStatusContext = createContext();
|
|
21763
21671
|
const MessageBoxReportTitleChildContext = createContext();
|
|
@@ -21825,7 +21733,7 @@ const MessageBox = ({
|
|
|
21825
21733
|
});
|
|
21826
21734
|
};
|
|
21827
21735
|
|
|
21828
|
-
|
|
21736
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
21829
21737
|
.navi_message_box {
|
|
21830
21738
|
.navi_title {
|
|
21831
21739
|
margin-top: 0;
|
|
@@ -21833,7 +21741,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
21833
21741
|
color: var(--x-message-color);
|
|
21834
21742
|
}
|
|
21835
21743
|
}
|
|
21836
|
-
|
|
21744
|
+
`, "/src/text/title.jsx"];
|
|
21837
21745
|
const TitleLevelContext = createContext();
|
|
21838
21746
|
const useTitleLevel = () => {
|
|
21839
21747
|
return useContext(TitleLevelContext);
|
|
@@ -22010,7 +21918,8 @@ const useDimColorWhen = (elementRef, shouldDim) => {
|
|
|
22010
21918
|
});
|
|
22011
21919
|
};
|
|
22012
21920
|
|
|
22013
|
-
|
|
21921
|
+
installImportMetaCssBuild(import.meta);/* eslint-disable jsenv/no-unknown-params */
|
|
21922
|
+
import.meta.css = [/* css */`
|
|
22014
21923
|
@layer navi {
|
|
22015
21924
|
.navi_link {
|
|
22016
21925
|
--link-border-radius: unset;
|
|
@@ -22282,7 +22191,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
22282
22191
|
.navi_title .navi_link[data-reveal-on-interaction] {
|
|
22283
22192
|
top: 0.25em;
|
|
22284
22193
|
}
|
|
22285
|
-
|
|
22194
|
+
`, "/src/nav/link/link.jsx"];
|
|
22286
22195
|
const LinkStyleCSSVars = {
|
|
22287
22196
|
"outlineColor": "--link-outline-color",
|
|
22288
22197
|
"borderRadius": "--link-border-radius",
|
|
@@ -22482,6 +22391,7 @@ const LinkPlain = props => {
|
|
|
22482
22391
|
overflowEllipsis: overflowEllipsis
|
|
22483
22392
|
// Visual
|
|
22484
22393
|
,
|
|
22394
|
+
|
|
22485
22395
|
"data-appearance": appearance,
|
|
22486
22396
|
"data-current-effect-bold": currentEffectBold ? "" : undefined,
|
|
22487
22397
|
"data-current-effect-shadow": currentEffectShadow ? "" : undefined,
|
|
@@ -22586,7 +22496,11 @@ const LinkWithAction = props => {
|
|
|
22586
22496
|
const NavContext = createContext();
|
|
22587
22497
|
createContext();
|
|
22588
22498
|
|
|
22589
|
-
|
|
22499
|
+
installImportMetaCssBuild(import.meta);/**
|
|
22500
|
+
* TabList component with support for horizontal and vertical layouts
|
|
22501
|
+
* https://dribbble.com/search/tabs
|
|
22502
|
+
*/
|
|
22503
|
+
import.meta.css = [/* css */`
|
|
22590
22504
|
@layer navi {
|
|
22591
22505
|
.navi_nav {
|
|
22592
22506
|
--nav-border: none;
|
|
@@ -22695,7 +22609,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
22695
22609
|
}
|
|
22696
22610
|
}
|
|
22697
22611
|
}
|
|
22698
|
-
|
|
22612
|
+
`, "/src/nav/link/nav.jsx"];
|
|
22699
22613
|
const NavStyleCSSVars = {
|
|
22700
22614
|
border: "--nav-border",
|
|
22701
22615
|
borderRadius: "--nav-border-radius",
|
|
@@ -22765,9 +22679,9 @@ const useFocusGroup = (
|
|
|
22765
22679
|
}, [direction, skipTab, loop, name]);
|
|
22766
22680
|
};
|
|
22767
22681
|
|
|
22768
|
-
|
|
22682
|
+
installImportMetaCssBuild(import.meta);const rightArrowPath = "M680-480L360-160l-80-80 240-240-240-240 80-80 320 320z";
|
|
22769
22683
|
const downArrowPath = "M480-280L160-600l80-80 240 240 240-240 80 80-320 320z";
|
|
22770
|
-
import.meta.css = /* css */`
|
|
22684
|
+
import.meta.css = [/* css */`
|
|
22771
22685
|
.navi_summary_marker {
|
|
22772
22686
|
width: 1em;
|
|
22773
22687
|
height: 1em;
|
|
@@ -22847,7 +22761,7 @@ import.meta.css = /* css */`
|
|
|
22847
22761
|
d: path("${rightArrowPath}");
|
|
22848
22762
|
}
|
|
22849
22763
|
}
|
|
22850
|
-
|
|
22764
|
+
`, "/src/field/details/summary_marker.jsx"];
|
|
22851
22765
|
const SummaryMarker = ({
|
|
22852
22766
|
open,
|
|
22853
22767
|
loading
|
|
@@ -22905,7 +22819,7 @@ const SummaryMarker = ({
|
|
|
22905
22819
|
});
|
|
22906
22820
|
};
|
|
22907
22821
|
|
|
22908
|
-
|
|
22822
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
22909
22823
|
.navi_details {
|
|
22910
22824
|
position: relative;
|
|
22911
22825
|
z-index: 1;
|
|
@@ -22940,7 +22854,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
22940
22854
|
}
|
|
22941
22855
|
}
|
|
22942
22856
|
}
|
|
22943
|
-
|
|
22857
|
+
`, "/src/field/details/details.jsx"];
|
|
22944
22858
|
const Details = props => {
|
|
22945
22859
|
const {
|
|
22946
22860
|
value = "on",
|
|
@@ -23256,7 +23170,7 @@ const fieldPropSet = new Set([
|
|
|
23256
23170
|
"data-testid",
|
|
23257
23171
|
]);
|
|
23258
23172
|
|
|
23259
|
-
|
|
23173
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
23260
23174
|
@layer navi {
|
|
23261
23175
|
label {
|
|
23262
23176
|
&[data-interactive] {
|
|
@@ -23270,7 +23184,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
23270
23184
|
}
|
|
23271
23185
|
}
|
|
23272
23186
|
}
|
|
23273
|
-
|
|
23187
|
+
`, "/src/field/label.jsx"];
|
|
23274
23188
|
const ReportReadOnlyOnLabelContext = createContext();
|
|
23275
23189
|
const ReportDisabledOnLabelContext = createContext();
|
|
23276
23190
|
const ReportInteractiveOnLabelContext = createContext();
|
|
@@ -23321,7 +23235,7 @@ const Label = props => {
|
|
|
23321
23235
|
});
|
|
23322
23236
|
};
|
|
23323
23237
|
|
|
23324
|
-
|
|
23238
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
23325
23239
|
@layer navi {
|
|
23326
23240
|
.navi_checkbox {
|
|
23327
23241
|
--margin: 3px 3px 3px 4px;
|
|
@@ -23646,7 +23560,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
23646
23560
|
}
|
|
23647
23561
|
}
|
|
23648
23562
|
}
|
|
23649
|
-
|
|
23563
|
+
`, "/src/field/input_checkbox.jsx"];
|
|
23650
23564
|
const InputCheckbox = props => {
|
|
23651
23565
|
const {
|
|
23652
23566
|
value = "on"
|
|
@@ -23916,14 +23830,15 @@ const InputCheckboxWithAction = props => {
|
|
|
23916
23830
|
});
|
|
23917
23831
|
};
|
|
23918
23832
|
|
|
23919
|
-
|
|
23833
|
+
installImportMetaCssBuild(import.meta);// TOFIX: select in data then reset, it reset to red/blue instead of red/blue/green
|
|
23834
|
+
import.meta.css = [/* css */`
|
|
23920
23835
|
@layer navi {
|
|
23921
23836
|
.navi_checkbox_list {
|
|
23922
23837
|
display: flex;
|
|
23923
23838
|
flex-direction: column;
|
|
23924
23839
|
}
|
|
23925
23840
|
}
|
|
23926
|
-
|
|
23841
|
+
`, "/src/field/checkbox_list.jsx"];
|
|
23927
23842
|
const CheckboxList = forwardRef((props, ref) => {
|
|
23928
23843
|
const uiStateController = useUIGroupStateController(props, "checkbox_list", {
|
|
23929
23844
|
childComponentType: "checkbox",
|
|
@@ -23975,6 +23890,7 @@ const CheckboxListBasic = forwardRef((props, ref) => {
|
|
|
23975
23890
|
"data-checkbox-list": true
|
|
23976
23891
|
// eslint-disable-next-line react/no-unknown-property
|
|
23977
23892
|
,
|
|
23893
|
+
|
|
23978
23894
|
onresetuistate: e => {
|
|
23979
23895
|
uiStateController.resetUIState(e);
|
|
23980
23896
|
},
|
|
@@ -24068,7 +23984,7 @@ forwardRef((props, ref) => {
|
|
|
24068
23984
|
});
|
|
24069
23985
|
});
|
|
24070
23986
|
|
|
24071
|
-
|
|
23987
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
24072
23988
|
@layer navi {
|
|
24073
23989
|
.navi_radio {
|
|
24074
23990
|
--margin: 3px 3px 0 5px;
|
|
@@ -24359,7 +24275,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
24359
24275
|
}
|
|
24360
24276
|
}
|
|
24361
24277
|
}
|
|
24362
|
-
|
|
24278
|
+
`, "/src/field/input_radio.jsx"];
|
|
24363
24279
|
const InputRadio = props => {
|
|
24364
24280
|
const {
|
|
24365
24281
|
value = "on"
|
|
@@ -24606,7 +24522,7 @@ const InputRadioWithAction = () => {
|
|
|
24606
24522
|
throw new Error(`<Input type="radio" /> with an action make no sense. Use <RadioList action={something} /> instead`);
|
|
24607
24523
|
};
|
|
24608
24524
|
|
|
24609
|
-
|
|
24525
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
24610
24526
|
@layer navi {
|
|
24611
24527
|
.navi_input_range {
|
|
24612
24528
|
--border-radius: 6px;
|
|
@@ -24813,7 +24729,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
24813
24729
|
.navi_input_range[data-callout] {
|
|
24814
24730
|
/* What can we do? */
|
|
24815
24731
|
}
|
|
24816
|
-
|
|
24732
|
+
`, "/src/field/input_range.jsx"];
|
|
24817
24733
|
const InputRange = props => {
|
|
24818
24734
|
const uiStateController = useUIStateController(props, "input");
|
|
24819
24735
|
const uiState = useUIState(uiStateController);
|
|
@@ -24965,6 +24881,7 @@ const InputRangeBasic = props => {
|
|
|
24965
24881
|
}
|
|
24966
24882
|
// style management
|
|
24967
24883
|
,
|
|
24884
|
+
|
|
24968
24885
|
baseClassName: "navi_native_input"
|
|
24969
24886
|
});
|
|
24970
24887
|
};
|
|
@@ -25083,7 +25000,24 @@ const SearchSvg = () => jsx("svg", {
|
|
|
25083
25000
|
})
|
|
25084
25001
|
});
|
|
25085
25002
|
|
|
25086
|
-
|
|
25003
|
+
installImportMetaCssBuild(import.meta);/**
|
|
25004
|
+
* Input component for all textual input types.
|
|
25005
|
+
*
|
|
25006
|
+
* Supports:
|
|
25007
|
+
* - text (default)
|
|
25008
|
+
* - password
|
|
25009
|
+
* - hidden
|
|
25010
|
+
* - email
|
|
25011
|
+
* - url
|
|
25012
|
+
* - search
|
|
25013
|
+
* - tel
|
|
25014
|
+
* - etc.
|
|
25015
|
+
*
|
|
25016
|
+
* For non-textual inputs, specialized components will be used:
|
|
25017
|
+
* - <InputCheckbox /> for type="checkbox"
|
|
25018
|
+
* - <InputRadio /> for type="radio"
|
|
25019
|
+
*/
|
|
25020
|
+
import.meta.css = [/* css */`
|
|
25087
25021
|
@layer navi {
|
|
25088
25022
|
.navi_input {
|
|
25089
25023
|
--border-radius: 2px;
|
|
@@ -25293,7 +25227,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
25293
25227
|
/* Fortunately we can override it as follow */
|
|
25294
25228
|
-webkit-text-fill-color: var(--x-color) !important;
|
|
25295
25229
|
}
|
|
25296
|
-
|
|
25230
|
+
`, "/src/field/input_textual.jsx"];
|
|
25297
25231
|
const InputTextual = props => {
|
|
25298
25232
|
const uiStateController = useUIStateController(props, "input");
|
|
25299
25233
|
const uiState = useUIState(uiStateController);
|
|
@@ -25436,6 +25370,7 @@ const InputTextualBasic = props => {
|
|
|
25436
25370
|
}
|
|
25437
25371
|
// style management
|
|
25438
25372
|
,
|
|
25373
|
+
|
|
25439
25374
|
baseClassName: "navi_native_input",
|
|
25440
25375
|
"data-rendered-by": ".navi_input"
|
|
25441
25376
|
});
|
|
@@ -25654,7 +25589,16 @@ const Input = props => {
|
|
|
25654
25589
|
});
|
|
25655
25590
|
};
|
|
25656
25591
|
|
|
25657
|
-
|
|
25592
|
+
installImportMetaCssBuild(import.meta);/**
|
|
25593
|
+
* - We must keep the edited element in the DOM so that
|
|
25594
|
+
* the layout remains the same (especially important for table cells)
|
|
25595
|
+
* And the editable part is in absolute so that it takes the original content dimensions
|
|
25596
|
+
* AND for table cells it can actually take the table cell dimensions
|
|
25597
|
+
*
|
|
25598
|
+
* This means an editable thing MUST have a parent with position relative that wraps the content and the eventual editable input
|
|
25599
|
+
*
|
|
25600
|
+
*/
|
|
25601
|
+
import.meta.css = [/* css */`
|
|
25658
25602
|
.navi_editable_wrapper {
|
|
25659
25603
|
--inset-top: 0px;
|
|
25660
25604
|
--inset-right: 0px;
|
|
@@ -25679,7 +25623,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
25679
25623
|
pointer-events: auto;
|
|
25680
25624
|
}
|
|
25681
25625
|
}
|
|
25682
|
-
|
|
25626
|
+
`, "/src/field/edition/editable.jsx"];
|
|
25683
25627
|
const useEditionController = () => {
|
|
25684
25628
|
const [editing, editingSetter] = useState(null);
|
|
25685
25629
|
const startEditing = useCallback(event => {
|
|
@@ -26113,7 +26057,7 @@ const FormWithAction = props => {
|
|
|
26113
26057
|
// form.dispatchEvent(customEvent);
|
|
26114
26058
|
// };
|
|
26115
26059
|
|
|
26116
|
-
|
|
26060
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
26117
26061
|
.navi_group {
|
|
26118
26062
|
--border-width: 1px;
|
|
26119
26063
|
|
|
@@ -26202,7 +26146,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
26202
26146
|
}
|
|
26203
26147
|
}
|
|
26204
26148
|
}
|
|
26205
|
-
|
|
26149
|
+
`, "/src/field/group.jsx"];
|
|
26206
26150
|
const Group = ({
|
|
26207
26151
|
children,
|
|
26208
26152
|
borderWidth = 1,
|
|
@@ -26227,7 +26171,7 @@ const Group = ({
|
|
|
26227
26171
|
});
|
|
26228
26172
|
};
|
|
26229
26173
|
|
|
26230
|
-
|
|
26174
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */``, "/src/field/radio_list.jsx"];
|
|
26231
26175
|
const RadioList = props => {
|
|
26232
26176
|
const uiStateController = useUIGroupStateController(props, "radio_list", {
|
|
26233
26177
|
childComponentType: "radio",
|
|
@@ -26408,12 +26352,12 @@ const useRefArray = (items, keyFromItem) => {
|
|
|
26408
26352
|
}, [items]);
|
|
26409
26353
|
};
|
|
26410
26354
|
|
|
26411
|
-
|
|
26412
|
-
import.meta.css = /* css */`
|
|
26355
|
+
installImportMetaCssBuild(import.meta);const useNavState = () => {};
|
|
26356
|
+
import.meta.css = [/* css */`
|
|
26413
26357
|
.navi_select[data-readonly] {
|
|
26414
26358
|
pointer-events: none;
|
|
26415
26359
|
}
|
|
26416
|
-
|
|
26360
|
+
`, "/src/field/select.jsx"];
|
|
26417
26361
|
const Select = forwardRef((props, ref) => {
|
|
26418
26362
|
const select = renderActionableComponent(props, ref);
|
|
26419
26363
|
return select;
|
|
@@ -26718,7 +26662,7 @@ const Z_INDEX_DROP_PREVIEW = Z_INDEX_STICKY_CORNER + 1;
|
|
|
26718
26662
|
|
|
26719
26663
|
const Z_INDEX_TABLE_UI = Z_INDEX_STICKY_CORNER + 1;
|
|
26720
26664
|
|
|
26721
|
-
|
|
26665
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
26722
26666
|
.navi_table_drag_clone_container {
|
|
26723
26667
|
position: absolute;
|
|
26724
26668
|
top: var(--table-visual-top);
|
|
@@ -26837,7 +26781,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
26837
26781
|
width: 10px;
|
|
26838
26782
|
height: 10px;
|
|
26839
26783
|
}
|
|
26840
|
-
|
|
26784
|
+
`, "/src/field/table/drag/table_drag.jsx"];
|
|
26841
26785
|
const TableDragContext = createContext();
|
|
26842
26786
|
const useTableDragContextValue = ({
|
|
26843
26787
|
tableDragCloneContainerRef,
|
|
@@ -27378,11 +27322,11 @@ const useTableSizeContextValue = ({
|
|
|
27378
27322
|
return tableSizeContextValue;
|
|
27379
27323
|
};
|
|
27380
27324
|
|
|
27381
|
-
|
|
27325
|
+
installImportMetaCssBuild(import.meta);const ROW_MIN_HEIGHT = 30;
|
|
27382
27326
|
const ROW_MAX_HEIGHT = 100;
|
|
27383
27327
|
const COLUMN_MIN_WIDTH = 50;
|
|
27384
27328
|
const COLUMN_MAX_WIDTH = 500;
|
|
27385
|
-
import.meta.css = /* css */`
|
|
27329
|
+
import.meta.css = [/* css */`
|
|
27386
27330
|
@layer navi {
|
|
27387
27331
|
.navi_table {
|
|
27388
27332
|
--table-resizer-handle-color: #063b7c;
|
|
@@ -27538,7 +27482,7 @@ import.meta.css = /* css */`
|
|
|
27538
27482
|
.navi_table_row_resizer[data-grabbed] .navi_table_row_resizer_line {
|
|
27539
27483
|
opacity: 1;
|
|
27540
27484
|
}
|
|
27541
|
-
|
|
27485
|
+
`, "/src/field/table/resize/table_resize.jsx"];
|
|
27542
27486
|
|
|
27543
27487
|
// Column resize components
|
|
27544
27488
|
const TableColumnResizer = forwardRef((props, ref) => {
|
|
@@ -28004,7 +27948,7 @@ const findPreviousTableRow = currentRow => {
|
|
|
28004
27948
|
return currentIndex > 0 ? allRows[currentIndex - 1] : null;
|
|
28005
27949
|
};
|
|
28006
27950
|
|
|
28007
|
-
|
|
27951
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
28008
27952
|
@layer navi {
|
|
28009
27953
|
.navi_table {
|
|
28010
27954
|
--selection-border-color: var(--navi-selection-border-color, #0078d4);
|
|
@@ -28099,7 +28043,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
28099
28043
|
inset 0 -1px 0 0 var(--selection-border-color),
|
|
28100
28044
|
inset 1px 0 0 0 var(--selection-border-color);
|
|
28101
28045
|
}
|
|
28102
|
-
|
|
28046
|
+
`, "/src/field/table/selection/table_selection.jsx"];
|
|
28103
28047
|
const useTableSelectionController = ({
|
|
28104
28048
|
tableRef,
|
|
28105
28049
|
selection,
|
|
@@ -28575,7 +28519,8 @@ const useTableStickyContextValue = ({
|
|
|
28575
28519
|
}, [stickyLeftFrontierColumnIndex, stickyTopFrontierRowIndex]);
|
|
28576
28520
|
};
|
|
28577
28521
|
|
|
28578
|
-
|
|
28522
|
+
installImportMetaCssBuild(import.meta);// TODO: sticky left/top frontier should likely use "followPosition"
|
|
28523
|
+
import.meta.css = [/* css */`
|
|
28579
28524
|
@layer navi {
|
|
28580
28525
|
.navi_table {
|
|
28581
28526
|
--sticky-frontier-color: #c0c0c0;
|
|
@@ -28814,7 +28759,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
28814
28759
|
inset -1px 0 0 0 var(--border-color),
|
|
28815
28760
|
inset 0 -1px 0 0 var(--border-color);
|
|
28816
28761
|
}
|
|
28817
|
-
|
|
28762
|
+
`, "/src/field/table/sticky/table_sticky.jsx"];
|
|
28818
28763
|
const TableStickyFrontier = ({
|
|
28819
28764
|
tableRef
|
|
28820
28765
|
}) => {
|
|
@@ -29036,7 +28981,7 @@ const initMoveStickyFrontierViaPointer = (pointerdownEvent, {
|
|
|
29036
28981
|
});
|
|
29037
28982
|
};
|
|
29038
28983
|
|
|
29039
|
-
|
|
28984
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
29040
28985
|
.navi_table_ui {
|
|
29041
28986
|
position: fixed;
|
|
29042
28987
|
inset: 0;
|
|
@@ -29045,7 +28990,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
29045
28990
|
overflow: hidden; /* Ensure UI elements cannot impact scrollbars of the document */
|
|
29046
28991
|
/* background: rgba(0, 255, 0, 0.2); */
|
|
29047
28992
|
}
|
|
29048
|
-
|
|
28993
|
+
`, "/src/field/table/table_ui.jsx"];
|
|
29049
28994
|
const TableUI = forwardRef((props, ref) => {
|
|
29050
28995
|
const {
|
|
29051
28996
|
tableRef,
|
|
@@ -29960,7 +29905,7 @@ const normalizeKey = (key) => {
|
|
|
29960
29905
|
return key;
|
|
29961
29906
|
};
|
|
29962
29907
|
|
|
29963
|
-
|
|
29908
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
29964
29909
|
.navi_shortcut_container[data-visually-hidden] {
|
|
29965
29910
|
/* Visually hidden container - doesn't affect layout */
|
|
29966
29911
|
position: absolute;
|
|
@@ -29994,7 +29939,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
29994
29939
|
opacity: 0;
|
|
29995
29940
|
pointer-events: none;
|
|
29996
29941
|
}
|
|
29997
|
-
|
|
29942
|
+
`, "/src/keyboard/active_keyboard_shortcuts.jsx"];
|
|
29998
29943
|
const ActiveKeyboardShortcuts = ({
|
|
29999
29944
|
visible
|
|
30000
29945
|
}) => {
|
|
@@ -30036,7 +29981,7 @@ const KeyboardShortcutAriaElement = ({
|
|
|
30036
29981
|
});
|
|
30037
29982
|
};
|
|
30038
29983
|
|
|
30039
|
-
|
|
29984
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
30040
29985
|
@layer navi {
|
|
30041
29986
|
.navi_clipboard_container {
|
|
30042
29987
|
--height: 1.5em;
|
|
@@ -30063,7 +30008,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
30063
30008
|
transform: translateY(-100%);
|
|
30064
30009
|
}
|
|
30065
30010
|
}
|
|
30066
|
-
|
|
30011
|
+
`, "/src/field/button_copy_to_clipboard.jsx"];
|
|
30067
30012
|
const ButtonCopyToClipboard = ({
|
|
30068
30013
|
children,
|
|
30069
30014
|
...props
|
|
@@ -30148,7 +30093,7 @@ const Address = ({
|
|
|
30148
30093
|
});
|
|
30149
30094
|
};
|
|
30150
30095
|
|
|
30151
|
-
|
|
30096
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
30152
30097
|
@layer navi {
|
|
30153
30098
|
}
|
|
30154
30099
|
.navi_badge {
|
|
@@ -30176,7 +30121,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
30176
30121
|
--x-color-contrasting: var(--navi-color-white);
|
|
30177
30122
|
}
|
|
30178
30123
|
}
|
|
30179
|
-
|
|
30124
|
+
`, "/src/text/badge.jsx"];
|
|
30180
30125
|
const BadgeStyleCSSVars$1 = {
|
|
30181
30126
|
borderWidth: "--border-width",
|
|
30182
30127
|
borderRadius: "--border-radius",
|
|
@@ -30271,7 +30216,7 @@ const formatNumber = (value, { lang } = {}) => {
|
|
|
30271
30216
|
return new Intl.NumberFormat(lang).format(value);
|
|
30272
30217
|
};
|
|
30273
30218
|
|
|
30274
|
-
|
|
30219
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
30275
30220
|
@layer navi {
|
|
30276
30221
|
}
|
|
30277
30222
|
.navi_badge_count {
|
|
@@ -30360,7 +30305,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
30360
30305
|
}
|
|
30361
30306
|
}
|
|
30362
30307
|
}
|
|
30363
|
-
|
|
30308
|
+
`, "/src/text/badge_count.jsx"];
|
|
30364
30309
|
const BadgeStyleCSSVars = {
|
|
30365
30310
|
borderWidth: "--border-width",
|
|
30366
30311
|
borderRadius: "--border-radius",
|
|
@@ -30519,7 +30464,7 @@ const BadgeCountCircle = ({
|
|
|
30519
30464
|
});
|
|
30520
30465
|
};
|
|
30521
30466
|
|
|
30522
|
-
|
|
30467
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
30523
30468
|
@layer navi {
|
|
30524
30469
|
.navi_caption {
|
|
30525
30470
|
--color: #6b7280;
|
|
@@ -30535,7 +30480,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
30535
30480
|
.navi_caption {
|
|
30536
30481
|
color: var(--color);
|
|
30537
30482
|
}
|
|
30538
|
-
|
|
30483
|
+
`, "/src/text/caption.jsx"];
|
|
30539
30484
|
const CaptionStyleCSSVars = {
|
|
30540
30485
|
color: "--color"
|
|
30541
30486
|
};
|
|
@@ -30547,6 +30492,7 @@ const Caption = ({
|
|
|
30547
30492
|
as: "small",
|
|
30548
30493
|
size: "0.8em" // We use em to be relative to the parent (we want to be smaller than the surrounding text)
|
|
30549
30494
|
,
|
|
30495
|
+
|
|
30550
30496
|
className: withPropsClassName("navi_caption", className),
|
|
30551
30497
|
...rest,
|
|
30552
30498
|
styleCSSVars: CaptionStyleCSSVars
|
|
@@ -30919,7 +30865,7 @@ const interpolate = (template, values) => {
|
|
|
30919
30865
|
});
|
|
30920
30866
|
};
|
|
30921
30867
|
|
|
30922
|
-
|
|
30868
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
30923
30869
|
@layer navi {
|
|
30924
30870
|
.navi_quantity {
|
|
30925
30871
|
--unit-color: color-mix(in srgb, currentColor 50%, white);
|
|
@@ -30975,7 +30921,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
30975
30921
|
}
|
|
30976
30922
|
}
|
|
30977
30923
|
}
|
|
30978
|
-
|
|
30924
|
+
`, "/src/text/quantity.jsx"];
|
|
30979
30925
|
const QuantityIntl = createIntl();
|
|
30980
30926
|
const wellKnownUnitMap = new Map();
|
|
30981
30927
|
/**
|
|
@@ -31112,7 +31058,7 @@ const parseQuantityValue = children => {
|
|
|
31112
31058
|
return Number.isNaN(parsed) ? children : parsed;
|
|
31113
31059
|
};
|
|
31114
31060
|
|
|
31115
|
-
|
|
31061
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
31116
31062
|
@layer navi {
|
|
31117
31063
|
.navi_meter {
|
|
31118
31064
|
--loader-color: var(--navi-loader-color);
|
|
@@ -31229,7 +31175,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31229
31175
|
}
|
|
31230
31176
|
}
|
|
31231
31177
|
}
|
|
31232
|
-
|
|
31178
|
+
`, "/src/text/meter.jsx"];
|
|
31233
31179
|
const MeterStyleCSSVars = {
|
|
31234
31180
|
trackColor: "--track-color",
|
|
31235
31181
|
borderColor: "--border-color",
|
|
@@ -31376,7 +31322,7 @@ const Paragraph = props => {
|
|
|
31376
31322
|
});
|
|
31377
31323
|
};
|
|
31378
31324
|
|
|
31379
|
-
|
|
31325
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
31380
31326
|
.navi_text_placeholder {
|
|
31381
31327
|
display: inline-block;
|
|
31382
31328
|
width: 100%;
|
|
@@ -31397,7 +31343,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31397
31343
|
background-position: -200% 0;
|
|
31398
31344
|
}
|
|
31399
31345
|
}
|
|
31400
|
-
|
|
31346
|
+
`, "/src/text/text_placeholder.jsx"];
|
|
31401
31347
|
const TextPlaceholder = ({
|
|
31402
31348
|
loading,
|
|
31403
31349
|
...props
|
|
@@ -31423,7 +31369,41 @@ const Svg = props => {
|
|
|
31423
31369
|
});
|
|
31424
31370
|
};
|
|
31425
31371
|
|
|
31426
|
-
|
|
31372
|
+
installImportMetaCssBuild(import.meta);/**
|
|
31373
|
+
* SVGComposition Component
|
|
31374
|
+
*
|
|
31375
|
+
* Creates composite SVGs by combining independent SVG elements with masking.
|
|
31376
|
+
*
|
|
31377
|
+
* This component solves the challenge of combining independently created SVGs into
|
|
31378
|
+
* a single visual composition. Each SVG can have its own coordinate system, viewBox,
|
|
31379
|
+
* and styling, allowing for maximum reusability of individual icons or graphics.
|
|
31380
|
+
*
|
|
31381
|
+
* When overlaying SVGs, each subsequent overlay "cuts out" its portion from the base SVG,
|
|
31382
|
+
* creating a seamless integration where SVGs appear to interact with each other visually.
|
|
31383
|
+
*
|
|
31384
|
+
* Key benefits:
|
|
31385
|
+
* - Maintains each SVG's independence - use them individually elsewhere
|
|
31386
|
+
* - Handles different viewBox dimensions automatically
|
|
31387
|
+
* - Works with any SVG components regardless of internal implementation
|
|
31388
|
+
* - Supports unlimited overlay elements
|
|
31389
|
+
* - Creates proper masking between elements for visual integration
|
|
31390
|
+
*
|
|
31391
|
+
* Usage example combining two independent icon components:
|
|
31392
|
+
* ```jsx
|
|
31393
|
+
* <SVGMaskOverlay viewBox="0 0 24 24">
|
|
31394
|
+
* <DatabaseSvg />
|
|
31395
|
+
* <svg x="12" y="12" width="16" height="16" overflow="visible">
|
|
31396
|
+
* <PlusSvg />
|
|
31397
|
+
* </svg>
|
|
31398
|
+
* </SVGMaskOverlay>
|
|
31399
|
+
* ```
|
|
31400
|
+
*
|
|
31401
|
+
* @param {Object} props - Component properties
|
|
31402
|
+
* @param {string} props.viewBox - The main viewBox for the composition (required)
|
|
31403
|
+
* @param {ReactNode[]} props.children - SVG elements (first is base, rest are overlays)
|
|
31404
|
+
* @returns {ReactElement} A composed SVG with all elements properly masked
|
|
31405
|
+
*/
|
|
31406
|
+
import.meta.css = [/* css */`
|
|
31427
31407
|
.svg_mask_content * {
|
|
31428
31408
|
color: black !important;
|
|
31429
31409
|
opacity: 1 !important;
|
|
@@ -31432,7 +31412,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31432
31412
|
stroke: black !important;
|
|
31433
31413
|
stroke-opacity: 1 !important;
|
|
31434
31414
|
}
|
|
31435
|
-
|
|
31415
|
+
`, "/src/graphic/svg_mask_overlay.jsx"];
|
|
31436
31416
|
const SVGMaskOverlay = ({
|
|
31437
31417
|
viewBox,
|
|
31438
31418
|
children
|
|
@@ -31489,7 +31469,8 @@ const SVGMaskOverlay = ({
|
|
|
31489
31469
|
});
|
|
31490
31470
|
};
|
|
31491
31471
|
|
|
31492
|
-
|
|
31472
|
+
installImportMetaCssBuild(import.meta);// We HAVE TO put paddings around the dialog to ensure window resizing respects this space
|
|
31473
|
+
import.meta.css = [/* css */`
|
|
31493
31474
|
@layer navi {
|
|
31494
31475
|
.navi_dialog_layout {
|
|
31495
31476
|
--layout-margin: 30px;
|
|
@@ -31547,7 +31528,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31547
31528
|
border-color: var(--layout-border-color);
|
|
31548
31529
|
border-radius: var(--layout-border-radius);
|
|
31549
31530
|
}
|
|
31550
|
-
|
|
31531
|
+
`, "/src/layout/dialog_layout.jsx"];
|
|
31551
31532
|
const DialogLayoutStyleCSSVars = {
|
|
31552
31533
|
margin: "--layout-margin",
|
|
31553
31534
|
marginTop: "--layout-margin-top",
|
|
@@ -31588,7 +31569,7 @@ const DialogLayout = ({
|
|
|
31588
31569
|
});
|
|
31589
31570
|
};
|
|
31590
31571
|
|
|
31591
|
-
|
|
31572
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
31592
31573
|
@layer navi {
|
|
31593
31574
|
.navi_separator {
|
|
31594
31575
|
--size: 1px;
|
|
@@ -31620,7 +31601,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31620
31601
|
vertical-align: bottom;
|
|
31621
31602
|
}
|
|
31622
31603
|
}
|
|
31623
|
-
|
|
31604
|
+
`, "/src/layout/separator.jsx"];
|
|
31624
31605
|
const SeparatorStyleCSSVars = {
|
|
31625
31606
|
color: "--color"
|
|
31626
31607
|
};
|
|
@@ -31637,7 +31618,7 @@ const Separator = ({
|
|
|
31637
31618
|
});
|
|
31638
31619
|
};
|
|
31639
31620
|
|
|
31640
|
-
|
|
31621
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
31641
31622
|
@layer navi {
|
|
31642
31623
|
.navi_viewport_layout {
|
|
31643
31624
|
--layout-padding: 40px;
|
|
@@ -31664,7 +31645,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31664
31645
|
);
|
|
31665
31646
|
background: var(--layout-background);
|
|
31666
31647
|
}
|
|
31667
|
-
|
|
31648
|
+
`, "/src/layout/viewport_layout.jsx"];
|
|
31668
31649
|
const ViewportLayoutStyleCSSVars = {
|
|
31669
31650
|
padding: "--layout-padding",
|
|
31670
31651
|
paddingTop: "--layout-padding-top",
|
|
@@ -31684,7 +31665,7 @@ const ViewportLayout = props => {
|
|
|
31684
31665
|
});
|
|
31685
31666
|
};
|
|
31686
31667
|
|
|
31687
|
-
|
|
31668
|
+
installImportMetaCssBuild(import.meta);import.meta.css = [/* css */`
|
|
31688
31669
|
@layer navi {
|
|
31689
31670
|
.navi_side_panel {
|
|
31690
31671
|
--side-panel-width: 400px;
|
|
@@ -31781,7 +31762,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
31781
31762
|
transform: translateX(100%);
|
|
31782
31763
|
}
|
|
31783
31764
|
}
|
|
31784
|
-
|
|
31765
|
+
`, "/src/popover/side_panel.jsx"];
|
|
31785
31766
|
const SidePanelCloseContext = createContext(null);
|
|
31786
31767
|
const useSidePanelClose = () => useContext(SidePanelCloseContext);
|
|
31787
31768
|
const SidePanelStyleCSSVars = {
|