@jsenv/navi 0.29.107 → 0.29.108
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 +637 -64
- package/dist/jsenv_navi.js.map +65 -37
- package/dist/jsenv_navi_side_effects.js +11 -0
- package/dist/jsenv_navi_side_effects.js.map +2 -2
- package/docs/form_changed.md +2 -1
- package/docs/navigation.md +9 -1
- package/docs/testid.md +20 -2
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -38,7 +38,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
38
38
|
* any of these, and a number is the last resort, not the first tool.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
const css$
|
|
41
|
+
const css$15 = /* css */`
|
|
42
42
|
@layer navi {
|
|
43
43
|
:root {
|
|
44
44
|
/* A control that overlaps its neighbours (the members of a Group share
|
|
@@ -102,7 +102,7 @@ const css$14 = /* css */`
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
`;
|
|
105
|
-
import.meta.css = [css$
|
|
105
|
+
import.meta.css = [css$15, "@jsenv/navi/src/navi_z_indexes.js"];
|
|
106
106
|
|
|
107
107
|
const addIntoArray = (array, ...valuesToAdd) => {
|
|
108
108
|
if (valuesToAdd.length === 1) {
|
|
@@ -371,7 +371,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
371
371
|
* the very first render and the browser does everything on its own.
|
|
372
372
|
*/
|
|
373
373
|
const URL_TARGET_ATTRIBUTE = "data-url-target";
|
|
374
|
-
const css$
|
|
374
|
+
const css$14 = /* css */`
|
|
375
375
|
@layer navi {
|
|
376
376
|
[${URL_TARGET_ATTRIBUTE}] {
|
|
377
377
|
animation: navi_url_target var(--navi-url-target-duration, 2000ms)
|
|
@@ -389,7 +389,7 @@ const css$13 = /* css */`
|
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
391
|
`;
|
|
392
|
-
import.meta.css = [css$
|
|
392
|
+
import.meta.css = [css$14, "@jsenv/navi/src/nav/url_target/url_target.js"];
|
|
393
393
|
let urlTargetOptions = {
|
|
394
394
|
block: "start",
|
|
395
395
|
behavior: "instant",
|
|
@@ -750,7 +750,7 @@ const useActionStatus = (action) => {
|
|
|
750
750
|
};
|
|
751
751
|
};
|
|
752
752
|
|
|
753
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
753
|
+
installImportMetaCssBuild(import.meta);const css$13 = /* css */`
|
|
754
754
|
.action_error {
|
|
755
755
|
margin-top: 0;
|
|
756
756
|
margin-bottom: 20px;
|
|
@@ -775,7 +775,7 @@ const ActionRenderer = ({
|
|
|
775
775
|
children,
|
|
776
776
|
disabled
|
|
777
777
|
}) => {
|
|
778
|
-
import.meta.css = [css$
|
|
778
|
+
import.meta.css = [css$13, "@jsenv/navi/src/action/action_renderer.jsx"];
|
|
779
779
|
if (action === undefined) {
|
|
780
780
|
throw new Error("ActionRenderer requires an action to render, but none was provided.");
|
|
781
781
|
}
|
|
@@ -3813,6 +3813,9 @@ const CONTROL_PROP_SET = new Set([
|
|
|
3813
3813
|
"signal",
|
|
3814
3814
|
"defaultValue",
|
|
3815
3815
|
"defaultChecked",
|
|
3816
|
+
// A checked radio pressed again lets its value go — a group allowed to hold
|
|
3817
|
+
// nothing. Answered by the radio's own reactions (see control_hooks.jsx).
|
|
3818
|
+
"deselectable",
|
|
3816
3819
|
"readOnly", // will depend wether readOnly is supported
|
|
3817
3820
|
|
|
3818
3821
|
"loading",
|
|
@@ -4185,15 +4188,26 @@ let renderMessageText = text => text;
|
|
|
4185
4188
|
const setCalloutMessageTextRenderer = renderer => {
|
|
4186
4189
|
renderMessageText = renderer;
|
|
4187
4190
|
};
|
|
4188
|
-
|
|
4191
|
+
|
|
4192
|
+
// What a callout's own JSX may know about the callout around it: how to close
|
|
4193
|
+
// it, and the element — whose id is what `commandFor` needs when the button
|
|
4194
|
+
// closing it is not inside it (inside, `--navi-close` finds it on its own).
|
|
4195
|
+
const CalloutContext = createContext();
|
|
4189
4196
|
const useCalloutRequestClose = () => {
|
|
4190
|
-
return useContext(
|
|
4197
|
+
return useContext(CalloutContext)?.requestClose;
|
|
4198
|
+
};
|
|
4199
|
+
const useCalloutElement = () => {
|
|
4200
|
+
return useContext(CalloutContext)?.element;
|
|
4191
4201
|
};
|
|
4192
4202
|
const renderIntoCallout = (jsx$1, calloutMessageElement, {
|
|
4193
|
-
requestClose
|
|
4203
|
+
requestClose,
|
|
4204
|
+
element
|
|
4194
4205
|
}) => {
|
|
4195
|
-
const calloutJsx = jsx(
|
|
4196
|
-
value:
|
|
4206
|
+
const calloutJsx = jsx(CalloutContext.Provider, {
|
|
4207
|
+
value: {
|
|
4208
|
+
requestClose,
|
|
4209
|
+
element
|
|
4210
|
+
},
|
|
4197
4211
|
children: jsx$1
|
|
4198
4212
|
});
|
|
4199
4213
|
render(calloutJsx, calloutMessageElement);
|
|
@@ -4203,12 +4217,14 @@ const renderIntoCallout = (jsx$1, calloutMessageElement, {
|
|
|
4203
4217
|
// text can go through renderMessageText: an emoji in a validation message must
|
|
4204
4218
|
// not make the first line taller than the icon and close button beside it.
|
|
4205
4219
|
const renderHtmlIntoCallout = (html, calloutMessageElement, {
|
|
4206
|
-
requestClose
|
|
4220
|
+
requestClose,
|
|
4221
|
+
element
|
|
4207
4222
|
}) => {
|
|
4208
4223
|
const template = document.createElement("template");
|
|
4209
4224
|
template.innerHTML = html;
|
|
4210
4225
|
renderIntoCallout(domToVNodes(template.content), calloutMessageElement, {
|
|
4211
|
-
requestClose
|
|
4226
|
+
requestClose,
|
|
4227
|
+
element
|
|
4212
4228
|
});
|
|
4213
4229
|
};
|
|
4214
4230
|
|
|
@@ -4241,6 +4257,98 @@ const domToVNodes = node => {
|
|
|
4241
4257
|
return vnodes;
|
|
4242
4258
|
};
|
|
4243
4259
|
|
|
4260
|
+
installImportMetaCssBuild(import.meta);/**
|
|
4261
|
+
* The icon a callout shows beside its message — a square in the status color
|
|
4262
|
+
* with the "!" glyph — drawable on its own, where the callout is not: on the
|
|
4263
|
+
* trigger that opens one (a picker in callout mode), so what one presses looks
|
|
4264
|
+
* like what it opens. The callout's own template draws from the same glyph
|
|
4265
|
+
* (see calloutTemplate in callout.js).
|
|
4266
|
+
*/
|
|
4267
|
+
|
|
4268
|
+
const css$12 = /* css */`
|
|
4269
|
+
.navi_callout_status_icon {
|
|
4270
|
+
--x-callout-status-icon-color: var(--navi-callout-neutral-color);
|
|
4271
|
+
|
|
4272
|
+
display: inline-flex;
|
|
4273
|
+
box-sizing: border-box;
|
|
4274
|
+
aspect-ratio: 1 / 1;
|
|
4275
|
+
width: 1em;
|
|
4276
|
+
height: 1em;
|
|
4277
|
+
flex-shrink: 0;
|
|
4278
|
+
align-items: center;
|
|
4279
|
+
justify-content: center;
|
|
4280
|
+
color: white;
|
|
4281
|
+
vertical-align: middle;
|
|
4282
|
+
background-color: var(--x-callout-status-icon-color);
|
|
4283
|
+
border-radius: 2px;
|
|
4284
|
+
|
|
4285
|
+
&[data-status="success"] {
|
|
4286
|
+
--x-callout-status-icon-color: var(--navi-callout-success-color);
|
|
4287
|
+
}
|
|
4288
|
+
&[data-status="info"] {
|
|
4289
|
+
--x-callout-status-icon-color: var(--navi-callout-info-color);
|
|
4290
|
+
}
|
|
4291
|
+
&[data-status="warning"] {
|
|
4292
|
+
--x-callout-status-icon-color: var(--navi-callout-warning-color);
|
|
4293
|
+
}
|
|
4294
|
+
&[data-status="error"] {
|
|
4295
|
+
--x-callout-status-icon-color: var(--navi-callout-error-color);
|
|
4296
|
+
}
|
|
4297
|
+
&[data-shape="circle"] {
|
|
4298
|
+
border-radius: 50%;
|
|
4299
|
+
}
|
|
4300
|
+
|
|
4301
|
+
svg {
|
|
4302
|
+
width: auto;
|
|
4303
|
+
height: 55%;
|
|
4304
|
+
}
|
|
4305
|
+
}
|
|
4306
|
+
/* Inside an <Icon>, the icon box is the size: fill it. The glyph keeps its
|
|
4307
|
+
own share of it — the Icon's rule sizing any svg it holds to the whole
|
|
4308
|
+
box is for an svg that IS the icon, and this one sits in a square. */
|
|
4309
|
+
.navi_icon > .navi_callout_status_icon {
|
|
4310
|
+
width: 100%;
|
|
4311
|
+
height: 100%;
|
|
4312
|
+
}
|
|
4313
|
+
.navi_icon[data-icon-char] .navi_callout_status_icon svg {
|
|
4314
|
+
width: auto;
|
|
4315
|
+
height: 55%;
|
|
4316
|
+
}
|
|
4317
|
+
`;
|
|
4318
|
+
const CALLOUT_STATUS_GLYPH_VIEWBOX = "0 0 125 300";
|
|
4319
|
+
const CALLOUT_STATUS_GLYPH_PATH = "m25,1 8,196h59l8-196zm37,224a37,37 0 1,0 2,0z";
|
|
4320
|
+
|
|
4321
|
+
/**
|
|
4322
|
+
* @type {import("ignore:preact").FunctionComponent<{
|
|
4323
|
+
* status?: "info" | "warning" | "error" | "success" | "none",
|
|
4324
|
+
* shape?: "square" | "circle",
|
|
4325
|
+
* }>}
|
|
4326
|
+
* @param {"info"|"warning"|"error"|"success"|"none"} [status="info"] The color
|
|
4327
|
+
* — the callout's own for that status. `"none"` is the neutral one.
|
|
4328
|
+
* @param {"square"|"circle"} [shape="square"] Square like the callout's own
|
|
4329
|
+
* icon, or a circle.
|
|
4330
|
+
*/
|
|
4331
|
+
const CalloutStatusIcon = ({
|
|
4332
|
+
status = "info",
|
|
4333
|
+
shape = "square"
|
|
4334
|
+
}) => {
|
|
4335
|
+
import.meta.css = [css$12, "@jsenv/navi/src/control/rules/callout/callout_status_icon.jsx"];
|
|
4336
|
+
return jsx("span", {
|
|
4337
|
+
className: "navi_callout_status_icon",
|
|
4338
|
+
"data-status": status === "none" ? undefined : status,
|
|
4339
|
+
"data-shape": shape === "circle" ? "circle" : undefined,
|
|
4340
|
+
"aria-hidden": "true",
|
|
4341
|
+
children: jsx("svg", {
|
|
4342
|
+
viewBox: CALLOUT_STATUS_GLYPH_VIEWBOX,
|
|
4343
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
4344
|
+
children: jsx("path", {
|
|
4345
|
+
fill: "currentColor",
|
|
4346
|
+
d: CALLOUT_STATUS_GLYPH_PATH
|
|
4347
|
+
})
|
|
4348
|
+
})
|
|
4349
|
+
});
|
|
4350
|
+
};
|
|
4351
|
+
|
|
4244
4352
|
installImportMetaCssBuild(import.meta);/**
|
|
4245
4353
|
* A callout component that mimics native browser validation messages.
|
|
4246
4354
|
* Features:
|
|
@@ -4250,6 +4358,9 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
4250
4358
|
* - Arrow automatically shows when pointing at a valid anchor element
|
|
4251
4359
|
* - Centers in viewport when no anchor element provided or anchor is too big
|
|
4252
4360
|
*/
|
|
4361
|
+
|
|
4362
|
+
// Unique for the page's lifetime: a caller may write the id in a commandfor.
|
|
4363
|
+
let calloutCount = 0;
|
|
4253
4364
|
const css$11 = /* css */`
|
|
4254
4365
|
@layer navi {
|
|
4255
4366
|
.navi_callout {
|
|
@@ -4259,19 +4370,37 @@ const css$11 = /* css */`
|
|
|
4259
4370
|
copies. */
|
|
4260
4371
|
user-select: text;
|
|
4261
4372
|
|
|
4262
|
-
--callout-success-color:
|
|
4263
|
-
--callout-info-color:
|
|
4264
|
-
--callout-warning-color:
|
|
4265
|
-
--callout-error-color:
|
|
4373
|
+
--callout-success-color: var(--navi-callout-success-color);
|
|
4374
|
+
--callout-info-color: var(--navi-callout-info-color);
|
|
4375
|
+
--callout-warning-color: var(--navi-callout-warning-color);
|
|
4376
|
+
--callout-error-color: var(--navi-callout-error-color);
|
|
4377
|
+
--callout-neutral-color: var(--navi-callout-neutral-color);
|
|
4266
4378
|
|
|
4267
4379
|
--callout-background-color: white;
|
|
4268
4380
|
--callout-icon-color: black;
|
|
4269
4381
|
--callout-padding: 8px;
|
|
4270
4382
|
--callout-z-index: var(--navi-z-index-callout);
|
|
4383
|
+
/* The callout's own, like its font: the icon and the cross are columns
|
|
4384
|
+
one line tall (1lh), and that line has to be the message's first
|
|
4385
|
+
line — which it is only if both read the same line-height, rather
|
|
4386
|
+
than whatever the element the callout sits in happens to use. */
|
|
4387
|
+
--callout-line-height: 1.5;
|
|
4388
|
+
/* The cross is furniture, not content: quieter than the message beside
|
|
4389
|
+
it, and the size of a glyph on the message's first line. */
|
|
4390
|
+
--callout-close-button-color: color-mix(
|
|
4391
|
+
in srgb,
|
|
4392
|
+
currentColor 45%,
|
|
4393
|
+
transparent
|
|
4394
|
+
);
|
|
4395
|
+
--callout-close-button-color-hover: currentColor;
|
|
4396
|
+
--callout-close-button-size: 0.7em;
|
|
4271
4397
|
}
|
|
4272
4398
|
}
|
|
4273
4399
|
|
|
4274
4400
|
.navi_callout {
|
|
4401
|
+
/* No status until one is said (the data-status blocks below): a plain
|
|
4402
|
+
tooltip, framed in the neutral color and shown without an icon. */
|
|
4403
|
+
--x-callout-status-color: var(--callout-neutral-color);
|
|
4275
4404
|
--x-callout-border-color: var(--x-callout-status-color);
|
|
4276
4405
|
--x-callout-background-color: var(--callout-background-color);
|
|
4277
4406
|
--x-callout-icon-color: var(--x-callout-status-color);
|
|
@@ -4297,6 +4426,9 @@ const css$11 = /* css */`
|
|
|
4297
4426
|
color: revert; /* Do no inherit element color, callout is inside the element it should use document color though */
|
|
4298
4427
|
font-weight: initial; /* Callout fells disconnected from the element, font weight should be predictible and stable */
|
|
4299
4428
|
font-size: initial; /* Callout fells disconnected from the element, font size should be predictible and stable */
|
|
4429
|
+
line-height: var(
|
|
4430
|
+
--callout-line-height
|
|
4431
|
+
); /* Same reason — and what the columns measure their 1lh against */
|
|
4300
4432
|
background: transparent;
|
|
4301
4433
|
border: none;
|
|
4302
4434
|
outline: none; /* programmatic focus may land here briefly before being redirected to close button */
|
|
@@ -4326,6 +4458,11 @@ const css$11 = /* css */`
|
|
|
4326
4458
|
&[data-status="error"] {
|
|
4327
4459
|
--x-callout-status-color: var(--callout-error-color);
|
|
4328
4460
|
}
|
|
4461
|
+
&[data-close-button="none"] {
|
|
4462
|
+
.navi_callout_close_button_column {
|
|
4463
|
+
display: none;
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4329
4466
|
|
|
4330
4467
|
.navi_callout_box {
|
|
4331
4468
|
position: relative;
|
|
@@ -4376,6 +4513,15 @@ const css$11 = /* css */`
|
|
|
4376
4513
|
background-color: var(--x-callout-icon-color);
|
|
4377
4514
|
border-radius: 2px;
|
|
4378
4515
|
|
|
4516
|
+
/* Not drawn without a status (nothing to say about the message),
|
|
4517
|
+
nor when the message asked for none (icon: false). Nested in
|
|
4518
|
+
here rather than written beside this block: a rule one level up
|
|
4519
|
+
would lose to the display above on specificity alone. */
|
|
4520
|
+
.navi_callout:not([data-status]) &,
|
|
4521
|
+
.navi_callout[data-icon="none"] & {
|
|
4522
|
+
display: none;
|
|
4523
|
+
}
|
|
4524
|
+
|
|
4379
4525
|
svg {
|
|
4380
4526
|
width: 16px;
|
|
4381
4527
|
height: 12px;
|
|
@@ -4408,37 +4554,52 @@ const css$11 = /* css */`
|
|
|
4408
4554
|
.navi_callout_close_button_column {
|
|
4409
4555
|
display: flex;
|
|
4410
4556
|
height: var(--callout-icon-height);
|
|
4557
|
+
/* The button is a square one line tall around a cross of glyph size,
|
|
4558
|
+
so most of it is empty. Taken back on both sides: what is drawn then
|
|
4559
|
+
sits one gap from the text and one padding from the edge — where the
|
|
4560
|
+
icon sits on the other side — instead of that plus the button's own
|
|
4561
|
+
margin. The target keeps its full size; only the space it claims in
|
|
4562
|
+
the row shrinks. */
|
|
4563
|
+
margin-inline: calc(
|
|
4564
|
+
-1 * (var(--callout-icon-height) - var(--callout-close-button-size)) / 2
|
|
4565
|
+
);
|
|
4566
|
+
/* Whatever the cross measures, it sits on the middle of the first line
|
|
4567
|
+
— the line it is read with. */
|
|
4568
|
+
align-items: center;
|
|
4411
4569
|
align-self: flex-start;
|
|
4412
4570
|
|
|
4413
4571
|
.navi_callout_close_button {
|
|
4414
4572
|
/* A square filling the column, so the whole first line is the target;
|
|
4415
|
-
the
|
|
4573
|
+
the cross itself is drawn at glyph size in the middle of it. */
|
|
4416
4574
|
display: inline-flex;
|
|
4417
4575
|
box-sizing: border-box;
|
|
4418
4576
|
aspect-ratio: 1 / 1;
|
|
4419
4577
|
height: 100%;
|
|
4420
|
-
padding: 0
|
|
4578
|
+
padding: 0;
|
|
4421
4579
|
align-items: center;
|
|
4422
4580
|
justify-content: center;
|
|
4423
|
-
color:
|
|
4581
|
+
color: var(--callout-close-button-color);
|
|
4424
4582
|
font-size: inherit;
|
|
4425
4583
|
background: none;
|
|
4426
4584
|
border: none;
|
|
4427
4585
|
border-radius: 0.2em;
|
|
4586
|
+
/* transition: color 0.15s ease-in-out; */
|
|
4428
4587
|
cursor: pointer;
|
|
4429
4588
|
|
|
4430
4589
|
&:hover {
|
|
4431
|
-
|
|
4590
|
+
color: var(--callout-close-button-color-hover);
|
|
4591
|
+
background: rgba(0, 0, 0, 0.06);
|
|
4432
4592
|
}
|
|
4433
4593
|
|
|
4434
4594
|
&:focus-visible,
|
|
4435
4595
|
.navi_callout:focus-visible & {
|
|
4596
|
+
color: var(--callout-close-button-color-hover);
|
|
4436
4597
|
outline: auto;
|
|
4437
4598
|
}
|
|
4438
4599
|
|
|
4439
4600
|
.navi_callout_close_button_svg {
|
|
4440
|
-
width:
|
|
4441
|
-
height:
|
|
4601
|
+
width: var(--callout-close-button-size);
|
|
4602
|
+
height: var(--callout-close-button-size);
|
|
4442
4603
|
}
|
|
4443
4604
|
}
|
|
4444
4605
|
}
|
|
@@ -4453,6 +4614,11 @@ const css$11 = /* css */`
|
|
|
4453
4614
|
* @param {string} [options.status=""] - Callout status: "info" | "warning" | "error" | "success"
|
|
4454
4615
|
* @param {Function} [options.onClose] - Callback when callout is closed
|
|
4455
4616
|
* @param {boolean} [options.closeOnClickOutside] - Whether to close on outside clicks (defaults to true for "info" status)
|
|
4617
|
+
* @param {boolean} [options.icon=true] - Whether the status icon is shown beside the message.
|
|
4618
|
+
* Never shown without a status either way (see the CSS).
|
|
4619
|
+
* @param {boolean} [options.closeButton=true] - Whether the cross is shown. Without it the callout
|
|
4620
|
+
* still closes on Escape, a click outside and its own `--navi-close` — for a tooltip that is
|
|
4621
|
+
* read rather than dismissed
|
|
4456
4622
|
* @param {string} [options.reopen="toggle"] - What to do when the anchor already has an open callout:
|
|
4457
4623
|
* "toggle" closes it (a second press on what opened it closes it), "update" replaces its message
|
|
4458
4624
|
* in place, "replace" tears it down and opens a new one
|
|
@@ -4499,6 +4665,8 @@ const openCallout = (message, {
|
|
|
4499
4665
|
reopen = "toggle",
|
|
4500
4666
|
showErrorStack,
|
|
4501
4667
|
skipFocus = false,
|
|
4668
|
+
icon = true,
|
|
4669
|
+
closeButton = true,
|
|
4502
4670
|
debug = () => {}
|
|
4503
4671
|
} = {}) => {
|
|
4504
4672
|
import.meta.css = [css$11, "@jsenv/navi/src/control/rules/callout/callout.js"];
|
|
@@ -4655,10 +4823,27 @@ const openCallout = (message, {
|
|
|
4655
4823
|
}
|
|
4656
4824
|
requestClose(e, "click_close_button");
|
|
4657
4825
|
};
|
|
4658
|
-
|
|
4826
|
+
calloutCount++;
|
|
4827
|
+
const calloutId = `navi_callout_${calloutCount}`;
|
|
4659
4828
|
calloutElement.id = calloutId;
|
|
4660
4829
|
calloutElement.style.opacity = 0;
|
|
4661
4830
|
const update = (newMessage, options = {}) => {
|
|
4831
|
+
if (Object.hasOwn(options, "icon")) {
|
|
4832
|
+
if (options.icon === false) {
|
|
4833
|
+
calloutElement.setAttribute("data-icon", "none");
|
|
4834
|
+
} else {
|
|
4835
|
+
calloutElement.removeAttribute("data-icon");
|
|
4836
|
+
}
|
|
4837
|
+
}
|
|
4838
|
+
if (Object.hasOwn(options, "closeButton")) {
|
|
4839
|
+
// Per message rather than per callout: what replaces a message (a
|
|
4840
|
+
// constraint taking over a tooltip's callout) brings its own cross back.
|
|
4841
|
+
if (options.closeButton === false) {
|
|
4842
|
+
calloutElement.setAttribute("data-close-button", "none");
|
|
4843
|
+
} else {
|
|
4844
|
+
calloutElement.removeAttribute("data-close-button");
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4662
4847
|
const prevStatus = callout.status;
|
|
4663
4848
|
// Connect callout with target element for accessibility
|
|
4664
4849
|
if (options.status && options.status !== callout.status) {
|
|
@@ -4678,7 +4863,8 @@ const openCallout = (message, {
|
|
|
4678
4863
|
if (isValidElement(newMessage)) {
|
|
4679
4864
|
debug(`callout update message (jsx)`);
|
|
4680
4865
|
renderIntoCallout(newMessage, calloutMessageElement, {
|
|
4681
|
-
requestClose
|
|
4866
|
+
requestClose,
|
|
4867
|
+
element: calloutElement
|
|
4682
4868
|
});
|
|
4683
4869
|
} else if (newMessage instanceof Node) {
|
|
4684
4870
|
// Handle DOM node (cloned from CSS selector)
|
|
@@ -4690,9 +4876,11 @@ const openCallout = (message, {
|
|
|
4690
4876
|
clearCalloutMessage(calloutMessageElement);
|
|
4691
4877
|
newMessage({
|
|
4692
4878
|
renderIntoCallout: jsx => renderIntoCallout(jsx, calloutMessageElement, {
|
|
4693
|
-
requestClose
|
|
4879
|
+
requestClose,
|
|
4880
|
+
element: calloutElement
|
|
4694
4881
|
}),
|
|
4695
|
-
requestClose
|
|
4882
|
+
requestClose,
|
|
4883
|
+
element: calloutElement
|
|
4696
4884
|
});
|
|
4697
4885
|
} else {
|
|
4698
4886
|
if (Error.isError(newMessage)) {
|
|
@@ -4717,7 +4905,8 @@ const openCallout = (message, {
|
|
|
4717
4905
|
} else {
|
|
4718
4906
|
debug(`callout update message: ${typeof newMessage === "string" ? newMessage.slice(0, 80) : String(newMessage)}`);
|
|
4719
4907
|
renderHtmlIntoCallout(String(newMessage), calloutMessageElement, {
|
|
4720
|
-
requestClose
|
|
4908
|
+
requestClose,
|
|
4909
|
+
element: calloutElement
|
|
4721
4910
|
});
|
|
4722
4911
|
}
|
|
4723
4912
|
}
|
|
@@ -4932,6 +5121,21 @@ const openCallout = (message, {
|
|
|
4932
5121
|
};
|
|
4933
5122
|
calloutElement.addEventListener("navi_request_close", handleCustomCloseEvent);
|
|
4934
5123
|
}
|
|
5124
|
+
{
|
|
5125
|
+
// What a command said inside the callout is aimed at, once aria-expanded
|
|
5126
|
+
// made the callout its target (see calloutTemplate): run it, the way a
|
|
5127
|
+
// popup runs the commands aimed at it. Inlined rather than onNaviCommand
|
|
5128
|
+
// from commands.js, which already reaches this module through the callout
|
|
5129
|
+
// manager and must not be reached back.
|
|
5130
|
+
calloutElement.addEventListener("navi_command", e => {
|
|
5131
|
+
const {
|
|
5132
|
+
implementation
|
|
5133
|
+
} = e.detail;
|
|
5134
|
+
if (typeof implementation === "function") {
|
|
5135
|
+
implementation();
|
|
5136
|
+
}
|
|
5137
|
+
});
|
|
5138
|
+
}
|
|
4935
5139
|
Object.assign(callout, {
|
|
4936
5140
|
element: calloutElement,
|
|
4937
5141
|
update,
|
|
@@ -5030,7 +5234,9 @@ const openCallout = (message, {
|
|
|
5030
5234
|
});
|
|
5031
5235
|
}
|
|
5032
5236
|
update(message, {
|
|
5033
|
-
status
|
|
5237
|
+
status,
|
|
5238
|
+
icon,
|
|
5239
|
+
closeButton
|
|
5034
5240
|
});
|
|
5035
5241
|
|
|
5036
5242
|
// positionCallout itself handles both "no anchorElement at all" and "a
|
|
@@ -5056,21 +5262,25 @@ const ARROW_WIDTH = 16;
|
|
|
5056
5262
|
const ARROW_HEIGHT = 8;
|
|
5057
5263
|
const ARROW_SPACING = 8;
|
|
5058
5264
|
|
|
5059
|
-
//
|
|
5265
|
+
// aria-expanded is what --navi-close/--navi-cancel resolve their target with
|
|
5266
|
+
// (closest "[aria-expanded]", see commands.js): a button inside the callout
|
|
5267
|
+
// closes the callout, not the picker or dialog around it. Never "false" — a
|
|
5268
|
+
// closed callout is removed, not kept.
|
|
5060
5269
|
const calloutTemplate = /* html */`
|
|
5061
5270
|
<div
|
|
5062
5271
|
class="navi_callout"
|
|
5063
5272
|
popover="manual"
|
|
5273
|
+
aria-expanded="true"
|
|
5064
5274
|
>
|
|
5065
5275
|
<div class="navi_callout_box">
|
|
5066
5276
|
<div class="navi_callout_frame"></div>
|
|
5067
5277
|
<div class="navi_callout_body">
|
|
5068
5278
|
<div class="navi_callout_icon">
|
|
5069
|
-
<svg
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
/>
|
|
5279
|
+
<svg
|
|
5280
|
+
viewBox="${CALLOUT_STATUS_GLYPH_VIEWBOX}"
|
|
5281
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
5282
|
+
>
|
|
5283
|
+
<path fill="currentColor" d="${CALLOUT_STATUS_GLYPH_PATH}" />
|
|
5074
5284
|
</svg>
|
|
5075
5285
|
</div>
|
|
5076
5286
|
<!-- Keep .navi_callout_message so preact controls it -->
|
|
@@ -5719,6 +5929,8 @@ const createCalloutManager = (
|
|
|
5719
5929
|
const [, remainingTokenData] = tokens.entries().next().value;
|
|
5720
5930
|
callout.update(remainingTokenData.message, {
|
|
5721
5931
|
status: remainingTokenData.status,
|
|
5932
|
+
icon: remainingTokenData.icon,
|
|
5933
|
+
closeButton: remainingTokenData.closeButton,
|
|
5722
5934
|
});
|
|
5723
5935
|
}
|
|
5724
5936
|
return false;
|
|
@@ -5740,7 +5952,16 @@ const createCalloutManager = (
|
|
|
5740
5952
|
|
|
5741
5953
|
const addOpenToken = (
|
|
5742
5954
|
token,
|
|
5743
|
-
{
|
|
5955
|
+
{
|
|
5956
|
+
message,
|
|
5957
|
+
status,
|
|
5958
|
+
icon,
|
|
5959
|
+
closeButton,
|
|
5960
|
+
anchorElement,
|
|
5961
|
+
event,
|
|
5962
|
+
skipFocus,
|
|
5963
|
+
onClose,
|
|
5964
|
+
} = {},
|
|
5744
5965
|
) => {
|
|
5745
5966
|
if (!message) {
|
|
5746
5967
|
removeOpenToken(token, event);
|
|
@@ -5748,10 +5969,12 @@ const createCalloutManager = (
|
|
|
5748
5969
|
}
|
|
5749
5970
|
const calloutOptions = {
|
|
5750
5971
|
status,
|
|
5972
|
+
icon,
|
|
5973
|
+
closeButton,
|
|
5751
5974
|
closeOnClickOutside: status !== "error",
|
|
5752
5975
|
};
|
|
5753
5976
|
|
|
5754
|
-
tokens.set(token, { message, status, onClose });
|
|
5977
|
+
tokens.set(token, { message, status, icon, closeButton, onClose });
|
|
5755
5978
|
if (callout) {
|
|
5756
5979
|
callout.update(message, calloutOptions);
|
|
5757
5980
|
return;
|
|
@@ -5768,7 +5991,11 @@ const createCalloutManager = (
|
|
|
5768
5991
|
openingEvent: event,
|
|
5769
5992
|
skipFocus,
|
|
5770
5993
|
debug: debugPopup,
|
|
5771
|
-
onClose: ({
|
|
5994
|
+
onClose: ({
|
|
5995
|
+
event: closeEvent,
|
|
5996
|
+
reason,
|
|
5997
|
+
shouldTransferFocusFromCallout,
|
|
5998
|
+
}) => {
|
|
5772
5999
|
removeCloseOnCleanup?.();
|
|
5773
6000
|
for (const result of openResults) {
|
|
5774
6001
|
if (typeof result === "function") {
|
|
@@ -5777,8 +6004,10 @@ const createCalloutManager = (
|
|
|
5777
6004
|
}
|
|
5778
6005
|
callout = null;
|
|
5779
6006
|
// User dismissed the callout — notify all active tokens then clear.
|
|
6007
|
+
// Told what closed it: a token whose content is a popup of its own (a
|
|
6008
|
+
// picker in callout mode) closes that popup on the same event.
|
|
5780
6009
|
for (const [, tokenData] of tokens) {
|
|
5781
|
-
tokenData.onClose?.();
|
|
6010
|
+
tokenData.onClose?.({ event: closeEvent, reason });
|
|
5782
6011
|
}
|
|
5783
6012
|
tokens.clear();
|
|
5784
6013
|
const element = controller.ref.current;
|
|
@@ -24826,9 +25055,11 @@ const getHrefTargetInfo = (href) => {
|
|
|
24826
25055
|
* leave by where the reader came in, and the swipe (which replaces already, see
|
|
24827
25056
|
* route_travel.jsx) and the press say the same thing.
|
|
24828
25057
|
*
|
|
24829
|
-
* `<Link replace>` is that, and
|
|
24830
|
-
*
|
|
24831
|
-
*
|
|
25058
|
+
* `<Link replace>` is that, and so is `<Button replace>` — on an `href`, or on
|
|
25059
|
+
* a `--navi-nav-to` command. It travels as an attribute because whoever
|
|
25060
|
+
* answers the press sees the element, not the component that rendered it: the
|
|
25061
|
+
* click handler reads it off the anchor, the command off its source — the same
|
|
25062
|
+
* mouth as what a link asks of a route transition.
|
|
24832
25063
|
*/
|
|
24833
25064
|
|
|
24834
25065
|
const LINK_REPLACE_ATTRIBUTE = "data-navi-replace";
|
|
@@ -29529,7 +29760,25 @@ registerNaviCommand("--navi-nav-to", (source, event, { argument }) => {
|
|
|
29529
29760
|
const target = resolveExplicitTarget(source) || source;
|
|
29530
29761
|
return {
|
|
29531
29762
|
target,
|
|
29532
|
-
|
|
29763
|
+
// Which way there is worn by the source, as a link wears it (see
|
|
29764
|
+
// link_replace.js): `<Button command="--navi-nav-to:/done" replace>`.
|
|
29765
|
+
implementation: () =>
|
|
29766
|
+
navTo(
|
|
29767
|
+
argument,
|
|
29768
|
+
linkAsksForReplace(source) ? { replace: true } : undefined,
|
|
29769
|
+
),
|
|
29770
|
+
};
|
|
29771
|
+
});
|
|
29772
|
+
|
|
29773
|
+
// Back to the screen the reader came from, with somewhere to land when there
|
|
29774
|
+
// is none of ours behind — a url opened cold (see navBack). The fallback is
|
|
29775
|
+
// the argument for the reason --navi-nav-to's destination is: it says WHAT the
|
|
29776
|
+
// command does when there is nothing to go back to.
|
|
29777
|
+
registerNaviCommand("--navi-nav-back", (source, event, { argument }) => {
|
|
29778
|
+
const target = resolveExplicitTarget(source) || source;
|
|
29779
|
+
return {
|
|
29780
|
+
target,
|
|
29781
|
+
implementation: () => navBack({ fallback: argument }),
|
|
29533
29782
|
};
|
|
29534
29783
|
});
|
|
29535
29784
|
|
|
@@ -33296,6 +33545,21 @@ const useControlProps = (props, {
|
|
|
33296
33545
|
return defaultAction !== "type" && defaultAction !== "value_change";
|
|
33297
33546
|
};
|
|
33298
33547
|
if (controlType === "link") {
|
|
33548
|
+
// Nothing waits for a link's action: the press is a departure, and
|
|
33549
|
+
// the navigation goes whatever the action does — so its command goes
|
|
33550
|
+
// too, unlike a button's, which follows its action (see below).
|
|
33551
|
+
const onLinkInteractionAllowed = e => {
|
|
33552
|
+
triggerUIAction(e);
|
|
33553
|
+
const control = ref.current;
|
|
33554
|
+
if (!control) {
|
|
33555
|
+
return;
|
|
33556
|
+
}
|
|
33557
|
+
tryActionAfterInteractionAllowed(control, {
|
|
33558
|
+
event: e,
|
|
33559
|
+
action: boundAction,
|
|
33560
|
+
requester: control
|
|
33561
|
+
});
|
|
33562
|
+
};
|
|
33299
33563
|
return {
|
|
33300
33564
|
keyDown: e => {
|
|
33301
33565
|
if (isSpaceToActivate(e)) {
|
|
@@ -33314,6 +33578,7 @@ const useControlProps = (props, {
|
|
|
33314
33578
|
click: e => {
|
|
33315
33579
|
return {
|
|
33316
33580
|
name: "click",
|
|
33581
|
+
allowed: () => onLinkInteractionAllowed(e),
|
|
33317
33582
|
prevented: () => {
|
|
33318
33583
|
e.preventDefault();
|
|
33319
33584
|
}
|
|
@@ -33541,6 +33806,15 @@ const useControlProps = (props, {
|
|
|
33541
33806
|
};
|
|
33542
33807
|
if (isRadio) {
|
|
33543
33808
|
if (checked) {
|
|
33809
|
+
if (props.deselectable) {
|
|
33810
|
+
return {
|
|
33811
|
+
name: "enter to uncheck radio",
|
|
33812
|
+
allowed: () => dispatchRequestSetUIState(inputEl, undefined, {
|
|
33813
|
+
event: e
|
|
33814
|
+
}),
|
|
33815
|
+
always
|
|
33816
|
+
};
|
|
33817
|
+
}
|
|
33544
33818
|
return {
|
|
33545
33819
|
name: "enter on checked radio",
|
|
33546
33820
|
allowed: () => triggerUIAction(e),
|
|
@@ -33566,6 +33840,14 @@ const useControlProps = (props, {
|
|
|
33566
33840
|
if (isRadio && e.key === " ") {
|
|
33567
33841
|
const inputEl = e.currentTarget;
|
|
33568
33842
|
if (inputEl.checked) {
|
|
33843
|
+
if (props.deselectable) {
|
|
33844
|
+
return {
|
|
33845
|
+
name: "space to uncheck radio",
|
|
33846
|
+
allowed: () => dispatchRequestSetUIState(inputEl, undefined, {
|
|
33847
|
+
event: e
|
|
33848
|
+
})
|
|
33849
|
+
};
|
|
33850
|
+
}
|
|
33569
33851
|
// allow space to still trigger uiState and commands
|
|
33570
33852
|
// on checked radios (won't update the ui state but will notify of interaction)
|
|
33571
33853
|
return {
|
|
@@ -33591,6 +33873,20 @@ const useControlProps = (props, {
|
|
|
33591
33873
|
// that lands on the <label> (not the <input>) never fires "mousedown" on
|
|
33592
33874
|
// the input at all, so a DOM-snapshot-at-mousedown approach misses it.
|
|
33593
33875
|
if (isRadio && uiStateController.uiState !== undefined) {
|
|
33876
|
+
if (props.deselectable) {
|
|
33877
|
+
// Not prevented: a prevented click has the browser put the
|
|
33878
|
+
// radio back to checked once the listeners are done. Left to
|
|
33879
|
+
// run, it changes nothing (the radio was checked already) and
|
|
33880
|
+
// reports nothing — a radio getting unchecked fires no input
|
|
33881
|
+
// event — so this is the one place the uncheck is said.
|
|
33882
|
+
return {
|
|
33883
|
+
name: `click to uncheck radio`,
|
|
33884
|
+
allowed: () => dispatchRequestSetUIState(ref.current, undefined, {
|
|
33885
|
+
event: e
|
|
33886
|
+
}),
|
|
33887
|
+
prevented: () => e.preventDefault()
|
|
33888
|
+
};
|
|
33889
|
+
}
|
|
33594
33890
|
return {
|
|
33595
33891
|
name: `click on checked radio`,
|
|
33596
33892
|
allowed: () => triggerUIAction(e),
|
|
@@ -38584,6 +38880,14 @@ Object.assign(PSEUDO_CLASSES, {
|
|
|
38584
38880
|
* way there changes. What a row of tabs wants — the neighbour is a lateral
|
|
38585
38881
|
* move, not a step deeper, so the whole row weighs one entry and the back
|
|
38586
38882
|
* button leaves by where the reader came in.
|
|
38883
|
+
* @param {string} [props.command] - What the press asks of a control around
|
|
38884
|
+
* the link — `"--navi-close"` on a link that leaves the sheet it is in.
|
|
38885
|
+
* Triggered on the press, before the navigation.
|
|
38886
|
+
* @param {Function} [props.action] - Work the press runs, before the
|
|
38887
|
+
* navigation. Nothing waits for it — not the navigation, not `command`: what
|
|
38888
|
+
* the next page must find has to be written synchronously (a draft in a
|
|
38889
|
+
* signal), and a request goes on its own while the page changes. Work that
|
|
38890
|
+
* decides the destination navigates itself, from a `<Button action>`.
|
|
38587
38891
|
* @param {boolean} [props.preventDefault] - Call `event.preventDefault()` on
|
|
38588
38892
|
* click (navigation suppressed; `onClick` still runs).
|
|
38589
38893
|
* @param {(event: MouseEvent) => void} [props.onClick]
|
|
@@ -38884,7 +39188,7 @@ const LinkPlain = props => {
|
|
|
38884
39188
|
"data-current-effect-shadow": currentEffectShadow ? "" : undefined,
|
|
38885
39189
|
"data-current-indicator-position": currentIndicatorPosition,
|
|
38886
39190
|
"data-anchor": anchor ? "" : undefined,
|
|
38887
|
-
"data-interactive": onClick ? "" : undefined,
|
|
39191
|
+
"data-interactive": onClick || props.command || props.action ? "" : undefined,
|
|
38888
39192
|
"data-reveal-on-interaction": revealOnInteraction ? "" : undefined,
|
|
38889
39193
|
baseClassName: "navi_link",
|
|
38890
39194
|
styleCSSVars: LinkStyleCSSVars,
|
|
@@ -45160,6 +45464,7 @@ const ButtonUI = props => {
|
|
|
45160
45464
|
href,
|
|
45161
45465
|
target,
|
|
45162
45466
|
rel,
|
|
45467
|
+
replace,
|
|
45163
45468
|
// visual
|
|
45164
45469
|
variant,
|
|
45165
45470
|
pressEffect,
|
|
@@ -45206,6 +45511,12 @@ const ButtonUI = props => {
|
|
|
45206
45511
|
...basePseudoState,
|
|
45207
45512
|
":-navi-href-current": innerCurrent
|
|
45208
45513
|
};
|
|
45514
|
+
|
|
45515
|
+
// Worn as an attribute, like a link's (see link_replace.js): read off the
|
|
45516
|
+
// anchor by the click handler, off the source by --navi-nav-to.
|
|
45517
|
+
const replaceRequest = replace ? {
|
|
45518
|
+
[LINK_REPLACE_ATTRIBUTE]: ""
|
|
45519
|
+
} : null;
|
|
45209
45520
|
const visualSelector = ".navi_button_content";
|
|
45210
45521
|
useAccentColorAttributes(ref, null, {
|
|
45211
45522
|
elementSelector: visualSelector
|
|
@@ -45232,11 +45543,11 @@ const ButtonUI = props => {
|
|
|
45232
45543
|
as: as,
|
|
45233
45544
|
href: href,
|
|
45234
45545
|
target: innerTarget,
|
|
45235
|
-
rel: innerRel
|
|
45546
|
+
rel: innerRel,
|
|
45547
|
+
replace: undefined,
|
|
45548
|
+
...replaceRequest,
|
|
45236
45549
|
// Respond with the JS prop value directly so callers (e.g. resolveCommandValue)
|
|
45237
45550
|
// get the original type instead of the DOM-coerced string (e.g. "[object Object]").
|
|
45238
|
-
,
|
|
45239
|
-
|
|
45240
45551
|
onnavi_get_value: e => {
|
|
45241
45552
|
e.detail.respondWith(props.value);
|
|
45242
45553
|
},
|
|
@@ -45454,8 +45765,13 @@ const COMMAND_DEFAULT_PROPS_FACTORIES = {
|
|
|
45454
45765
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
45455
45766
|
* ownTarget?: boolean | "refuse" | "always",
|
|
45456
45767
|
* emojiAsIcon?: boolean,
|
|
45768
|
+
* replace?: boolean,
|
|
45457
45769
|
* [key: string]: any,
|
|
45458
45770
|
* }>}
|
|
45771
|
+
* @param {boolean} [replace] Go where the press leads — an `href`, a
|
|
45772
|
+
* `--navi-nav-to` command — by TAKING THE PLACE of the current history entry
|
|
45773
|
+
* rather than stacking on it: what `<Link replace>` says, for a press drawn
|
|
45774
|
+
* as a button.
|
|
45459
45775
|
* @param {boolean} [emojiAsIcon=true] Renders the emoji of the label as icons
|
|
45460
45776
|
* so the button keeps the height of its text — `Text`'s prop, on by default
|
|
45461
45777
|
* here. Pass `false` to let an emoji draw at its natural size.
|
|
@@ -56105,6 +56421,40 @@ const PickerCustomResolver = props => {
|
|
|
56105
56421
|
...props
|
|
56106
56422
|
});
|
|
56107
56423
|
}
|
|
56424
|
+
if (props.mode === "callout") {
|
|
56425
|
+
// A tooltip is an icon one presses, unless told otherwise. Own-property
|
|
56426
|
+
// rather than undefined: an explicit variant={undefined} asks for the
|
|
56427
|
+
// field-like drawing back. "circle" is the icon variant with the status
|
|
56428
|
+
// icon drawn round — a word about the trigger, not a drawing of its own.
|
|
56429
|
+
if (!Object.hasOwn(props, "variant")) {
|
|
56430
|
+
props.variant = "icon";
|
|
56431
|
+
}
|
|
56432
|
+
const circle = props.variant === "circle";
|
|
56433
|
+
if (circle) {
|
|
56434
|
+
props.variant = "icon";
|
|
56435
|
+
}
|
|
56436
|
+
// A word in a sentence asks for a plain tooltip — no icon in the callout,
|
|
56437
|
+
// no status color; an icon one presses is the callout's own status icon,
|
|
56438
|
+
// and says "info" like the callout it opens.
|
|
56439
|
+
if (props.calloutStatus === undefined) {
|
|
56440
|
+
props.calloutStatus = props.variant === "text" ? "none" : "info";
|
|
56441
|
+
}
|
|
56442
|
+
if (props.calloutIcon === undefined) {
|
|
56443
|
+
props.calloutIcon = props.variant !== "text";
|
|
56444
|
+
}
|
|
56445
|
+
if (props.rightSlotIcon === undefined) {
|
|
56446
|
+
props.rightSlotIcon = jsx(CalloutStatusIcon, {
|
|
56447
|
+
status: props.calloutStatus,
|
|
56448
|
+
shape: circle ? "circle" : "square"
|
|
56449
|
+
});
|
|
56450
|
+
}
|
|
56451
|
+
// The arrow on the middle of what was pressed — an icon, a word — rather
|
|
56452
|
+
// than on where its text starts, which is where a callout points at a
|
|
56453
|
+
// field by default (see the anchor attributes in callout.js).
|
|
56454
|
+
if (props["data-callout-arrow-x"] === undefined) {
|
|
56455
|
+
props["data-callout-arrow-x"] = "center";
|
|
56456
|
+
}
|
|
56457
|
+
}
|
|
56108
56458
|
if (props.type === undefined) {
|
|
56109
56459
|
// A picker with a popup of its own holds whatever the control inside it
|
|
56110
56460
|
// holds — a boolean, a number, an id — and a field with no type is read
|
|
@@ -56448,7 +56798,9 @@ const PickerCustom = props => {
|
|
|
56448
56798
|
// opens anything. Told a value — even an empty one — the picker owns it
|
|
56449
56799
|
// and pushes it down instead, leaving the popup free to build its
|
|
56450
56800
|
// content only when it is first opened (see popup_content_mount.js).
|
|
56451
|
-
|
|
56801
|
+
// A caller who knows better says so with the popup's own props.
|
|
56802
|
+
mountWhenClosed: props.mountWhenClosed ?? !isControlValueGivenByProps(props),
|
|
56803
|
+
unmountWhenClosed: props.unmountWhenClosed,
|
|
56452
56804
|
// Not on pickerProps (the trigger): commands.js's own
|
|
56453
56805
|
// resolveClosestExpandable() does `el.closest("[aria-expanded]")` to
|
|
56454
56806
|
// find where to dispatch navi_request_open/navi_request_close — and
|
|
@@ -56687,6 +57039,9 @@ const PickerContentInsidePopup = props => {
|
|
|
56687
57039
|
// but popupProps is built explicitly here, so it only travels if named.
|
|
56688
57040
|
// "popupLayer" rather than "layer": the picker itself is not the popup.
|
|
56689
57041
|
popupLayer,
|
|
57042
|
+
// Same reason: a `data-testid` on the picker names the trigger (see
|
|
57043
|
+
// docs/testid.md) — this one names the popup.
|
|
57044
|
+
popupTestId,
|
|
56690
57045
|
positionArea,
|
|
56691
57046
|
popoverMode = "nearby",
|
|
56692
57047
|
popoverSpacing = popoverMode === "nearby" ? 5 : 0,
|
|
@@ -56708,13 +57063,26 @@ const PickerContentInsidePopup = props => {
|
|
|
56708
57063
|
// marginWithAnchor.
|
|
56709
57064
|
dockedOnSmallTouchScreen,
|
|
56710
57065
|
animation,
|
|
57066
|
+
// mode="callout": what the callout says about what it holds, and paints
|
|
57067
|
+
// in its border and icon — "none" for a plain tooltip (see the callout
|
|
57068
|
+
// defaults in PickerCustomResolver). And whether it wears a cross: without
|
|
57069
|
+
// one it still closes on Escape, a click outside, or a --navi-close of the
|
|
57070
|
+
// content's own.
|
|
57071
|
+
calloutStatus,
|
|
57072
|
+
calloutIcon,
|
|
57073
|
+
calloutCloseButton,
|
|
56711
57074
|
...rest
|
|
56712
57075
|
} = props;
|
|
56713
57076
|
const isPopover = mode === "popover";
|
|
57077
|
+
const isCallout = mode === "callout";
|
|
56714
57078
|
return jsx(Next, {
|
|
56715
57079
|
"aria-haspopup": isPopover ? "listbox" : "dialog",
|
|
56716
57080
|
"navi-popover-mode": isPopover ? popoverMode : undefined,
|
|
56717
57081
|
...rest,
|
|
57082
|
+
// On popupProps already (see the picker's popup assembly); they mean
|
|
57083
|
+
// nothing to the picker element.
|
|
57084
|
+
mountWhenClosed: undefined,
|
|
57085
|
+
unmountWhenClosed: undefined,
|
|
56718
57086
|
onFocusOut: e => {
|
|
56719
57087
|
if (!isPopover || !closeOnFocusOut) {
|
|
56720
57088
|
return;
|
|
@@ -56739,8 +57107,19 @@ const PickerContentInsidePopup = props => {
|
|
|
56739
57107
|
}
|
|
56740
57108
|
});
|
|
56741
57109
|
},
|
|
56742
|
-
children: jsx(
|
|
57110
|
+
children: isCallout ? jsx(PickerCalloutPopup, {
|
|
56743
57111
|
...popupProps,
|
|
57112
|
+
pickerRef: props.ref,
|
|
57113
|
+
status: calloutStatus,
|
|
57114
|
+
icon: calloutIcon,
|
|
57115
|
+
closeButton: calloutCloseButton,
|
|
57116
|
+
children: jsx(PopupModeContext.Provider, {
|
|
57117
|
+
value: mode,
|
|
57118
|
+
children: children
|
|
57119
|
+
})
|
|
57120
|
+
}) : jsx(Popup, {
|
|
57121
|
+
...popupProps,
|
|
57122
|
+
"data-testid": popupTestId,
|
|
56744
57123
|
mode: mode,
|
|
56745
57124
|
layer: popupLayer,
|
|
56746
57125
|
animation: animation,
|
|
@@ -56763,6 +57142,112 @@ const PickerContentInsidePopup = props => {
|
|
|
56763
57142
|
});
|
|
56764
57143
|
};
|
|
56765
57144
|
|
|
57145
|
+
// One token per picker rather than per instance: a callout manager belongs to
|
|
57146
|
+
// one control, so the key only has to be distinct from the other reasons that
|
|
57147
|
+
// control may have to show a callout (a failing constraint, a busy refusal, its
|
|
57148
|
+
// `error` prop). Those keep working on top of this one: opened while the
|
|
57149
|
+
// content is up they take the callout over, and give it back when they go.
|
|
57150
|
+
const PICKER_CALLOUT_CONTENT_TOKEN = createOpenToken();
|
|
57151
|
+
|
|
57152
|
+
/**
|
|
57153
|
+
* The popup of a `mode="callout"` picker: the picker's own callout — the one
|
|
57154
|
+
* its constraints speak in — showing the picker's children instead of a
|
|
57155
|
+
* message. A speech bubble on the trigger, for a tooltip that opens on a press.
|
|
57156
|
+
*
|
|
57157
|
+
* Wired the way Popover and Dialog are, through `openController.openEffect`:
|
|
57158
|
+
* opening adds a token to the picker's callout manager, whose cleanup removes
|
|
57159
|
+
* it. The callout has ways out of its own (its cross, a click outside, Escape,
|
|
57160
|
+
* focus leaving the picker) and says so through the token's `onClose`, which
|
|
57161
|
+
* closes the controller for real — the popup is already gone, there is no
|
|
57162
|
+
* choice left to offer `requestClose`.
|
|
57163
|
+
*
|
|
57164
|
+
* The content is rendered through a portal into an element this component
|
|
57165
|
+
* owns, handed to the callout as its message (a Node, appended as-is). It is
|
|
57166
|
+
* rendered whether the callout is open or not, so what the content holds
|
|
57167
|
+
* survives a close, the way a popup's `mountWhenClosed` keeps it. The element
|
|
57168
|
+
* carries data-picker-content: the callout is appended inside the picker root,
|
|
57169
|
+
* and a press in there must read as inside the popup, not on the trigger.
|
|
57170
|
+
*/
|
|
57171
|
+
const PickerCalloutPopup = ({
|
|
57172
|
+
ref,
|
|
57173
|
+
id,
|
|
57174
|
+
anchor,
|
|
57175
|
+
openController,
|
|
57176
|
+
pickerRef,
|
|
57177
|
+
status,
|
|
57178
|
+
icon,
|
|
57179
|
+
closeButton,
|
|
57180
|
+
onnavi_request_open,
|
|
57181
|
+
onnavi_request_close,
|
|
57182
|
+
onnavi_request_confirm,
|
|
57183
|
+
children
|
|
57184
|
+
}) => {
|
|
57185
|
+
const hostRef = useRef(null);
|
|
57186
|
+
if (!hostRef.current) {
|
|
57187
|
+
const host = document.createElement("div");
|
|
57188
|
+
host.setAttribute("data-picker-content", "");
|
|
57189
|
+
hostRef.current = host;
|
|
57190
|
+
}
|
|
57191
|
+
// Reassigned on every render, like Popover's own, so it closes over the
|
|
57192
|
+
// latest props.
|
|
57193
|
+
openController.openEffect = openEvent => {
|
|
57194
|
+
const pickerEl = pickerRef.current;
|
|
57195
|
+
const calloutManager = getPickerInput(pickerEl).__uiStateController__.rules.callout;
|
|
57196
|
+
// Only an anchor the caller named: left unsaid, the manager anchors on the
|
|
57197
|
+
// picker's own input — which is where the data-callout-* attributes a
|
|
57198
|
+
// caller puts on the picker land, and where the callout reads them.
|
|
57199
|
+
const anchorElement = anchor === pickerRef ? undefined : anchor && "current" in anchor ? anchor.current : anchor;
|
|
57200
|
+
calloutManager.addOpenToken(PICKER_CALLOUT_CONTENT_TOKEN, {
|
|
57201
|
+
message: hostRef.current,
|
|
57202
|
+
// "none" is the picker's word for it; the callout's is no status at all.
|
|
57203
|
+
status: status === "none" ? undefined : status,
|
|
57204
|
+
icon,
|
|
57205
|
+
closeButton,
|
|
57206
|
+
anchorElement,
|
|
57207
|
+
// The request, chained to the press that made it: the callout reads the
|
|
57208
|
+
// mousedown off it to wait for the release before listening for a click
|
|
57209
|
+
// outside — the same gesture's own click would close it otherwise.
|
|
57210
|
+
event: openEvent,
|
|
57211
|
+
// Not skipped: the callout moves the focus into the picker when it is
|
|
57212
|
+
// elsewhere, which is what lets Escape find the callout right away.
|
|
57213
|
+
skipFocus: false,
|
|
57214
|
+
onClose: ({
|
|
57215
|
+
event
|
|
57216
|
+
}) => {
|
|
57217
|
+
openController.close(event);
|
|
57218
|
+
}
|
|
57219
|
+
});
|
|
57220
|
+
// A --navi-confirm said inside the callout is aimed at the callout (its
|
|
57221
|
+
// aria-expanded), not at the element the picker listens on: carried over,
|
|
57222
|
+
// for a confirm picker whose question is a speech bubble.
|
|
57223
|
+
const calloutElement = calloutManager.callout.element;
|
|
57224
|
+
const forwardConfirm = e => {
|
|
57225
|
+
onnavi_request_confirm?.(e);
|
|
57226
|
+
};
|
|
57227
|
+
calloutElement.addEventListener("navi_request_confirm", forwardConfirm);
|
|
57228
|
+
return closeEvent => {
|
|
57229
|
+
calloutElement.removeEventListener("navi_request_confirm", forwardConfirm);
|
|
57230
|
+
calloutManager.removeOpenToken(PICKER_CALLOUT_CONTENT_TOKEN, closeEvent);
|
|
57231
|
+
};
|
|
57232
|
+
};
|
|
57233
|
+
return (
|
|
57234
|
+
// What the picker addresses (aria-controls, the request events it
|
|
57235
|
+
// forwards); the callout itself lives where the callout manager puts it.
|
|
57236
|
+
jsx(Box, {
|
|
57237
|
+
as: "span",
|
|
57238
|
+
ref: ref,
|
|
57239
|
+
id: id,
|
|
57240
|
+
style: {
|
|
57241
|
+
display: "contents"
|
|
57242
|
+
},
|
|
57243
|
+
onnavi_request_open: onnavi_request_open,
|
|
57244
|
+
onnavi_request_close: onnavi_request_close,
|
|
57245
|
+
onnavi_request_confirm: onnavi_request_confirm,
|
|
57246
|
+
children: createPortal(children, hostRef.current)
|
|
57247
|
+
})
|
|
57248
|
+
);
|
|
57249
|
+
};
|
|
57250
|
+
|
|
56766
57251
|
installImportMetaCssBuild(import.meta);/**
|
|
56767
57252
|
* A trigger that asks "are you sure?" before doing what it stands for.
|
|
56768
57253
|
*
|
|
@@ -56811,6 +57296,8 @@ const PickerConfirmResolver = props => {
|
|
|
56811
57296
|
message,
|
|
56812
57297
|
confirmLabel,
|
|
56813
57298
|
cancelLabel,
|
|
57299
|
+
confirmTestId,
|
|
57300
|
+
cancelTestId,
|
|
56814
57301
|
focusOnOpen = "confirm",
|
|
56815
57302
|
// A popover whatever the screen: the question is short and about the
|
|
56816
57303
|
// control it points at, and a sheet sliding up for one sentence is too
|
|
@@ -56854,15 +57341,25 @@ const PickerConfirmResolver = props => {
|
|
|
56854
57341
|
mode: mode,
|
|
56855
57342
|
focusCapture: focusCapture,
|
|
56856
57343
|
openWhileReadOnly: openWhileReadOnly,
|
|
56857
|
-
onConfirm: onConfirm
|
|
57344
|
+
onConfirm: onConfirm
|
|
57345
|
+
// A question holds no value to read before it is asked: the popup is
|
|
57346
|
+
// built on the first open, like that of a picker told its value (see
|
|
57347
|
+
// mountWhenClosed in picker_custom.jsx).
|
|
57348
|
+
,
|
|
57349
|
+
|
|
57350
|
+
mountWhenClosed: false,
|
|
56858
57351
|
message: undefined,
|
|
56859
57352
|
confirmLabel: undefined,
|
|
56860
57353
|
cancelLabel: undefined,
|
|
57354
|
+
confirmTestId: undefined,
|
|
57355
|
+
cancelTestId: undefined,
|
|
56861
57356
|
focusOnOpen: undefined,
|
|
56862
57357
|
children: children === undefined ? jsx(PickerConfirmBody, {
|
|
56863
57358
|
message: message,
|
|
56864
57359
|
confirmLabel: confirmLabel,
|
|
56865
57360
|
cancelLabel: cancelLabel,
|
|
57361
|
+
confirmTestId: confirmTestId,
|
|
57362
|
+
cancelTestId: cancelTestId,
|
|
56866
57363
|
focusOnOpen: focusOnOpen
|
|
56867
57364
|
}) : children
|
|
56868
57365
|
});
|
|
@@ -56871,6 +57368,8 @@ const PickerConfirmBody = ({
|
|
|
56871
57368
|
message,
|
|
56872
57369
|
confirmLabel,
|
|
56873
57370
|
cancelLabel,
|
|
57371
|
+
confirmTestId,
|
|
57372
|
+
cancelTestId,
|
|
56874
57373
|
focusOnOpen
|
|
56875
57374
|
}) => {
|
|
56876
57375
|
return jsxs("div", {
|
|
@@ -56882,10 +57381,12 @@ const PickerConfirmBody = ({
|
|
|
56882
57381
|
children: [jsx(Button, {
|
|
56883
57382
|
command: "--navi-cancel",
|
|
56884
57383
|
autoFocus: focusOnOpen === "cancel",
|
|
57384
|
+
"data-testid": cancelTestId,
|
|
56885
57385
|
children: cancelLabel
|
|
56886
57386
|
}), jsx(Button, {
|
|
56887
57387
|
command: "--navi-confirm",
|
|
56888
57388
|
autoFocus: focusOnOpen === "confirm",
|
|
57389
|
+
"data-testid": confirmTestId,
|
|
56889
57390
|
children: confirmLabel
|
|
56890
57391
|
})]
|
|
56891
57392
|
})]
|
|
@@ -57847,6 +58348,9 @@ installImportMetaCssBuild(import.meta);const css$z = /* css */`
|
|
|
57847
58348
|
}
|
|
57848
58349
|
`;
|
|
57849
58350
|
const SelectableListMultipleContext = createContext(false);
|
|
58351
|
+
// A single-select list whose selected row, pressed again, lets go: what its
|
|
58352
|
+
// rows' radios need to know to answer the press (see `deselectable` on Input).
|
|
58353
|
+
const SelectableListDeselectableContext = createContext(false);
|
|
57850
58354
|
// A row of a selectable list is selectable — the list is what decides, and a
|
|
57851
58355
|
// row says nothing unless it wants out (`selectable={false}` on a row that is
|
|
57852
58356
|
// only there to be read). Also set to false by a non-selectable list, so a list
|
|
@@ -57878,6 +58382,7 @@ const ListSelectable = props => {
|
|
|
57878
58382
|
const {
|
|
57879
58383
|
ref,
|
|
57880
58384
|
multiple,
|
|
58385
|
+
deselectable,
|
|
57881
58386
|
focusGroupDirection,
|
|
57882
58387
|
focusGroupWrap
|
|
57883
58388
|
} = props;
|
|
@@ -58014,6 +58519,7 @@ const ListSelectable = props => {
|
|
|
58014
58519
|
defaultValue: undefined,
|
|
58015
58520
|
selectable: undefined,
|
|
58016
58521
|
multiple: undefined,
|
|
58522
|
+
deselectable: undefined,
|
|
58017
58523
|
focusGroupDirection: undefined,
|
|
58018
58524
|
focusGroupWrap: undefined
|
|
58019
58525
|
// Track focus inside the list: whichever item gets focus becomes current.
|
|
@@ -58136,7 +58642,7 @@ const ListSelectable = props => {
|
|
|
58136
58642
|
if (!currentId) {
|
|
58137
58643
|
return;
|
|
58138
58644
|
}
|
|
58139
|
-
if (multiple) {
|
|
58645
|
+
if (multiple || deselectable) {
|
|
58140
58646
|
const inputId = `${currentId}_input`;
|
|
58141
58647
|
const childController = uiGroupStateController.findChildById(inputId);
|
|
58142
58648
|
const isSelected = childController && childController.uiState;
|
|
@@ -58160,7 +58666,10 @@ const ListSelectable = props => {
|
|
|
58160
58666
|
value: true,
|
|
58161
58667
|
children: jsx(SelectableListMultipleContext.Provider, {
|
|
58162
58668
|
value: multiple,
|
|
58163
|
-
children:
|
|
58669
|
+
children: jsx(SelectableListDeselectableContext.Provider, {
|
|
58670
|
+
value: Boolean(deselectable),
|
|
58671
|
+
children: listVnode
|
|
58672
|
+
})
|
|
58164
58673
|
})
|
|
58165
58674
|
});
|
|
58166
58675
|
};
|
|
@@ -58209,6 +58718,8 @@ const ListItemSelectable = props => {
|
|
|
58209
58718
|
...rest
|
|
58210
58719
|
} = props;
|
|
58211
58720
|
const multiple = useContext(SelectableListMultipleContext);
|
|
58721
|
+
// A checkbox toggles on its own; only a radio has to be told it may let go.
|
|
58722
|
+
const deselectable = useContext(SelectableListDeselectableContext) && !multiple;
|
|
58212
58723
|
// Whose reason it is that this row cannot be taken. Read-only reaching it
|
|
58213
58724
|
// from above is the LIST's, and what is settled is then the whole answer —
|
|
58214
58725
|
// said as the selection where several things are taken, as the choice where
|
|
@@ -58231,6 +58742,7 @@ const ListItemSelectable = props => {
|
|
|
58231
58742
|
ref: inputRef,
|
|
58232
58743
|
id: inputId,
|
|
58233
58744
|
type: inputType,
|
|
58745
|
+
deselectable,
|
|
58234
58746
|
defaultChecked: defaultSelected,
|
|
58235
58747
|
...(hasSelectedProp ? {
|
|
58236
58748
|
checked: selected
|
|
@@ -58249,9 +58761,10 @@ const ListItemSelectable = props => {
|
|
|
58249
58761
|
type: inputType,
|
|
58250
58762
|
checked,
|
|
58251
58763
|
readOnly,
|
|
58252
|
-
value
|
|
58764
|
+
value,
|
|
58765
|
+
deselectable
|
|
58253
58766
|
};
|
|
58254
|
-
}, [inputId, inputType, checked, readOnly, value]);
|
|
58767
|
+
}, [inputId, inputType, checked, readOnly, value, deselectable]);
|
|
58255
58768
|
return jsxs(Next, {
|
|
58256
58769
|
id: id,
|
|
58257
58770
|
index: index,
|
|
@@ -59489,6 +60002,7 @@ const ListFirstResolver = props => {
|
|
|
59489
60002
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
59490
60003
|
* selectable?: boolean,
|
|
59491
60004
|
* multiple?: boolean,
|
|
60005
|
+
* deselectable?: boolean,
|
|
59492
60006
|
* maxLength?: number,
|
|
59493
60007
|
* maxLengthGuard?: number,
|
|
59494
60008
|
* action?: (value: any) => void,
|
|
@@ -59613,6 +60127,11 @@ const ListFirstResolver = props => {
|
|
|
59613
60127
|
* Pass `true` for a list whose rows must stay live under the pointer while
|
|
59614
60128
|
* it scrolls. The trade of the default is the mirror one: right after a
|
|
59615
60129
|
* scroll, the row under the pointer lights up only once the pointer moves.
|
|
60130
|
+
* @param {boolean} [props.deselectable]
|
|
60131
|
+
* A single-select list allowed to hold nothing: the selected row, pressed
|
|
60132
|
+
* again, lets go. Without it the list is a radio group — a choice, once
|
|
60133
|
+
* made, moves to another row but never goes away. A `multiple` list toggles
|
|
60134
|
+
* its rows already.
|
|
59616
60135
|
* @param {number} [props.maxLength]
|
|
59617
60136
|
* How many items a `selectable multiple` list accepts — the same word, and
|
|
59618
60137
|
* the same behaviour, as `maxLength` on a text field: a rule the list is
|
|
@@ -64625,6 +65144,31 @@ installImportMetaCssBuild(import.meta);const css$u = /* css */`
|
|
|
64625
65144
|
|
|
64626
65145
|
text-align: center;
|
|
64627
65146
|
}
|
|
65147
|
+
/* text: a word in a sentence, marked by the dotted line under it — the way
|
|
65148
|
+
a term one can ask about is marked. No box, no slot; the font is the
|
|
65149
|
+
sentence's own, so the word sits in its line like the ones around it. */
|
|
65150
|
+
&[data-variant="text"] {
|
|
65151
|
+
--picker-padding-x-default: 0;
|
|
65152
|
+
--picker-padding-y-default: 0;
|
|
65153
|
+
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
65154
|
+
--picker-border-color: transparent;
|
|
65155
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
65156
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
65157
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
65158
|
+
--picker-background-color: transparent;
|
|
65159
|
+
--picker-background-color-hover: var(--picker-background-color);
|
|
65160
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
65161
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
65162
|
+
|
|
65163
|
+
font-size: inherit;
|
|
65164
|
+
font-family: inherit;
|
|
65165
|
+
text-decoration: underline dotted;
|
|
65166
|
+
text-underline-offset: 0.2em;
|
|
65167
|
+
|
|
65168
|
+
&[data-hover] {
|
|
65169
|
+
text-decoration-style: solid;
|
|
65170
|
+
}
|
|
65171
|
+
}
|
|
64628
65172
|
}
|
|
64629
65173
|
`;
|
|
64630
65174
|
const PickerButton = props => {
|
|
@@ -64668,6 +65212,8 @@ const PickerButton = props => {
|
|
|
64668
65212
|
error
|
|
64669
65213
|
} = props;
|
|
64670
65214
|
const isSingleLine = maxLines === 1;
|
|
65215
|
+
// Same rule as the root: phrasing content inside a sentence.
|
|
65216
|
+
const ContentTag = variant === "text" ? "span" : "div";
|
|
64671
65217
|
const inputRef = useRef(null);
|
|
64672
65218
|
const [pickerRemainingProps, inputProps, facadeChildrenProps] = useControlFacadeProps({
|
|
64673
65219
|
...props,
|
|
@@ -64705,8 +65251,11 @@ const PickerButton = props => {
|
|
|
64705
65251
|
as a value nobody may change. */
|
|
64706
65252
|
jsx(ReadOnlyContext.Provider, {
|
|
64707
65253
|
value: readOnlyResolved,
|
|
64708
|
-
children: jsxs(Box
|
|
64709
|
-
|
|
65254
|
+
children: jsxs(Box
|
|
65255
|
+
// A word in a sentence (variant="text") sits in a <p>, where a <div> is
|
|
65256
|
+
// not allowed: phrasing content there, block content elsewhere.
|
|
65257
|
+
, {
|
|
65258
|
+
as: variant === "text" ? "span" : "div",
|
|
64710
65259
|
ref: ref
|
|
64711
65260
|
// The flow this element really has (.navi_picker is display:inline-flex).
|
|
64712
65261
|
// Left unsaid, Box reads a <div> as block and resolves alignX into a
|
|
@@ -64856,7 +65405,7 @@ const PickerButton = props => {
|
|
|
64856
65405
|
// picker behind it is.
|
|
64857
65406
|
,
|
|
64858
65407
|
|
|
64859
|
-
"navi-placeholder": variant !== "button" && uiStateHoldsNothing(value) ? "" : undefined,
|
|
65408
|
+
"navi-placeholder": variant !== "button" && variant !== "text" && uiStateHoldsNothing(value) ? "" : undefined,
|
|
64860
65409
|
maxLines: maxLines,
|
|
64861
65410
|
children: jsx(PickerOwnContent, {
|
|
64862
65411
|
children: jsx(PickerContext.Provider, {
|
|
@@ -64880,7 +65429,7 @@ const PickerButton = props => {
|
|
|
64880
65429
|
})
|
|
64881
65430
|
})
|
|
64882
65431
|
})
|
|
64883
|
-
}), variant === "icon" || variant === "headless" || variant === "button" || ui === "default" ? null : jsx("span", {
|
|
65432
|
+
}), variant === "icon" || variant === "headless" || variant === "button" || variant === "text" || ui === "default" ? null : jsx("span", {
|
|
64884
65433
|
className: "navi_picker_right_slot",
|
|
64885
65434
|
children: jsx(PickerOwnContent, {
|
|
64886
65435
|
children: clearable && interactive && value !== undefined && value !== "" && clearConfirm !== undefined ?
|
|
@@ -64946,7 +65495,7 @@ const PickerButton = props => {
|
|
|
64946
65495
|
})]
|
|
64947
65496
|
}), jsx(ControlFacadeChildrenWrapper, {
|
|
64948
65497
|
...facadeChildrenProps,
|
|
64949
|
-
children: jsx(
|
|
65498
|
+
children: jsx(ContentTag, {
|
|
64950
65499
|
className: "navi_picker_content",
|
|
64951
65500
|
"data-picker-content": "",
|
|
64952
65501
|
children: children
|
|
@@ -68027,6 +68576,7 @@ const css$n = /* css */`
|
|
|
68027
68576
|
* pointerInteractionOutsideEffect?: "close" | "cancel" | "capture",
|
|
68028
68577
|
* escapeEffect?: "cancel" | "close",
|
|
68029
68578
|
* popupLayer?: "top" | "local",
|
|
68579
|
+
* popupTestId?: string,
|
|
68030
68580
|
* [key: string]: any,
|
|
68031
68581
|
* }>}
|
|
68032
68582
|
* @param {Array<{value: any, label: import("ignore:preact").ComponentChildren}>} options
|
|
@@ -68068,7 +68618,7 @@ const css$n = /* css */`
|
|
|
68068
68618
|
* `dockedOnSmallTouchScreen`, `dialogExpand*`, `dialogMinWidth`/`Height`,
|
|
68069
68619
|
* `dialogMaxWidth`/`Height`,
|
|
68070
68620
|
* `marginWithContainer`, `popoverMode`, `popoverSpacing`, `popupLayer`,
|
|
68071
|
-
* `popupWidthFitContent`, `popoverMaxHeight`, `backdropVariant`,
|
|
68621
|
+
* `popupTestId`, `popupWidthFitContent`, `popoverMaxHeight`, `backdropVariant`,
|
|
68072
68622
|
* `pointerInteractionOutsideEffect`, `escapeEffect`, `closeOnFocusOut`,
|
|
68073
68623
|
* `scrollCapture`, `focusCapture`, `popupBackgroundColor`,
|
|
68074
68624
|
* `popupBorderRadius`, `animation`. See picker.jsx for what each one says.
|
|
@@ -68270,7 +68820,7 @@ const SplitButton = props => {
|
|
|
68270
68820
|
// What the Picker's popup answers to — Picker's own popup props, named here so
|
|
68271
68821
|
// a caller reaches all of them through the split button (see picker.jsx's JSDoc
|
|
68272
68822
|
// for what each one says).
|
|
68273
|
-
const POPUP_PROP_SET = new Set(["mode", "popupLayer", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMinWidth", "dialogMinHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdropVariant", "pointerInteractionOutsideEffect", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
|
|
68823
|
+
const POPUP_PROP_SET = new Set(["mode", "popupLayer", "popupTestId", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMinWidth", "dialogMinHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdropVariant", "pointerInteractionOutsideEffect", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
|
|
68274
68824
|
const splitPopupProps = props => {
|
|
68275
68825
|
const popupProps = {};
|
|
68276
68826
|
const boxProps = {};
|
|
@@ -75869,7 +76419,7 @@ const ErrorSvg = () => {
|
|
|
75869
76419
|
})
|
|
75870
76420
|
});
|
|
75871
76421
|
};
|
|
75872
|
-
const InfoSvg = () => {
|
|
76422
|
+
const InfoSvg$1 = () => {
|
|
75873
76423
|
return jsx("svg", {
|
|
75874
76424
|
viewBox: "0 0 16 16",
|
|
75875
76425
|
fill: "currentColor",
|
|
@@ -75952,7 +76502,7 @@ const MessageBox = ({
|
|
|
75952
76502
|
const [hasTitleChild, setHasTitleChild] = useState(false);
|
|
75953
76503
|
const innerLeftStripe = leftStripe === undefined ? hasTitleChild : leftStripe;
|
|
75954
76504
|
if (icon === true) {
|
|
75955
|
-
icon = status === "info" ? jsx(InfoSvg, {}) : status === "success" ? jsx(SuccessSvg, {}) : status === "warning" ? jsx(WarningSvg, {}) : status === "error" ? jsx(ErrorSvg, {}) : null;
|
|
76505
|
+
icon = status === "info" ? jsx(InfoSvg$1, {}) : status === "success" ? jsx(SuccessSvg, {}) : status === "warning" ? jsx(WarningSvg, {}) : status === "error" ? jsx(ErrorSvg, {}) : null;
|
|
75956
76506
|
} else if (typeof icon === "function") {
|
|
75957
76507
|
const Comp = icon;
|
|
75958
76508
|
icon = jsx(Comp, {});
|
|
@@ -78026,6 +78576,29 @@ const ExclamationSvg = () => {
|
|
|
78026
78576
|
});
|
|
78027
78577
|
};
|
|
78028
78578
|
|
|
78579
|
+
const InfoSvg = () => {
|
|
78580
|
+
return jsxs("svg", {
|
|
78581
|
+
viewBox: "0 0 24 24",
|
|
78582
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
78583
|
+
children: [jsx("circle", {
|
|
78584
|
+
cx: "12",
|
|
78585
|
+
cy: "12",
|
|
78586
|
+
r: "10",
|
|
78587
|
+
fill: "none",
|
|
78588
|
+
stroke: "currentColor",
|
|
78589
|
+
strokeWidth: "2"
|
|
78590
|
+
}), jsx("circle", {
|
|
78591
|
+
cx: "12",
|
|
78592
|
+
cy: "7.6",
|
|
78593
|
+
r: "1.4",
|
|
78594
|
+
fill: "currentColor"
|
|
78595
|
+
}), jsx("path", {
|
|
78596
|
+
fill: "currentColor",
|
|
78597
|
+
d: "M10.6 10.6h2.8V18h-2.8z"
|
|
78598
|
+
})]
|
|
78599
|
+
});
|
|
78600
|
+
};
|
|
78601
|
+
|
|
78029
78602
|
const EyeClosedSvg = () => {
|
|
78030
78603
|
return jsx("svg", {
|
|
78031
78604
|
viewBox: "0 0 24 24",
|
|
@@ -78101,5 +78674,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
78101
78674
|
})
|
|
78102
78675
|
});
|
|
78103
78676
|
|
|
78104
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, renderEmojiAsIcon, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
78677
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, renderEmojiAsIcon, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
78105
78678
|
//# sourceMappingURL=jsenv_navi.js.map
|