@jsenv/navi 0.28.8 → 0.28.10
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 +273 -44
- package/dist/jsenv_navi.js.map +20 -7
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -5353,10 +5353,12 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
5353
5353
|
// Convert numeric IDs to strings for consistency
|
|
5354
5354
|
const signalIdString = String(signalId);
|
|
5355
5355
|
if (globalSignalRegistry.has(signalIdString)) {
|
|
5356
|
-
const
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5356
|
+
const existingEntry = globalSignalRegistry.get(signalIdString);
|
|
5357
|
+
{
|
|
5358
|
+
throw new Error(
|
|
5359
|
+
`Signal ID conflict: A signal with ID "${signalIdString}" already exists (existing default: ${existingEntry.options.getDefaultValue()})`,
|
|
5360
|
+
);
|
|
5361
|
+
}
|
|
5360
5362
|
}
|
|
5361
5363
|
|
|
5362
5364
|
// Determine localStorage key: use id if persists=true, or legacy localStorage option
|
|
@@ -5481,7 +5483,12 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
5481
5483
|
// can reflect the current input state without silently correcting it.
|
|
5482
5484
|
return validity.value;
|
|
5483
5485
|
};
|
|
5484
|
-
const preactSignal = signal(
|
|
5486
|
+
const preactSignal = signal(
|
|
5487
|
+
processValue(
|
|
5488
|
+
getFallbackValue()
|
|
5489
|
+
,
|
|
5490
|
+
),
|
|
5491
|
+
);
|
|
5485
5492
|
|
|
5486
5493
|
// Override the value setter on the instance to intercept writes and apply processValue.
|
|
5487
5494
|
// We do this on the instance (not the prototype) so preactSignal remains a real Signal
|
|
@@ -6514,6 +6521,13 @@ const DIMENSION_PROPS = {
|
|
|
6514
6521
|
const inHorizontalFlexFlow =
|
|
6515
6522
|
parentBoxFlow === "flex-x" || parentBoxFlow === "inline-flex-x";
|
|
6516
6523
|
if (inHorizontalFlexFlow) {
|
|
6524
|
+
if (value === "content") {
|
|
6525
|
+
// flex-basis stays auto: the item still takes the free space, but its
|
|
6526
|
+
// content size is what line-breaking sees — so in a flexWrap parent a
|
|
6527
|
+
// neighbor that no longer fits wraps to the next line. With basis 0%
|
|
6528
|
+
// (below) nothing ever wraps: every item claims a size of zero.
|
|
6529
|
+
return { flexGrow: 1 };
|
|
6530
|
+
}
|
|
6517
6531
|
// Parent is flex-x: grow as flex item
|
|
6518
6532
|
return { flexGrow: 1, flexBasis: "0%" };
|
|
6519
6533
|
}
|
|
@@ -6533,6 +6547,11 @@ const DIMENSION_PROPS = {
|
|
|
6533
6547
|
const inVerticalFlexFlow =
|
|
6534
6548
|
parentBoxFlow === "flex-y" || parentBoxFlow === "inline-flex-y";
|
|
6535
6549
|
if (inVerticalFlexFlow) {
|
|
6550
|
+
if (value === "content") {
|
|
6551
|
+
// Same as expandX="content": grow from the content size, so a
|
|
6552
|
+
// flexWrap parent can wrap.
|
|
6553
|
+
return { flexGrow: 1 };
|
|
6554
|
+
}
|
|
6536
6555
|
// Parent is flex-y: grow as flex item
|
|
6537
6556
|
return { flexGrow: 1, flexBasis: "0%" };
|
|
6538
6557
|
}
|
|
@@ -17428,8 +17447,12 @@ const canContainCallout = element => {
|
|
|
17428
17447
|
if (VOID_ELEMENT_TAG_NAMES.has(element.tagName)) {
|
|
17429
17448
|
return false;
|
|
17430
17449
|
}
|
|
17431
|
-
if (element.tagName === "BUTTON") {
|
|
17432
|
-
// callout
|
|
17450
|
+
if (element.tagName === "BUTTON" || element.getAttribute("role") === "button") {
|
|
17451
|
+
// Never mount the callout inside a button, native or role="button":
|
|
17452
|
+
// - a <button> cannot contain the callout's own close button
|
|
17453
|
+
// - presses inside the callout would bubble into the button's own press
|
|
17454
|
+
// handlers: a preventDefault there makes the callout text unselectable,
|
|
17455
|
+
// and a handler that opens the callout re-opens it (visible blink)
|
|
17433
17456
|
return false;
|
|
17434
17457
|
}
|
|
17435
17458
|
return true;
|
|
@@ -35063,7 +35086,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
35063
35086
|
* - variant="discrete" + backgroundColor: the color applies at rest and hover,
|
|
35064
35087
|
* and the field goes transparent while focused.
|
|
35065
35088
|
*/
|
|
35066
|
-
const
|
|
35089
|
+
const inputCss = /* css */`
|
|
35067
35090
|
@layer navi {
|
|
35068
35091
|
.navi_input {
|
|
35069
35092
|
--border-radius: var(--navi-control-border-radius);
|
|
@@ -35394,7 +35417,7 @@ const useInputTextualProps = props => {
|
|
|
35394
35417
|
});
|
|
35395
35418
|
};
|
|
35396
35419
|
const InputTextualUI = props => {
|
|
35397
|
-
import.meta.css = [
|
|
35420
|
+
import.meta.css = [inputCss, "@jsenv/navi/src/control/input/input_textual.jsx"];
|
|
35398
35421
|
// Spacing props travel to CSS as a raw custom property value, so the size
|
|
35399
35422
|
// keywords have to become lengths here — "s" reaching CSS untouched makes the
|
|
35400
35423
|
// declaration invalid, silently, and the gap just goes away.
|
|
@@ -35513,6 +35536,9 @@ const RealInput = ({
|
|
|
35513
35536
|
"navi-max-length": maxLength
|
|
35514
35537
|
});
|
|
35515
35538
|
};
|
|
35539
|
+
|
|
35540
|
+
// Shared with textarea.jsx: a textarea is styled as a .navi_input box, so the
|
|
35541
|
+
// two read the same style props and pseudo states.
|
|
35516
35542
|
const InputStyleCSSVars = {
|
|
35517
35543
|
"slotSpacing": "--slot-spacing",
|
|
35518
35544
|
"outlineWidth": "--outline-width",
|
|
@@ -36051,7 +36077,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
36051
36077
|
* This means an editable thing MUST have a parent with position relative that wraps the content and the eventual editable input
|
|
36052
36078
|
*
|
|
36053
36079
|
*/
|
|
36054
|
-
const css$
|
|
36080
|
+
const css$D = /* css */`
|
|
36055
36081
|
.navi_editable_wrapper {
|
|
36056
36082
|
--inset-top: 0px;
|
|
36057
36083
|
--inset-right: 0px;
|
|
@@ -36100,7 +36126,7 @@ const useEditionController = () => {
|
|
|
36100
36126
|
};
|
|
36101
36127
|
};
|
|
36102
36128
|
const Editable = props => {
|
|
36103
|
-
import.meta.css = [css$
|
|
36129
|
+
import.meta.css = [css$D, "@jsenv/navi/src/control/edition/editable.jsx"];
|
|
36104
36130
|
let {
|
|
36105
36131
|
children,
|
|
36106
36132
|
action,
|
|
@@ -36514,7 +36540,7 @@ HTMLFormElement.prototype.requestSubmit = function (submitter) {
|
|
|
36514
36540
|
// form.dispatchEvent(customEvent);
|
|
36515
36541
|
// };
|
|
36516
36542
|
|
|
36517
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
36543
|
+
installImportMetaCssBuild(import.meta);const css$C = /* css */`
|
|
36518
36544
|
.navi_group {
|
|
36519
36545
|
--group-border-width: 1px;
|
|
36520
36546
|
|
|
@@ -36610,7 +36636,7 @@ const Group = ({
|
|
|
36610
36636
|
vertical = row,
|
|
36611
36637
|
...props
|
|
36612
36638
|
}) => {
|
|
36613
|
-
import.meta.css = [css$
|
|
36639
|
+
import.meta.css = [css$C, "@jsenv/navi/src/control/group.jsx"];
|
|
36614
36640
|
return jsx(Box, {
|
|
36615
36641
|
baseClassName: "navi_group",
|
|
36616
36642
|
"data-vertical": vertical ? "" : undefined,
|
|
@@ -37020,7 +37046,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
37020
37046
|
* pair. One popup holding slides of its own contents has no such problem — and
|
|
37021
37047
|
* it is the same component in the document, in a dialog or in a popover.
|
|
37022
37048
|
*/
|
|
37023
|
-
const css$
|
|
37049
|
+
const css$B = /* css */`
|
|
37024
37050
|
/* Every slide in the same grid cell: the box then measures itself on the
|
|
37025
37051
|
LARGEST of them, in both directions, without anything being measured by
|
|
37026
37052
|
hand — which is also why nothing here resizes as the slides change. Each
|
|
@@ -37318,7 +37344,7 @@ const SlideContainer = ({
|
|
|
37318
37344
|
children,
|
|
37319
37345
|
...rest
|
|
37320
37346
|
}) => {
|
|
37321
|
-
import.meta.css = [css$
|
|
37347
|
+
import.meta.css = [css$B, "@jsenv/navi/src/layout/slide_container.jsx"];
|
|
37322
37348
|
const debugFocus = useDebugFocus();
|
|
37323
37349
|
const trackRef = useRef();
|
|
37324
37350
|
// The box itself: it is what takes the keyboard when what is on screen holds
|
|
@@ -39918,7 +39944,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
39918
39944
|
* reaches the real container.
|
|
39919
39945
|
*/
|
|
39920
39946
|
let openLocalDialogCount = 0;
|
|
39921
|
-
const css$
|
|
39947
|
+
const css$A = /* css */`
|
|
39922
39948
|
@layer navi {
|
|
39923
39949
|
.navi_dialog {
|
|
39924
39950
|
/* Min gap between the dialog and the edges of its container. Written
|
|
@@ -40325,7 +40351,7 @@ const css$z = /* css */`
|
|
|
40325
40351
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
40326
40352
|
*/
|
|
40327
40353
|
const Dialog = props => {
|
|
40328
|
-
import.meta.css = [css$
|
|
40354
|
+
import.meta.css = [css$A, "@jsenv/navi/src/layout/dialog.jsx"];
|
|
40329
40355
|
if (props.openController) {
|
|
40330
40356
|
return jsx(ControlledDialog, {
|
|
40331
40357
|
...props
|
|
@@ -41143,7 +41169,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
41143
41169
|
* and applied.
|
|
41144
41170
|
*/
|
|
41145
41171
|
let openLocalPopoverCount = 0;
|
|
41146
|
-
const css$
|
|
41172
|
+
const css$z = /* css */`
|
|
41147
41173
|
@layer navi {
|
|
41148
41174
|
.navi_popover {
|
|
41149
41175
|
/* soft: user-configurable preferred max-height. Kept as a *default*
|
|
@@ -41510,7 +41536,7 @@ const css$y = /* css */`
|
|
|
41510
41536
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
41511
41537
|
*/
|
|
41512
41538
|
const Popover = props => {
|
|
41513
|
-
import.meta.css = [css$
|
|
41539
|
+
import.meta.css = [css$z, "@jsenv/navi/src/layout/popover.jsx"];
|
|
41514
41540
|
if (props.openController) {
|
|
41515
41541
|
return jsx(ControlledPopover, {
|
|
41516
41542
|
...props
|
|
@@ -42474,7 +42500,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
42474
42500
|
* pass through untouched via `...rest` to whichever of Popover/Dialog
|
|
42475
42501
|
* actually renders.
|
|
42476
42502
|
*/
|
|
42477
|
-
const css$
|
|
42503
|
+
const css$y = /* css */`
|
|
42478
42504
|
@layer navi {
|
|
42479
42505
|
.navi_popup {
|
|
42480
42506
|
--popup-border-radius: var(--navi-popup-border-radius);
|
|
@@ -42568,7 +42594,7 @@ const css$x = /* css */`
|
|
|
42568
42594
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
42569
42595
|
*/
|
|
42570
42596
|
const Popup = props => {
|
|
42571
|
-
import.meta.css = [css$
|
|
42597
|
+
import.meta.css = [css$y, "@jsenv/navi/src/layout/popup.jsx"];
|
|
42572
42598
|
const {
|
|
42573
42599
|
mode: modeProp,
|
|
42574
42600
|
maxWidth,
|
|
@@ -42711,7 +42737,7 @@ const commitSubtree = (controller, e) => {
|
|
|
42711
42737
|
}
|
|
42712
42738
|
};
|
|
42713
42739
|
|
|
42714
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
42740
|
+
installImportMetaCssBuild(import.meta);const css$x = /* css */`
|
|
42715
42741
|
.navi_picker {
|
|
42716
42742
|
/* Sizing ceilings (maxmax), background, box-shadow, outline, padding,
|
|
42717
42743
|
overflow... are already handled correctly by Popup/Popover/Dialog
|
|
@@ -42823,7 +42849,7 @@ installImportMetaCssBuild(import.meta);const css$w = /* css */`
|
|
|
42823
42849
|
}
|
|
42824
42850
|
`;
|
|
42825
42851
|
const PickerCustomResolver = props => {
|
|
42826
|
-
import.meta.css = [css$
|
|
42852
|
+
import.meta.css = [css$x, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
|
|
42827
42853
|
if (props.children === undefined) {
|
|
42828
42854
|
return jsx(PickerNative, {
|
|
42829
42855
|
...props
|
|
@@ -43468,7 +43494,7 @@ const LoadingIndicator = ({
|
|
|
43468
43494
|
});
|
|
43469
43495
|
};
|
|
43470
43496
|
|
|
43471
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
43497
|
+
installImportMetaCssBuild(import.meta);const css$w = /* css */`
|
|
43472
43498
|
@layer navi {
|
|
43473
43499
|
.navi_separator {
|
|
43474
43500
|
--size: 1px;
|
|
@@ -43546,7 +43572,7 @@ const Separator = ({
|
|
|
43546
43572
|
style,
|
|
43547
43573
|
...props
|
|
43548
43574
|
}) => {
|
|
43549
|
-
import.meta.css = [css$
|
|
43575
|
+
import.meta.css = [css$w, "@jsenv/navi/src/layout/separator.jsx"];
|
|
43550
43576
|
return jsx(Box, {
|
|
43551
43577
|
as: vertical ? "span" : "hr",
|
|
43552
43578
|
...props,
|
|
@@ -44003,7 +44029,7 @@ const ListItemFooter = props => {
|
|
|
44003
44029
|
});
|
|
44004
44030
|
};
|
|
44005
44031
|
|
|
44006
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
44032
|
+
installImportMetaCssBuild(import.meta);const css$v = /* css */`
|
|
44007
44033
|
@layer navi {
|
|
44008
44034
|
.navi_list_container[navi-selectable] {
|
|
44009
44035
|
/* Focus outline */
|
|
@@ -44207,7 +44233,7 @@ const ListSelectableResolver = props => {
|
|
|
44207
44233
|
};
|
|
44208
44234
|
const ListSelectable = props => {
|
|
44209
44235
|
const Next = useNextResolver();
|
|
44210
|
-
import.meta.css = [css$
|
|
44236
|
+
import.meta.css = [css$v, "@jsenv/navi/src/control/list/list_selectable.jsx"];
|
|
44211
44237
|
// we allow ourselves to auto-generate a name
|
|
44212
44238
|
const defaultName = useId();
|
|
44213
44239
|
props.name = props.name || `listbox_${defaultName}`;
|
|
@@ -44749,7 +44775,7 @@ const SeparatorContext = createContext(null);
|
|
|
44749
44775
|
// Set by <List itemTransition>: each row then gets a view-transition-name of
|
|
44750
44776
|
// its own, so a change wrapped in a view transition animates row by row.
|
|
44751
44777
|
const ItemTransitionContext = createContext(false);
|
|
44752
|
-
const css$
|
|
44778
|
+
const css$u = /* css */`
|
|
44753
44779
|
@layer navi {
|
|
44754
44780
|
.navi_list_container {
|
|
44755
44781
|
--list-outline-width: 1px;
|
|
@@ -45237,7 +45263,7 @@ const css$t = /* css */`
|
|
|
45237
45263
|
}
|
|
45238
45264
|
`;
|
|
45239
45265
|
const ListUI = props => {
|
|
45240
|
-
import.meta.css = [css$
|
|
45266
|
+
import.meta.css = [css$u, "@jsenv/navi/src/control/list/list.jsx"];
|
|
45241
45267
|
const {
|
|
45242
45268
|
ref,
|
|
45243
45269
|
renderBudget: renderBudgetProp = RENDER_BUDGET_DEFAULT,
|
|
@@ -46802,7 +46828,7 @@ const PickerPresetResolver = props => {
|
|
|
46802
46828
|
});
|
|
46803
46829
|
};
|
|
46804
46830
|
|
|
46805
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
46831
|
+
installImportMetaCssBuild(import.meta);const css$t = /* css */`
|
|
46806
46832
|
@layer navi {
|
|
46807
46833
|
}
|
|
46808
46834
|
.navi_badge {
|
|
@@ -46881,7 +46907,7 @@ const Badge = ({
|
|
|
46881
46907
|
className,
|
|
46882
46908
|
...props
|
|
46883
46909
|
}) => {
|
|
46884
|
-
import.meta.css = [css$
|
|
46910
|
+
import.meta.css = [css$t, "@jsenv/navi/src/text/badge.jsx"];
|
|
46885
46911
|
const defaultRef = useRef();
|
|
46886
46912
|
props.ref = props.ref || defaultRef;
|
|
46887
46913
|
const {
|
|
@@ -46928,7 +46954,7 @@ const BadgeButton = props => {
|
|
|
46928
46954
|
};
|
|
46929
46955
|
Badge.Button = BadgeButton;
|
|
46930
46956
|
|
|
46931
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
46957
|
+
installImportMetaCssBuild(import.meta);const css$s = /* css */`
|
|
46932
46958
|
@layer navi {
|
|
46933
46959
|
}
|
|
46934
46960
|
.navi_badge_list {
|
|
@@ -46953,7 +46979,7 @@ const BadgeList = ({
|
|
|
46953
46979
|
max,
|
|
46954
46980
|
...props
|
|
46955
46981
|
}) => {
|
|
46956
|
-
import.meta.css = [css$
|
|
46982
|
+
import.meta.css = [css$s, "@jsenv/navi/src/text/badge_list.jsx"];
|
|
46957
46983
|
const measureRef = useRef();
|
|
46958
46984
|
const visibleRef = useRef();
|
|
46959
46985
|
useLayoutEffect(() => {
|
|
@@ -47028,7 +47054,7 @@ const BadgeList = ({
|
|
|
47028
47054
|
});
|
|
47029
47055
|
};
|
|
47030
47056
|
|
|
47031
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47057
|
+
installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
47032
47058
|
.navi_color {
|
|
47033
47059
|
display: block;
|
|
47034
47060
|
aspect-ratio: 1/1;
|
|
@@ -47059,7 +47085,7 @@ const Color = ({
|
|
|
47059
47085
|
children,
|
|
47060
47086
|
...rest
|
|
47061
47087
|
}) => {
|
|
47062
|
-
import.meta.css = [css$
|
|
47088
|
+
import.meta.css = [css$r, "@jsenv/navi/src/text/color.jsx"];
|
|
47063
47089
|
const color = children || undefined;
|
|
47064
47090
|
return jsx(Box, {
|
|
47065
47091
|
as: "span",
|
|
@@ -47514,7 +47540,7 @@ const PickerFileUI = () => {
|
|
|
47514
47540
|
return String(value);
|
|
47515
47541
|
};
|
|
47516
47542
|
|
|
47517
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47543
|
+
installImportMetaCssBuild(import.meta);const css$q = /* css */`
|
|
47518
47544
|
@layer navi {
|
|
47519
47545
|
.navi_picker {
|
|
47520
47546
|
--picker-border-radius: var(--navi-control-border-radius);
|
|
@@ -47840,7 +47866,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
|
47840
47866
|
}
|
|
47841
47867
|
`;
|
|
47842
47868
|
const PickerButton = props => {
|
|
47843
|
-
import.meta.css = [css$
|
|
47869
|
+
import.meta.css = [css$q, "@jsenv/navi/src/control/picker/picker.jsx"];
|
|
47844
47870
|
if (typeof props.maxLines === "string") {
|
|
47845
47871
|
props.maxLines = parseInt(props.maxLines);
|
|
47846
47872
|
}
|
|
@@ -48298,10 +48324,14 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
48298
48324
|
* is what keeps the focus where the travel happens instead of moving it into a
|
|
48299
48325
|
* slide that is about to leave.
|
|
48300
48326
|
*/
|
|
48301
|
-
const css$
|
|
48327
|
+
const css$p = /* css */`
|
|
48302
48328
|
.navi_picker_spin {
|
|
48303
48329
|
/* What the loading outline is drawn around. */
|
|
48304
48330
|
position: relative;
|
|
48331
|
+
/* Written in the control font, like the picker it wraps: the day and its
|
|
48332
|
+
two chevrons are a control, not running text. */
|
|
48333
|
+
font-size: var(--navi-control-font-size);
|
|
48334
|
+
font-family: var(--navi-control-font-family);
|
|
48305
48335
|
/* Framed like every other control (see navi_css_vars.js): what one steps
|
|
48306
48336
|
through is a value one edits, and a box around it is what says so. Said
|
|
48307
48337
|
as CSS rather than as defaults on the Box, so borderWidth="0" or a radius
|
|
@@ -48533,7 +48563,7 @@ const DaySpin = ({
|
|
|
48533
48563
|
nextLabel,
|
|
48534
48564
|
...rest
|
|
48535
48565
|
}) => {
|
|
48536
|
-
import.meta.css = [css$
|
|
48566
|
+
import.meta.css = [css$p, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
|
|
48537
48567
|
const id = useId();
|
|
48538
48568
|
const containerId = `${id}_days`;
|
|
48539
48569
|
const pickerId = `${id}_picker`;
|
|
@@ -48928,7 +48958,7 @@ const addDays = (day, count) => {
|
|
|
48928
48958
|
};
|
|
48929
48959
|
|
|
48930
48960
|
installImportMetaCssBuild(import.meta);// TOFIX: select in data then reset, it reset to red/blue instead of red/blue/green
|
|
48931
|
-
const css$
|
|
48961
|
+
const css$o = /* css */`
|
|
48932
48962
|
.navi_checkbox_group {
|
|
48933
48963
|
border-style: solid;
|
|
48934
48964
|
|
|
@@ -48948,7 +48978,7 @@ const CheckboxGroup = props => {
|
|
|
48948
48978
|
return checkboxGroup;
|
|
48949
48979
|
};
|
|
48950
48980
|
const CheckboxGroupInterface = props => {
|
|
48951
|
-
import.meta.css = [css$
|
|
48981
|
+
import.meta.css = [css$o, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
|
|
48952
48982
|
const {
|
|
48953
48983
|
ref
|
|
48954
48984
|
} = props;
|
|
@@ -48979,6 +49009,197 @@ const CheckboxGroupInterface = props => {
|
|
|
48979
49009
|
});
|
|
48980
49010
|
};
|
|
48981
49011
|
|
|
49012
|
+
installImportMetaCssBuild(import.meta);/**
|
|
49013
|
+
* Multiline text control that grows with what is typed.
|
|
49014
|
+
*
|
|
49015
|
+
* Autosize is native: `field-sizing: content` lets the browser size the
|
|
49016
|
+
* textarea from its value — no hidden mirror textarea to measure against (the
|
|
49017
|
+
* technique libraries used before the property existed). `minRows`/`maxRows`
|
|
49018
|
+
* become min/max heights in `lh` units on top of it; past `maxRows` the
|
|
49019
|
+
* content scrolls.
|
|
49020
|
+
*
|
|
49021
|
+
* TextareaCharCount is the counter that goes with it, and the caller places
|
|
49022
|
+
* it: under the box, in a form footer, next to a label — fed with the same
|
|
49023
|
+
* value/signal as the textarea. The textarea draws no counter of its own.
|
|
49024
|
+
*
|
|
49025
|
+
* Styled as a `.navi_input` box (border, background, focus ring, readonly and
|
|
49026
|
+
* disabled fades, variants): one look for everything one types into. The
|
|
49027
|
+
* shared sheet is registered here too — a page may render a Textarea without
|
|
49028
|
+
* any Input.
|
|
49029
|
+
*/
|
|
49030
|
+
const css$n = /* css */`
|
|
49031
|
+
.navi_input.navi_textarea {
|
|
49032
|
+
.navi_control_input {
|
|
49033
|
+
min-height: calc(var(--textarea-min-rows, 1.5) * 1lh);
|
|
49034
|
+
/* Above maxRows the box stops growing and the content scrolls. The
|
|
49035
|
+
99999 fallback means "no cap" without needing a conditional rule. */
|
|
49036
|
+
max-height: calc(var(--textarea-max-rows, 99999) * 1lh);
|
|
49037
|
+
field-sizing: content;
|
|
49038
|
+
/* Explicit, never normal: minRows/maxRows are lengths in lh, and with
|
|
49039
|
+
line-height normal the lh unit resolves to a theoretical value that
|
|
49040
|
+
does not match the real rendered line — the box then jumps by a few
|
|
49041
|
+
pixels the moment the first character replaces the theory with a real
|
|
49042
|
+
line. One number for both keeps every row count exact. */
|
|
49043
|
+
line-height: 1.5;
|
|
49044
|
+
/* The control grows itself; resizable below hands the handle back. */
|
|
49045
|
+
resize: none;
|
|
49046
|
+
overflow: auto;
|
|
49047
|
+
}
|
|
49048
|
+
&[data-resizable] .navi_control_input {
|
|
49049
|
+
height: calc(var(--textarea-min-rows, 1.5) * 1lh);
|
|
49050
|
+
/* The two are exclusive: with field-sizing content the browser removes
|
|
49051
|
+
the resize handle (the size follows the content, there is nothing to
|
|
49052
|
+
drag). resizable means the hand takes over — fixed sizing, starting
|
|
49053
|
+
at minRows, and the drag writes its own inline height from there. */
|
|
49054
|
+
field-sizing: fixed;
|
|
49055
|
+
resize: vertical;
|
|
49056
|
+
}
|
|
49057
|
+
}
|
|
49058
|
+
.navi_textarea_char_count {
|
|
49059
|
+
color: color-mix(in srgb, currentColor 60%, transparent);
|
|
49060
|
+
font-size: 0.75em;
|
|
49061
|
+
user-select: none;
|
|
49062
|
+
}
|
|
49063
|
+
`;
|
|
49064
|
+
|
|
49065
|
+
/**
|
|
49066
|
+
* @type {import("ignore:preact").FunctionComponent<{
|
|
49067
|
+
* value?: string,
|
|
49068
|
+
* defaultValue?: string,
|
|
49069
|
+
* signal?: import("@preact/signals").Signal<string>,
|
|
49070
|
+
* name?: string,
|
|
49071
|
+
* minRows?: number,
|
|
49072
|
+
* maxRows?: number,
|
|
49073
|
+
* resizable?: boolean,
|
|
49074
|
+
* maxLength?: number,
|
|
49075
|
+
* width?: string,
|
|
49076
|
+
* [key: string]: any,
|
|
49077
|
+
* }>}
|
|
49078
|
+
* @param {number} [minRows=1.5] Height the empty control starts at, in lines.
|
|
49079
|
+
* The default shows half of a second line: enough to read "multiline" at a
|
|
49080
|
+
* glance without the height of a full extra row.
|
|
49081
|
+
* @param {number} [maxRows] Lines after which the control stops growing and
|
|
49082
|
+
* scrolls instead. Without it the control grows with its content.
|
|
49083
|
+
* @param {boolean} [resizable] Give the browser's vertical resize handle back.
|
|
49084
|
+
* A manual resize takes over from the automatic growth.
|
|
49085
|
+
* @param {number} [maxLength] The character limit, validated at submit. Pair
|
|
49086
|
+
* with `maxLengthGuard` to block typing past it, and render a
|
|
49087
|
+
* TextareaCharCount to show it.
|
|
49088
|
+
* @param {string} [width="35ch"] The control's width. Fixed on purpose: with
|
|
49089
|
+
* field-sizing the width would otherwise follow the longest line, and a box
|
|
49090
|
+
* that widens while one types is a box one chases.
|
|
49091
|
+
*/
|
|
49092
|
+
const Textarea = ({
|
|
49093
|
+
// Destructured, never deleted off the props object: Preact reuses the same
|
|
49094
|
+
// props object when an internal state update re-renders the component, so a
|
|
49095
|
+
// delete would make these props vanish from the second render on (the box
|
|
49096
|
+
// then jumps back to the default minRows at the first keystroke).
|
|
49097
|
+
minRows = 1.5,
|
|
49098
|
+
maxRows,
|
|
49099
|
+
resizable,
|
|
49100
|
+
width = "35ch",
|
|
49101
|
+
...props
|
|
49102
|
+
}) => {
|
|
49103
|
+
import.meta.css = [inputCss + css$n, "@jsenv/navi/src/control/input/textarea.jsx"];
|
|
49104
|
+
const defaultRef = useRef(null);
|
|
49105
|
+
props.ref = props.ref || defaultRef;
|
|
49106
|
+
const [rootProps, hostProps, childrenWrapperProps] = useControlProps(props, {
|
|
49107
|
+
controlType: "input"
|
|
49108
|
+
});
|
|
49109
|
+
const {
|
|
49110
|
+
basePseudoState,
|
|
49111
|
+
children
|
|
49112
|
+
} = hostProps;
|
|
49113
|
+
// Children go through ControlChildrenWrapper below; inside the <textarea>
|
|
49114
|
+
// element they would become its text content.
|
|
49115
|
+
delete hostProps.children;
|
|
49116
|
+
const loading = basePseudoState[":-navi-loading"];
|
|
49117
|
+
delete rootProps.width;
|
|
49118
|
+
hostProps.width = width;
|
|
49119
|
+
return jsxs(Box, {
|
|
49120
|
+
as: "span",
|
|
49121
|
+
inline: true,
|
|
49122
|
+
flex: true,
|
|
49123
|
+
baseClassName: "navi_input",
|
|
49124
|
+
className: "navi_textarea",
|
|
49125
|
+
...rootProps,
|
|
49126
|
+
basePseudoState: basePseudoState,
|
|
49127
|
+
"data-resizable": resizable ? "" : undefined,
|
|
49128
|
+
styleCSSVars: InputStyleCSSVars,
|
|
49129
|
+
pseudoStateSelector: ".navi_control_input",
|
|
49130
|
+
pseudoClasses: InputPseudoClasses,
|
|
49131
|
+
pseudoElements: InputPseudoElements,
|
|
49132
|
+
"data-callout-anchor": ".navi_control_input",
|
|
49133
|
+
style: {
|
|
49134
|
+
"--textarea-min-rows": minRows,
|
|
49135
|
+
"--textarea-max-rows": maxRows,
|
|
49136
|
+
...rootProps.style
|
|
49137
|
+
},
|
|
49138
|
+
children: [jsx(LoadingOutline, {
|
|
49139
|
+
loading: loading,
|
|
49140
|
+
color: "var(--loader-color)",
|
|
49141
|
+
inset: -1
|
|
49142
|
+
}), jsx(RealTextarea, {
|
|
49143
|
+
...hostProps
|
|
49144
|
+
}), jsx(ControlChildrenWrapper, {
|
|
49145
|
+
...childrenWrapperProps,
|
|
49146
|
+
children: children
|
|
49147
|
+
})]
|
|
49148
|
+
});
|
|
49149
|
+
};
|
|
49150
|
+
|
|
49151
|
+
/**
|
|
49152
|
+
* The counter that goes with a Textarea: "50/200" — how many characters are
|
|
49153
|
+
* typed over how many the limit allows, the way Material writes it (just the
|
|
49154
|
+
* count when there is no `maxLength`). Where it goes is the caller's call,
|
|
49155
|
+
* which is why it is a separate component rather than something the textarea
|
|
49156
|
+
* draws: put it under the box, in a form footer, next to a label, and feed it
|
|
49157
|
+
* the same value or signal as the textarea.
|
|
49158
|
+
*
|
|
49159
|
+
* @type {import("ignore:preact").FunctionComponent<{
|
|
49160
|
+
* value?: string,
|
|
49161
|
+
* signal?: import("@preact/signals").Signal<string>,
|
|
49162
|
+
* maxLength?: number,
|
|
49163
|
+
* [key: string]: any,
|
|
49164
|
+
* }>}
|
|
49165
|
+
* @param {string} [value] The text being counted. Say `signal` instead for a
|
|
49166
|
+
* two-way bound textarea: reading it here subscribes the count to it.
|
|
49167
|
+
* @param {number} [maxLength] The limit, shown after the count ("50/200").
|
|
49168
|
+
* Without it the count stands alone.
|
|
49169
|
+
*/
|
|
49170
|
+
const TextareaCharCount = ({
|
|
49171
|
+
value,
|
|
49172
|
+
signal,
|
|
49173
|
+
maxLength,
|
|
49174
|
+
...rest
|
|
49175
|
+
}) => {
|
|
49176
|
+
import.meta.css = [css$n, "@jsenv/navi/src/control/input/textarea.jsx"];
|
|
49177
|
+
const resolvedValue = signal ? signal.value : value;
|
|
49178
|
+
const length = typeof resolvedValue === "string" ? resolvedValue.length : 0;
|
|
49179
|
+
return jsx(Box, {
|
|
49180
|
+
as: "span",
|
|
49181
|
+
baseClassName: "navi_textarea_char_count",
|
|
49182
|
+
...rest,
|
|
49183
|
+
children: maxLength === undefined ? length : `${length}/${maxLength}`
|
|
49184
|
+
});
|
|
49185
|
+
};
|
|
49186
|
+
const RealTextarea = ({
|
|
49187
|
+
maxLength,
|
|
49188
|
+
...domProps
|
|
49189
|
+
}) => {
|
|
49190
|
+
const autoSelectReadOnlyProps = useAutoSelectReadOnly(domProps);
|
|
49191
|
+
return jsx(Box, {
|
|
49192
|
+
...domProps,
|
|
49193
|
+
as: "textarea",
|
|
49194
|
+
baseClassName: "navi_control_input",
|
|
49195
|
+
...autoSelectReadOnlyProps,
|
|
49196
|
+
// Native maxLength stays off, like RealInput in input_textual.jsx: the
|
|
49197
|
+
// maxLengthGuard handles live blocking, the constraint validates at
|
|
49198
|
+
// submit, and navi-max-length keeps the value readable from the DOM.
|
|
49199
|
+
"navi-max-length": maxLength
|
|
49200
|
+
});
|
|
49201
|
+
};
|
|
49202
|
+
|
|
48982
49203
|
const Unit = ({
|
|
48983
49204
|
unit,
|
|
48984
49205
|
plural,
|
|
@@ -51015,7 +51236,11 @@ const useWheelInteractions = ({
|
|
|
51015
51236
|
if (vp.contains(documentWheelEvent.target)) {
|
|
51016
51237
|
return; // on the scroll surface → its own onWheel handles it
|
|
51017
51238
|
}
|
|
51018
|
-
documentWheelEvent.
|
|
51239
|
+
if (documentWheelEvent.cancelable) {
|
|
51240
|
+
// cancelable=false during an inertial scroll the browser already owns;
|
|
51241
|
+
// preventDefault would be ignored with an intervention warning.
|
|
51242
|
+
documentWheelEvent.preventDefault();
|
|
51243
|
+
}
|
|
51019
51244
|
keepClaimingGesture(); // the gesture continues elsewhere → keep swallowing it
|
|
51020
51245
|
};
|
|
51021
51246
|
const stopClaimingGesture = () => {
|
|
@@ -51315,7 +51540,11 @@ const useWheelInteractions = ({
|
|
|
51315
51540
|
// preventing touchstart has wider side effects. Requires a non-passive
|
|
51316
51541
|
// listener. See docs/MOBILE_TAP_SUPPRESSION_AFTER_DRAG.md.
|
|
51317
51542
|
const onTouchMove = e => {
|
|
51318
|
-
|
|
51543
|
+
// cancelable=false when the touch landed while a scroll was already in
|
|
51544
|
+
// progress (e.g. the page still coasting from a fling): the browser owns
|
|
51545
|
+
// that scroll, preventDefault would be a no-op and Chrome logs an
|
|
51546
|
+
// intervention warning for the attempt.
|
|
51547
|
+
if (drag && e.cancelable) {
|
|
51319
51548
|
e.preventDefault();
|
|
51320
51549
|
}
|
|
51321
51550
|
};
|
|
@@ -58392,5 +58621,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
58392
58621
|
})
|
|
58393
58622
|
});
|
|
58394
58623
|
|
|
58395
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Thead, Time, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage, windowWidthSignal };
|
|
58624
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage, windowWidthSignal };
|
|
58396
58625
|
//# sourceMappingURL=jsenv_navi.js.map
|