@jsenv/navi 0.27.49 → 0.27.51
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 +374 -218
- package/dist/jsenv_navi.js.map +40 -48
- package/dist/jsenv_navi_side_effects.js +3 -0
- package/dist/jsenv_navi_side_effects.js.map +2 -2
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -8869,11 +8869,11 @@ import.meta.css = [/* css */`
|
|
|
8869
8869
|
}
|
|
8870
8870
|
}
|
|
8871
8871
|
/*
|
|
8872
|
-
|
|
8873
|
-
It's very common to declare a display on component as follow
|
|
8872
|
+
To set display on component, code usually do something like:
|
|
8874
8873
|
.component_class { display: component_display; }
|
|
8875
8874
|
|
|
8876
|
-
|
|
8875
|
+
It overrides the default behavior of [hidden] attribute!
|
|
8876
|
+
This needs to be explicitly handled with:
|
|
8877
8877
|
.component_class[hidden] { display: none; }
|
|
8878
8878
|
|
|
8879
8879
|
To avoid this extra work and potential mistakes we force the default behavior of [hidden] attribute.
|
|
@@ -19687,11 +19687,6 @@ const MIN_CONSTRAINT = {
|
|
|
19687
19687
|
name: "min",
|
|
19688
19688
|
messageAttribute: "data-min-message",
|
|
19689
19689
|
check: (field) => {
|
|
19690
|
-
// Sub-inputs inside a duration_group: min/max is validated at the group level, not per-field.
|
|
19691
|
-
// Per-field min/max attributes are kept for arrow-key navigation bounds only.
|
|
19692
|
-
if (field.parentUIStateController?.controlType === "duration_group") {
|
|
19693
|
-
return null;
|
|
19694
|
-
}
|
|
19695
19690
|
if (field.controlType === "duration_group") {
|
|
19696
19691
|
const min = field.controlHostProps.min;
|
|
19697
19692
|
if (min === undefined || min === null) {
|
|
@@ -19795,11 +19790,6 @@ const MAX_CONSTRAINT = {
|
|
|
19795
19790
|
name: "max",
|
|
19796
19791
|
messageAttribute: "data-max-message",
|
|
19797
19792
|
check: (field) => {
|
|
19798
|
-
// Sub-inputs inside a duration_group: min/max is validated at the group level, not per-field.
|
|
19799
|
-
// Per-field min/max attributes are kept for arrow-key navigation bounds only.
|
|
19800
|
-
if (field.parentUIStateController?.controlType === "duration_group") {
|
|
19801
|
-
return null;
|
|
19802
|
-
}
|
|
19803
19793
|
if (field.controlType === "duration_group") {
|
|
19804
19794
|
const max = field.controlHostProps.max;
|
|
19805
19795
|
if (max === undefined || max === null) {
|
|
@@ -20171,21 +20161,21 @@ const NAVI_VALIDITY_CHANGE_CUSTOM_EVENT = "navi_validity_change";
|
|
|
20171
20161
|
|
|
20172
20162
|
const VALIDATION_TOKEN = createOpenToken();
|
|
20173
20163
|
|
|
20164
|
+
// the order matters here, the first constraint is picked first when multiple constraints fail
|
|
20165
|
+
// so it's better to keep the most complex constraints at the end of the list
|
|
20166
|
+
// so the more basic ones shows up first
|
|
20174
20167
|
const STANDARD_CONSTRAINT_SET = new Set([
|
|
20175
20168
|
REQUIRED_CONSTRAINT,
|
|
20176
20169
|
PATTERN_CONSTRAINT,
|
|
20177
20170
|
TYPE_EMAIL_CONSTRAINT,
|
|
20178
20171
|
TYPE_NUMBER_CONSTRAINT,
|
|
20179
|
-
MIN_LENGTH_CONSTRAINT,
|
|
20180
|
-
MAX_LENGTH_CONSTRAINT,
|
|
20181
20172
|
MIN_CONSTRAINT,
|
|
20182
20173
|
MAX_CONSTRAINT,
|
|
20183
20174
|
STEP_CONSTRAINT,
|
|
20175
|
+
MIN_LENGTH_CONSTRAINT,
|
|
20176
|
+
MAX_LENGTH_CONSTRAINT,
|
|
20184
20177
|
]);
|
|
20185
20178
|
const NAVI_CONSTRAINT_SET = new Set([
|
|
20186
|
-
// the order matters here, the last constraint is picked first when multiple constraints fail
|
|
20187
|
-
// so it's better to keep the most complex constraints at the beginning of the list
|
|
20188
|
-
// so the more basic ones shows up first
|
|
20189
20179
|
MIN_SPECIAL_CHAR_CONSTRAINT,
|
|
20190
20180
|
SINGLE_SPACE_CONSTRAINT,
|
|
20191
20181
|
MIN_DIGIT_CONSTRAINT,
|
|
@@ -20483,10 +20473,10 @@ const createControlValidation = (
|
|
|
20483
20473
|
const pickConstraintFailureInfo = (a, b) => {
|
|
20484
20474
|
const aPrio = getConstraintFailureInfoPriority(a);
|
|
20485
20475
|
const bPrio = getConstraintFailureInfoPriority(b);
|
|
20486
|
-
if (
|
|
20487
|
-
return
|
|
20476
|
+
if (bPrio > aPrio) {
|
|
20477
|
+
return b;
|
|
20488
20478
|
}
|
|
20489
|
-
return
|
|
20479
|
+
return a;
|
|
20490
20480
|
};
|
|
20491
20481
|
const getConstraintFailureInfoPriority = (failureInfo) => {
|
|
20492
20482
|
if (failureInfo.status === "error") {
|
|
@@ -21972,36 +21962,30 @@ const FormContext = createContext();
|
|
|
21972
21962
|
* Each value is a regex character class (including the [ ] delimiters).
|
|
21973
21963
|
*/
|
|
21974
21964
|
const CHAR_CLASS_PRESETS = {
|
|
21975
|
-
numeric:
|
|
21976
|
-
alpha:
|
|
21977
|
-
alphanumeric: "[0-9A-Za-z]",
|
|
21978
|
-
|
|
21979
|
-
|
|
21980
|
-
|
|
21981
|
-
|
|
21982
|
-
|
|
21983
|
-
|
|
21984
|
-
|
|
21985
|
-
|
|
21986
|
-
|
|
21987
|
-
|
|
21988
|
-
// Presets that imply a specific mobile keyboard layout
|
|
21989
|
-
const INPUT_MODE_FROM_PRESET = {
|
|
21990
|
-
numeric: "numeric",
|
|
21991
|
-
pin: "numeric",
|
|
21992
|
-
card: "numeric",
|
|
21993
|
-
tel: "tel",
|
|
21965
|
+
numeric: "[0-9]", // digits only
|
|
21966
|
+
alpha: "[A-Za-z]", // letters only
|
|
21967
|
+
alphanumeric: "[0-9A-Za-z]", // letters and digits
|
|
21968
|
+
decimal: "[-0-9.,]", // digits, minus, dot, comma
|
|
21969
|
+
uppercase: "[A-Z]", // uppercase letters only
|
|
21970
|
+
tel: "[-0-9+() ]", // phone: digits, +, -, parens, space
|
|
21971
|
+
email: "[a-zA-Z0-9._%+@-]", // email characters
|
|
21972
|
+
card: "[0-9 ]", // credit card: digits and spaces
|
|
21973
|
+
hex: "[0-9A-Fa-f]", // hexadecimal digits
|
|
21974
|
+
pin: "[0-9]", // numeric PIN
|
|
21975
|
+
postal: "[0-9A-Za-z -]", // postal code (FR, UK, US)
|
|
21976
|
+
iban: "[0-9A-Z]", // IBAN: uppercase and digits
|
|
21977
|
+
slug: "[a-z0-9-]", // URL slug
|
|
21994
21978
|
};
|
|
21995
21979
|
|
|
21996
21980
|
// Specific i18n keys per preset — more informative than the generic fallback
|
|
21997
21981
|
const MESSAGE_KEY_FROM_PRESET = {
|
|
21998
|
-
numeric:
|
|
21999
|
-
pin:
|
|
22000
|
-
alpha:
|
|
21982
|
+
numeric: "constraint.guard.number",
|
|
21983
|
+
pin: "constraint.guard.number",
|
|
21984
|
+
alpha: "constraint.guard.alpha",
|
|
22001
21985
|
alphanumeric: "constraint.guard.alphanumeric",
|
|
22002
|
-
uppercase:
|
|
22003
|
-
hex:
|
|
22004
|
-
slug:
|
|
21986
|
+
uppercase: "constraint.guard.uppercase",
|
|
21987
|
+
hex: "constraint.guard.hex",
|
|
21988
|
+
slug: "constraint.guard.slug",
|
|
22005
21989
|
// tel, card, postal, iban, custom → generic fallback
|
|
22006
21990
|
};
|
|
22007
21991
|
|
|
@@ -22014,13 +21998,6 @@ const resolveCharClass = (value) => {
|
|
|
22014
21998
|
return CHAR_CLASS_PRESETS[value] ?? value;
|
|
22015
21999
|
};
|
|
22016
22000
|
|
|
22017
|
-
/**
|
|
22018
|
-
* Returns the inputMode to auto-apply for the given preset, or null.
|
|
22019
|
-
*/
|
|
22020
|
-
const resolveInputModeFromAllowedChars = (value) => {
|
|
22021
|
-
return INPUT_MODE_FROM_PRESET[value] ?? null;
|
|
22022
|
-
};
|
|
22023
|
-
|
|
22024
22001
|
/**
|
|
22025
22002
|
* Returns the i18n key for the char guard rejection message.
|
|
22026
22003
|
* Falls back to the generic "constraint.guard.chars" for custom classes and
|
|
@@ -32213,20 +32190,99 @@ const resolveInputProps = (props) => {
|
|
|
32213
32190
|
if (currentTypeStepFormatter) {
|
|
32214
32191
|
props.step = currentTypeStepFormatter(props.step);
|
|
32215
32192
|
}
|
|
32193
|
+
|
|
32194
|
+
// For navi_number: choose inputMode based on whether step/min/max suggest decimals.
|
|
32195
|
+
// inputMode="numeric" (integer keyboard) vs "decimal" (keyboard with decimal separator).
|
|
32196
|
+
if (currentType === "navi_number") {
|
|
32197
|
+
if (props.inputMode === undefined) {
|
|
32198
|
+
props.inputMode =
|
|
32199
|
+
hasDecimalPlaces(props.step) ||
|
|
32200
|
+
hasDecimalPlaces(props.min) ||
|
|
32201
|
+
hasDecimalPlaces(props.max)
|
|
32202
|
+
? "decimal"
|
|
32203
|
+
: "numeric";
|
|
32204
|
+
}
|
|
32205
|
+
}
|
|
32206
|
+
|
|
32207
|
+
const { charGuard } = props;
|
|
32208
|
+
if (charGuard) {
|
|
32209
|
+
if (charGuard === true || charGuard === "auto") {
|
|
32210
|
+
// Auto-resolve charGuard from context.
|
|
32211
|
+
let charGuardResolved;
|
|
32212
|
+
const inputMode = props.inputMode;
|
|
32213
|
+
if (inputMode === "numeric") {
|
|
32214
|
+
charGuardResolved = "numeric";
|
|
32215
|
+
} else if (inputMode === "decimal") {
|
|
32216
|
+
charGuardResolved = "decimal";
|
|
32217
|
+
} else if (currentType === "tel") {
|
|
32218
|
+
charGuardResolved = "tel";
|
|
32219
|
+
} else if (currentType === "email") {
|
|
32220
|
+
charGuardResolved = "email";
|
|
32221
|
+
}
|
|
32222
|
+
if (charGuardResolved !== undefined) {
|
|
32223
|
+
props.charGuard = charGuardResolved;
|
|
32224
|
+
}
|
|
32225
|
+
}
|
|
32226
|
+
// charGuard is now resolved: derive inputMode from it if not already set.
|
|
32227
|
+
if (props.inputMode === undefined && props.charGuard) {
|
|
32228
|
+
const autoMode = INPUT_MODE_FROM_CHAR_GUARD[props.charGuard];
|
|
32229
|
+
if (autoMode) {
|
|
32230
|
+
props.inputMode = autoMode;
|
|
32231
|
+
}
|
|
32232
|
+
}
|
|
32233
|
+
// Build pattern from the resolved charGuard (preset name → class, or raw class passthrough).
|
|
32234
|
+
if (props.pattern === undefined && props.charGuard) {
|
|
32235
|
+
const charClass = CHAR_CLASS_PRESETS[props.charGuard] ?? props.charGuard;
|
|
32236
|
+
props.pattern = `${charClass}*`;
|
|
32237
|
+
}
|
|
32238
|
+
}
|
|
32239
|
+
|
|
32240
|
+
// Compute maxLength from max when inputMode is numeric/decimal.
|
|
32241
|
+
// Done here (after inputMode is set) so controller.props has the resolved value.
|
|
32242
|
+
if (props.maxLength === undefined) {
|
|
32243
|
+
if (props.inputMode === "numeric") {
|
|
32244
|
+
const { min, max } = props;
|
|
32245
|
+
if (max === undefined) ; else {
|
|
32246
|
+
const canBeNegative = min === undefined ? max < 0 : min < 0;
|
|
32247
|
+
const signCharCount = canBeNegative ? 1 : 0;
|
|
32248
|
+
const integerDigitCount = String(Math.floor(Math.abs(max))).length;
|
|
32249
|
+
props.maxLength = signCharCount + integerDigitCount;
|
|
32250
|
+
}
|
|
32251
|
+
} else if (props.inputMode === "decimal") {
|
|
32252
|
+
const { min, max, step } = props;
|
|
32253
|
+
if (max === undefined) ; else if (step === undefined) ; else {
|
|
32254
|
+
const canBeNegative = min === undefined ? max < 0 : min < 0;
|
|
32255
|
+
const signCharCount = canBeNegative ? 1 : 0;
|
|
32256
|
+
const integerDigitCount = String(Math.floor(Math.abs(max))).length;
|
|
32257
|
+
const stepStr = String(step);
|
|
32258
|
+
const dotIndex = stepStr.indexOf(".");
|
|
32259
|
+
// integer step + decimal inputMode is an unusual combo, but we stay consistent:
|
|
32260
|
+
// no decimal part in maxLength since valid values are whole numbers anyway
|
|
32261
|
+
const isIntegerStep = dotIndex === -1;
|
|
32262
|
+
const decimalSignCharCount = isIntegerStep ? 0 : 1;
|
|
32263
|
+
const decimalDigitCount = isIntegerStep
|
|
32264
|
+
? 0
|
|
32265
|
+
: stepStr.length - dotIndex - 1;
|
|
32266
|
+
props.maxLength =
|
|
32267
|
+
signCharCount +
|
|
32268
|
+
integerDigitCount +
|
|
32269
|
+
decimalSignCharCount +
|
|
32270
|
+
decimalDigitCount;
|
|
32271
|
+
}
|
|
32272
|
+
}
|
|
32273
|
+
}
|
|
32274
|
+
|
|
32275
|
+
// Resolve maxLengthGuard boolean/auto → the computed maxLength number.
|
|
32276
|
+
if (props.maxLengthGuard === true || props.maxLengthGuard === "auto") {
|
|
32277
|
+
props.maxLengthGuard =
|
|
32278
|
+
typeof props.maxLength === "number" ? props.maxLength : undefined;
|
|
32279
|
+
}
|
|
32280
|
+
|
|
32216
32281
|
const currentTypeDefaults = NAVI_TYPE_DEFAULTS[currentType];
|
|
32217
32282
|
if (!currentTypeDefaults) {
|
|
32218
32283
|
return;
|
|
32219
32284
|
}
|
|
32220
|
-
|
|
32221
|
-
// inputMode="numeric" (integer keyboard) vs "decimal" (keyboard with decimal separator).
|
|
32222
|
-
if (currentType === "navi_number" && props.inputMode === undefined) {
|
|
32223
|
-
props.inputMode =
|
|
32224
|
-
hasDecimalPlaces(props.step) ||
|
|
32225
|
-
hasDecimalPlaces(props.min) ||
|
|
32226
|
-
hasDecimalPlaces(props.max)
|
|
32227
|
-
? "decimal"
|
|
32228
|
-
: "numeric";
|
|
32229
|
-
}
|
|
32285
|
+
|
|
32230
32286
|
for (const key of Object.keys(currentTypeDefaults)) {
|
|
32231
32287
|
if (props[key] === undefined) {
|
|
32232
32288
|
props[key] = currentTypeDefaults[key];
|
|
@@ -32237,6 +32293,15 @@ const resolveInputProps = (props) => {
|
|
|
32237
32293
|
resolveInputProps(props);
|
|
32238
32294
|
};
|
|
32239
32295
|
|
|
32296
|
+
// Presets that imply a specific mobile keyboard inputMode.
|
|
32297
|
+
const INPUT_MODE_FROM_CHAR_GUARD = {
|
|
32298
|
+
numeric: "numeric",
|
|
32299
|
+
pin: "numeric",
|
|
32300
|
+
card: "numeric",
|
|
32301
|
+
tel: "tel",
|
|
32302
|
+
decimal: "decimal",
|
|
32303
|
+
};
|
|
32304
|
+
|
|
32240
32305
|
const normalizeToDate = (value) => {
|
|
32241
32306
|
if (value === undefined || value === null) {
|
|
32242
32307
|
return null;
|
|
@@ -32702,7 +32767,7 @@ const RangePseudoElements = ["::-navi-loader"];
|
|
|
32702
32767
|
const InputModeResolver = props => {
|
|
32703
32768
|
const Next = useNextResolver();
|
|
32704
32769
|
if (props.inputMode === "numeric" || props.inputMode === "decimal") {
|
|
32705
|
-
return jsx(
|
|
32770
|
+
return jsx(InputModeNumericOrDecimal, {
|
|
32706
32771
|
...props
|
|
32707
32772
|
});
|
|
32708
32773
|
}
|
|
@@ -32710,37 +32775,26 @@ const InputModeResolver = props => {
|
|
|
32710
32775
|
...props
|
|
32711
32776
|
});
|
|
32712
32777
|
};
|
|
32713
|
-
const
|
|
32778
|
+
const InputModeNumericOrDecimal = props => {
|
|
32714
32779
|
const Next = useNextResolver();
|
|
32715
|
-
const {
|
|
32716
|
-
min,
|
|
32717
|
-
max,
|
|
32718
|
-
step = 1
|
|
32719
|
-
} = props;
|
|
32720
|
-
let maxLength;
|
|
32721
|
-
if (max !== undefined) {
|
|
32722
|
-
const integerDigits = String(Math.floor(max)).length;
|
|
32723
|
-
// If step has decimal places, the value can contain a separator + those digits
|
|
32724
|
-
const stepStr = String(step);
|
|
32725
|
-
const dotIndex = stepStr.indexOf(".");
|
|
32726
|
-
const decimalDigits = dotIndex === -1 ? 0 : stepStr.length - dotIndex - 1;
|
|
32727
|
-
// If min is negative (or unknown and max itself is negative), a "-" sign can appear
|
|
32728
|
-
const canBeNegative = min !== undefined ? min < 0 : max < 0;
|
|
32729
|
-
const signChar = canBeNegative ? 1 : 0;
|
|
32730
|
-
maxLength = signChar + integerDigits + (decimalDigits > 0 ? 1 + decimalDigits : 0);
|
|
32731
|
-
}
|
|
32732
32780
|
return jsx(Next, {
|
|
32733
|
-
maxLength: maxLength,
|
|
32734
32781
|
...props,
|
|
32735
32782
|
onInput: e => {
|
|
32736
32783
|
props.onInput?.(e);
|
|
32737
32784
|
if (e.defaultPrevented) {
|
|
32738
32785
|
return;
|
|
32739
32786
|
}
|
|
32740
|
-
if (maxLength === undefined) {
|
|
32741
|
-
return;
|
|
32742
|
-
}
|
|
32743
32787
|
const input = e.currentTarget;
|
|
32788
|
+
let maxLength;
|
|
32789
|
+
const maxLengthProp = input.maxLength;
|
|
32790
|
+
if (maxLengthProp === -1) {
|
|
32791
|
+
const naviMaxLengthAttr = input.getAttribute("navi-max-length");
|
|
32792
|
+
if (naviMaxLengthAttr === null) {
|
|
32793
|
+
// no max length
|
|
32794
|
+
return;
|
|
32795
|
+
}
|
|
32796
|
+
maxLength = Number(naviMaxLengthAttr);
|
|
32797
|
+
}
|
|
32744
32798
|
if (input.value.length < maxLength) {
|
|
32745
32799
|
return;
|
|
32746
32800
|
}
|
|
@@ -33705,18 +33759,6 @@ const InputTextualFirstResolver = props => {
|
|
|
33705
33759
|
const defaultRef = useRef(null);
|
|
33706
33760
|
props.ref = props.ref || defaultRef;
|
|
33707
33761
|
resolveInputProps(props);
|
|
33708
|
-
|
|
33709
|
-
// charGuard → auto inputMode + auto pattern for mobile keyboard hints
|
|
33710
|
-
if (props.charGuard) {
|
|
33711
|
-
if (props.inputMode === undefined) {
|
|
33712
|
-
const autoMode = resolveInputModeFromAllowedChars(props.charGuard);
|
|
33713
|
-
if (autoMode) props.inputMode = autoMode;
|
|
33714
|
-
}
|
|
33715
|
-
if (props.pattern === undefined) {
|
|
33716
|
-
const charClass = resolveCharClass(props.charGuard);
|
|
33717
|
-
props.pattern = `${charClass}*`;
|
|
33718
|
-
}
|
|
33719
|
-
}
|
|
33720
33762
|
return jsx(Next, {
|
|
33721
33763
|
...props
|
|
33722
33764
|
});
|
|
@@ -33732,6 +33774,10 @@ const RealInput = props => {
|
|
|
33732
33774
|
// Never set native maxLength — our guard handles it. maxLength stays in
|
|
33733
33775
|
// inputControlHostProps so form validation constraints still read it.
|
|
33734
33776
|
maxLength: undefined
|
|
33777
|
+
// But do expose it (needed by navi_input_full event)
|
|
33778
|
+
,
|
|
33779
|
+
|
|
33780
|
+
"navi-max-length": props.maxLength
|
|
33735
33781
|
});
|
|
33736
33782
|
};
|
|
33737
33783
|
const InputStyleCSSVars = {
|
|
@@ -34671,7 +34717,9 @@ const InputDuration = props => {
|
|
|
34671
34717
|
uiAction,
|
|
34672
34718
|
action,
|
|
34673
34719
|
unitHour,
|
|
34674
|
-
textAlign = "auto"
|
|
34720
|
+
textAlign = "auto",
|
|
34721
|
+
maxLengthGuard,
|
|
34722
|
+
charGuard
|
|
34675
34723
|
} = props;
|
|
34676
34724
|
const minDuration = parseDuration(props.min);
|
|
34677
34725
|
const maxDuration = parseDuration(props.max);
|
|
@@ -34799,6 +34847,8 @@ const InputDuration = props => {
|
|
|
34799
34847
|
className: "navi_input_duration",
|
|
34800
34848
|
"data-callout-arrow-x": "center",
|
|
34801
34849
|
width: "fit-content",
|
|
34850
|
+
flex: true,
|
|
34851
|
+
spacing: "xxs",
|
|
34802
34852
|
...groupRootProps,
|
|
34803
34853
|
unit: undefined,
|
|
34804
34854
|
unitHour: undefined,
|
|
@@ -34818,37 +34868,34 @@ const InputDuration = props => {
|
|
|
34818
34868
|
} : {
|
|
34819
34869
|
defaultValue: initialIsoString
|
|
34820
34870
|
})
|
|
34821
|
-
}), jsx(
|
|
34822
|
-
|
|
34823
|
-
|
|
34824
|
-
|
|
34825
|
-
|
|
34826
|
-
|
|
34827
|
-
|
|
34828
|
-
|
|
34829
|
-
|
|
34830
|
-
|
|
34831
|
-
|
|
34832
|
-
|
|
34833
|
-
|
|
34834
|
-
|
|
34835
|
-
|
|
34836
|
-
|
|
34837
|
-
|
|
34838
|
-
|
|
34839
|
-
|
|
34840
|
-
|
|
34841
|
-
|
|
34842
|
-
|
|
34843
|
-
|
|
34844
|
-
|
|
34845
|
-
|
|
34846
|
-
|
|
34847
|
-
|
|
34848
|
-
|
|
34849
|
-
disabled: disabled,
|
|
34850
|
-
basePseudoState: basePseudoState
|
|
34851
|
-
})
|
|
34871
|
+
}), jsx(ControlgroupChildrenWrapper, {
|
|
34872
|
+
...childrenWrapperProps,
|
|
34873
|
+
name: undefined,
|
|
34874
|
+
children: jsx(InputDurationFields, {
|
|
34875
|
+
showHours: showHours,
|
|
34876
|
+
showMinutes: showMinutes,
|
|
34877
|
+
showSeconds: showSeconds,
|
|
34878
|
+
showMilliseconds: showMilliseconds,
|
|
34879
|
+
minutesReadOnly: minutesReadOnly,
|
|
34880
|
+
secondsReadOnly: secondsReadOnly,
|
|
34881
|
+
millisecondsReadOnly: millisecondsReadOnly,
|
|
34882
|
+
stepHasMilliseconds: stepHasMilliseconds,
|
|
34883
|
+
controlled: hasValue,
|
|
34884
|
+
hourValue: hourValue,
|
|
34885
|
+
minuteValue: minuteValue,
|
|
34886
|
+
secondValue: secondValue,
|
|
34887
|
+
millisecondValue: millisecondValue,
|
|
34888
|
+
minSeconds: minSeconds,
|
|
34889
|
+
maxSeconds: maxSeconds,
|
|
34890
|
+
stepSeconds: stepSeconds,
|
|
34891
|
+
unitHour: unitHour,
|
|
34892
|
+
textAlign: textAlign,
|
|
34893
|
+
maxLengthGuard: maxLengthGuard,
|
|
34894
|
+
charGuard: charGuard,
|
|
34895
|
+
required: required,
|
|
34896
|
+
readOnly: readOnly,
|
|
34897
|
+
disabled: disabled,
|
|
34898
|
+
basePseudoState: basePseudoState
|
|
34852
34899
|
})
|
|
34853
34900
|
})]
|
|
34854
34901
|
});
|
|
@@ -34908,7 +34955,20 @@ const useClipboardProps = groupRef => {
|
|
|
34908
34955
|
});
|
|
34909
34956
|
e.preventDefault();
|
|
34910
34957
|
};
|
|
34958
|
+
const isFromDurationField = e => {
|
|
34959
|
+
const target = e.target;
|
|
34960
|
+
if (!target.matches) {
|
|
34961
|
+
return false;
|
|
34962
|
+
}
|
|
34963
|
+
if (!target.matches(".navi_duration_part")) {
|
|
34964
|
+
return false;
|
|
34965
|
+
}
|
|
34966
|
+
return true;
|
|
34967
|
+
};
|
|
34911
34968
|
const onCopy = e => {
|
|
34969
|
+
if (!isFromDurationField(e)) {
|
|
34970
|
+
return;
|
|
34971
|
+
}
|
|
34912
34972
|
const payload = getClipboardPayload();
|
|
34913
34973
|
if (!payload) {
|
|
34914
34974
|
return;
|
|
@@ -34918,6 +34978,9 @@ const useClipboardProps = groupRef => {
|
|
|
34918
34978
|
e.preventDefault();
|
|
34919
34979
|
};
|
|
34920
34980
|
const onCut = e => {
|
|
34981
|
+
if (!isFromDurationField(e)) {
|
|
34982
|
+
return;
|
|
34983
|
+
}
|
|
34921
34984
|
const payload = getClipboardPayload();
|
|
34922
34985
|
if (!payload) {
|
|
34923
34986
|
return;
|
|
@@ -34927,6 +34990,9 @@ const useClipboardProps = groupRef => {
|
|
|
34927
34990
|
applyToGroup("", e);
|
|
34928
34991
|
};
|
|
34929
34992
|
const onPaste = e => {
|
|
34993
|
+
if (!isFromDurationField(e)) {
|
|
34994
|
+
return;
|
|
34995
|
+
}
|
|
34930
34996
|
const naviData = e.clipboardData.getData("application/x-navi");
|
|
34931
34997
|
const textData = e.clipboardData.getData("text/plain");
|
|
34932
34998
|
let isoValue = null;
|
|
@@ -35119,10 +35185,12 @@ const InputDurationPart = ({
|
|
|
35119
35185
|
return jsxs(Label, {
|
|
35120
35186
|
flex: "y",
|
|
35121
35187
|
"data-separator": separator || undefined,
|
|
35122
|
-
children: [jsx(Input
|
|
35123
|
-
|
|
35124
|
-
|
|
35125
|
-
|
|
35188
|
+
children: [jsx(Input, {
|
|
35189
|
+
className: "navi_duration_part"
|
|
35190
|
+
// When autofocused this field should be selected
|
|
35191
|
+
// this help to modify the value on mobile
|
|
35192
|
+
,
|
|
35193
|
+
|
|
35126
35194
|
autoFocusSelect: true,
|
|
35127
35195
|
type: "navi_number",
|
|
35128
35196
|
"navi-input-type": unit,
|
|
@@ -35396,6 +35464,7 @@ const Dialog = props => {
|
|
|
35396
35464
|
const topOffset = vv.offsetTop;
|
|
35397
35465
|
const marginTop = availableHeight > dialogHeight ? topOffset + (availableHeight - dialogHeight) / 2 : topOffset;
|
|
35398
35466
|
dialogEl.style.setProperty("--dialog-top-inset", `${snapToPixel(marginTop)}px`);
|
|
35467
|
+
dispatchCustomEvent(dialogEl, "navi_position_change");
|
|
35399
35468
|
};
|
|
35400
35469
|
const onScroll = () => {
|
|
35401
35470
|
updatePosition();
|
|
@@ -37188,7 +37257,7 @@ const createItemTracker = (onChange) => {
|
|
|
37188
37257
|
const visibleItemsSignal = signal([]);
|
|
37189
37258
|
const countSignal = signal(0);
|
|
37190
37259
|
const visibleCountSignal = signal(0);
|
|
37191
|
-
const
|
|
37260
|
+
const noMatchCountSignal = signal(0);
|
|
37192
37261
|
|
|
37193
37262
|
let notifyScheduled = false;
|
|
37194
37263
|
const runNotify = () => {
|
|
@@ -37210,7 +37279,7 @@ const createItemTracker = (onChange) => {
|
|
|
37210
37279
|
let visibleItemsChanged = false;
|
|
37211
37280
|
const allItems = [];
|
|
37212
37281
|
const visibleItems = [];
|
|
37213
|
-
let
|
|
37282
|
+
let newNoMatchCount = 0;
|
|
37214
37283
|
for (let i = 0; i < allOrderedKeys.length; i++) {
|
|
37215
37284
|
const key = allOrderedKeys[i];
|
|
37216
37285
|
const item = allRegistrations.get(key);
|
|
@@ -37219,12 +37288,12 @@ const createItemTracker = (onChange) => {
|
|
|
37219
37288
|
if (!allItemsChanged && item !== prevAllItems[i]) {
|
|
37220
37289
|
allItemsChanged = true;
|
|
37221
37290
|
}
|
|
37222
|
-
if (
|
|
37291
|
+
if (item.match === false) {
|
|
37292
|
+
newNoMatchCount++;
|
|
37293
|
+
}
|
|
37294
|
+
if (!item.hidden) {
|
|
37223
37295
|
const visibleIdx = visibleItems.length;
|
|
37224
37296
|
visibleItems.push(item);
|
|
37225
|
-
if (item.matchScore > 0) {
|
|
37226
|
-
newMatchCount++;
|
|
37227
|
-
}
|
|
37228
37297
|
if (!visibleItemsChanged && item !== prevVisibleItems[visibleIdx]) {
|
|
37229
37298
|
visibleItemsChanged = true;
|
|
37230
37299
|
}
|
|
@@ -37246,9 +37315,9 @@ const createItemTracker = (onChange) => {
|
|
|
37246
37315
|
visibleItemsSignal.value = visibleItems;
|
|
37247
37316
|
someChange = true;
|
|
37248
37317
|
}
|
|
37249
|
-
const
|
|
37250
|
-
if (
|
|
37251
|
-
|
|
37318
|
+
const noMatchCountModified = noMatchCountSignal.peek() !== newNoMatchCount;
|
|
37319
|
+
if (noMatchCountModified) {
|
|
37320
|
+
noMatchCountSignal.value = newNoMatchCount;
|
|
37252
37321
|
someChange = true;
|
|
37253
37322
|
}
|
|
37254
37323
|
if (someChange) {
|
|
@@ -37447,7 +37516,7 @@ const createItemTracker = (onChange) => {
|
|
|
37447
37516
|
visibleItemsSignal,
|
|
37448
37517
|
countSignal,
|
|
37449
37518
|
visibleCountSignal,
|
|
37450
|
-
|
|
37519
|
+
noMatchCountSignal,
|
|
37451
37520
|
_flushSync,
|
|
37452
37521
|
};
|
|
37453
37522
|
};
|
|
@@ -37514,8 +37583,8 @@ installImportMetaCssBuild(import.meta);const css$n = /* css */`
|
|
|
37514
37583
|
--list-item-outline-color: var(--navi-focus-outline-color);
|
|
37515
37584
|
/* Focus outline end */
|
|
37516
37585
|
--list-item-border-color: var(--navi-control-border-color);
|
|
37517
|
-
--list-item-padding-x-default: var(--navi-
|
|
37518
|
-
--list-item-padding-y-default: var(--navi-
|
|
37586
|
+
--list-item-padding-x-default: var(--navi-list-item-padding-x-default);
|
|
37587
|
+
--list-item-padding-y-default: var(--navi-list-item-padding-y-default);
|
|
37519
37588
|
|
|
37520
37589
|
/* Hover (mouse) */
|
|
37521
37590
|
--list-item-background-color-hover: light-dark(#f5f5f5, #2a2a2a);
|
|
@@ -37564,6 +37633,14 @@ installImportMetaCssBuild(import.meta);const css$n = /* css */`
|
|
|
37564
37633
|
}
|
|
37565
37634
|
}
|
|
37566
37635
|
|
|
37636
|
+
.navi_list_container[navi-selectable] {
|
|
37637
|
+
.navi_list_fallback,
|
|
37638
|
+
.navi_list_no_match_fallback {
|
|
37639
|
+
--list-item-padding-x-default: inherit;
|
|
37640
|
+
--list-item-padding-y-default: inherit;
|
|
37641
|
+
}
|
|
37642
|
+
}
|
|
37643
|
+
|
|
37567
37644
|
.navi_list_item[navi-selectable] {
|
|
37568
37645
|
--list-item-padding-x-default: inherit;
|
|
37569
37646
|
--list-item-padding-y-default: inherit;
|
|
@@ -37573,6 +37650,13 @@ installImportMetaCssBuild(import.meta);const css$n = /* css */`
|
|
|
37573
37650
|
outline-offset: var(--list-item-outline-offset);
|
|
37574
37651
|
cursor: var(--x-list-item-cursor);
|
|
37575
37652
|
|
|
37653
|
+
.navi_checkbox {
|
|
37654
|
+
--margin: 0;
|
|
37655
|
+
}
|
|
37656
|
+
.navi_radio {
|
|
37657
|
+
--margin: 0;
|
|
37658
|
+
}
|
|
37659
|
+
|
|
37576
37660
|
&[navi-selectable] {
|
|
37577
37661
|
user-select: none;
|
|
37578
37662
|
}
|
|
@@ -38184,6 +38268,11 @@ const applySearchHighlight = (el, highlight) => {
|
|
|
38184
38268
|
installImportMetaCssBuild(import.meta);const ListItemTrackerContext = createContext(null);
|
|
38185
38269
|
const GroupItemTrackerContext = createContext(null);
|
|
38186
38270
|
const PendingScrollRefContext = createContext(null);
|
|
38271
|
+
// Controls how List.Item behaves when match=false (set via List searchNoMatchMode prop):
|
|
38272
|
+
// "remove" — remove from DOM (default)
|
|
38273
|
+
// "invisible_and_inert" — keep in DOM, invisible and non-interactive (preserves layout, no content visible)
|
|
38274
|
+
// "muted" — keep in DOM, visible but opacified and still interactive
|
|
38275
|
+
const SearchNoMatchModeContext = createContext("remove");
|
|
38187
38276
|
|
|
38188
38277
|
// When total rendered items exceeds renderBudget, a render window [start, end)
|
|
38189
38278
|
// is activated to cap the number of DOM nodes. Items outside the window return
|
|
@@ -38385,6 +38474,14 @@ const css$m = /* css */`
|
|
|
38385
38474
|
scroll-margin-right: var(--x-list-scroll-spacing-right);
|
|
38386
38475
|
scroll-margin-bottom: var(--x-list-scroll-spacing-bottom);
|
|
38387
38476
|
scroll-margin-left: var(--x-list-scroll-spacing-left);
|
|
38477
|
+
|
|
38478
|
+
&[aria-hidden="true"] {
|
|
38479
|
+
opacity: 0;
|
|
38480
|
+
}
|
|
38481
|
+
|
|
38482
|
+
&[navi-muted] {
|
|
38483
|
+
opacity: 0.35;
|
|
38484
|
+
}
|
|
38388
38485
|
}
|
|
38389
38486
|
|
|
38390
38487
|
/* Virtual scroll fillers — must remain invisible.
|
|
@@ -38410,10 +38507,10 @@ const css$m = /* css */`
|
|
|
38410
38507
|
Using order ensures fallbacks always appear after items regardless of DOM order.
|
|
38411
38508
|
matchFallback intentionally shares the same order as fallback so it appears
|
|
38412
38509
|
at the same visual position — after an input if present but before any items
|
|
38413
|
-
still displayed (non-matching items remain in DOM
|
|
38510
|
+
still displayed (non-matching items remain in DOM, invisible_and_inert or muted):
|
|
38414
38511
|
1. Input (sticky header, order: -2)
|
|
38415
|
-
2.
|
|
38416
|
-
3.
|
|
38512
|
+
2. searchFallback (order: -1)
|
|
38513
|
+
3. invisible/dim items (regular order, after DOM flow)
|
|
38417
38514
|
4. HOT FIX OF THE DEAD for bottom filler + preact issue: order: 1
|
|
38418
38515
|
5. sticky footer (order: 2)
|
|
38419
38516
|
*/
|
|
@@ -38427,12 +38524,39 @@ const css$m = /* css */`
|
|
|
38427
38524
|
order: -2;
|
|
38428
38525
|
}
|
|
38429
38526
|
.navi_list_fallback,
|
|
38430
|
-
.
|
|
38527
|
+
.navi_list_search_fallback {
|
|
38431
38528
|
order: -1;
|
|
38432
38529
|
color: light-dark(#888, #aaa);
|
|
38433
38530
|
&[navi-default] {
|
|
38434
38531
|
display: inline;
|
|
38435
|
-
padding: var(
|
|
38532
|
+
padding-top: var(
|
|
38533
|
+
--list-item-padding-top,
|
|
38534
|
+
var(
|
|
38535
|
+
--list-item-padding-y,
|
|
38536
|
+
var(--list-item-padding, var(--list-item-padding-y-default))
|
|
38537
|
+
)
|
|
38538
|
+
);
|
|
38539
|
+
padding-right: var(
|
|
38540
|
+
--list-item-padding-right,
|
|
38541
|
+
var(
|
|
38542
|
+
--list-item-padding-x,
|
|
38543
|
+
var(--list-item-padding, var(--list-item-padding-x-default))
|
|
38544
|
+
)
|
|
38545
|
+
);
|
|
38546
|
+
padding-bottom: var(
|
|
38547
|
+
--list-item-padding-bottom,
|
|
38548
|
+
var(
|
|
38549
|
+
--list-item-padding-y,
|
|
38550
|
+
var(--list-item-padding, var(--list-item-padding-y-default))
|
|
38551
|
+
)
|
|
38552
|
+
);
|
|
38553
|
+
padding-left: var(
|
|
38554
|
+
--list-item-padding-left,
|
|
38555
|
+
var(
|
|
38556
|
+
--list-item-padding-x,
|
|
38557
|
+
var(--list-item-padding, var(--list-item-padding-x-default))
|
|
38558
|
+
)
|
|
38559
|
+
);
|
|
38436
38560
|
text-align: center;
|
|
38437
38561
|
user-select: none;
|
|
38438
38562
|
}
|
|
@@ -38506,37 +38630,6 @@ const css$m = /* css */`
|
|
|
38506
38630
|
}
|
|
38507
38631
|
}
|
|
38508
38632
|
`;
|
|
38509
|
-
|
|
38510
|
-
/**
|
|
38511
|
-
* List — generic virtualized scroll container.
|
|
38512
|
-
*
|
|
38513
|
-
* Renders children inside a scrollable container with an optional render budget
|
|
38514
|
-
* for virtual scrolling. Items must use <ListItem> to participate in tracking.
|
|
38515
|
-
*
|
|
38516
|
-
* Props:
|
|
38517
|
-
* keyboardInteractions — when true, attaches arrow/enter/escape keyboard shortcuts
|
|
38518
|
-
* that dispatch navi_list_nav / navi_list_confirm / navi_list_clear
|
|
38519
|
-
* to the list container. Pair with uiAction for a full keyboard-
|
|
38520
|
-
* navigable list.
|
|
38521
|
-
* uiAction — called with the selected value on confirm. When provided
|
|
38522
|
-
* the list becomes interactive: tracks hover and keyboard-
|
|
38523
|
-
* pointed state, handles navi_list_nav / navi_list_clear /
|
|
38524
|
-
* navi_list_confirm custom events via ListInteractionContext.
|
|
38525
|
-
* popover — when true, renders as a managed popover positioned near
|
|
38526
|
-
* an anchor element via navi_list_open / navi_list_close events.
|
|
38527
|
-
* renderBudget — max items in DOM at once (default 100, virtual scroll when exceeded)
|
|
38528
|
-
* virtualItemSize — fixed px size per item (width if horizontal, height otherwise) when all items have the same size.
|
|
38529
|
-
* Enables precise virtual-scroll filler sizing without a DOM
|
|
38530
|
-
* measurement pass. Required when renderBudget is active and
|
|
38531
|
-
* item height is known up-front.
|
|
38532
|
-
* fallback — content shown when no items exist at all
|
|
38533
|
-
* matchFallback — content shown when items exist but all are hidden (e.g. no search match)
|
|
38534
|
-
* separator — element or function(index, { previousItem, currentItem }) inserted between visible items
|
|
38535
|
-
* lockSize — when true, captures the container's dimensions on first render
|
|
38536
|
-
* (always in unfiltered state). Those values become min-width/
|
|
38537
|
-
* min-height so filtering cannot collapse the layout.
|
|
38538
|
-
* ...rest — forwarded to the outer scroll container <Box>
|
|
38539
|
-
*/
|
|
38540
38633
|
const ListUI = props => {
|
|
38541
38634
|
import.meta.css = [css$m, "@jsenv/navi/src/control/list/list.jsx"];
|
|
38542
38635
|
const {
|
|
@@ -38545,7 +38638,7 @@ const ListUI = props => {
|
|
|
38545
38638
|
renderBudgetSkipCheck,
|
|
38546
38639
|
role,
|
|
38547
38640
|
fallback,
|
|
38548
|
-
|
|
38641
|
+
searchFallback,
|
|
38549
38642
|
separator,
|
|
38550
38643
|
children,
|
|
38551
38644
|
popover,
|
|
@@ -38556,6 +38649,7 @@ const ListUI = props => {
|
|
|
38556
38649
|
virtualItemSize,
|
|
38557
38650
|
lockSize,
|
|
38558
38651
|
searchText,
|
|
38652
|
+
searchNoMatchMode = "remove",
|
|
38559
38653
|
horizontal,
|
|
38560
38654
|
spacing,
|
|
38561
38655
|
...rest
|
|
@@ -38645,8 +38739,8 @@ const ListUI = props => {
|
|
|
38645
38739
|
children: jsx(ListContent, {
|
|
38646
38740
|
role: role,
|
|
38647
38741
|
fallback: fallback,
|
|
38648
|
-
|
|
38649
|
-
|
|
38742
|
+
searchFallback: searchFallback,
|
|
38743
|
+
searchNoMatchMode: searchNoMatchMode,
|
|
38650
38744
|
separator: separator,
|
|
38651
38745
|
expandX: expandX,
|
|
38652
38746
|
expand: expand,
|
|
@@ -38670,12 +38764,48 @@ const ListFirstResolver = props => {
|
|
|
38670
38764
|
...props
|
|
38671
38765
|
});
|
|
38672
38766
|
};
|
|
38767
|
+
/**
|
|
38768
|
+
* List — generic virtualized scroll container.
|
|
38769
|
+
*
|
|
38770
|
+
* Renders children inside a scrollable container with an optional render budget
|
|
38771
|
+
* for virtual scrolling. Items must use <List.Item> to participate in tracking.
|
|
38772
|
+
*
|
|
38773
|
+
* Props:
|
|
38774
|
+
* selectable — enables selection: items get aria roles, action/uiAction callbacks,
|
|
38775
|
+
* and keyboard navigation (arrow keys, enter, escape).
|
|
38776
|
+
* action — called with the selected value when the user confirms a selection.
|
|
38777
|
+
* uiAction — called on every interaction (hover, keyboard navigation, confirm).
|
|
38778
|
+
* When provided the list tracks hovered/pointed state via ListInteractionContext.
|
|
38779
|
+
* popover — when true, renders as a managed popover positioned near
|
|
38780
|
+
* an anchor element via navi_list_open / navi_list_close events.
|
|
38781
|
+
* renderBudget — max items in DOM at once (default 100, virtual scroll when exceeded).
|
|
38782
|
+
* virtualItemSize — fixed px size per item (width if horizontal, height otherwise).
|
|
38783
|
+
* Enables precise virtual-scroll filler sizing without a DOM
|
|
38784
|
+
* measurement pass. Useful when renderBudget is active and
|
|
38785
|
+
* all items have the same known height.
|
|
38786
|
+
* fallback — content shown when the list has no items at all.
|
|
38787
|
+
* searchFallback — content shown when every matchable item (those with a match prop)
|
|
38788
|
+
* has match=false. Defaults to a "no results" message.
|
|
38789
|
+
* Pass false/null/'' to disable.
|
|
38790
|
+
* searchText — current search string, used to trigger scroll-to-top when
|
|
38791
|
+
* search becomes active and to drive search highlight.
|
|
38792
|
+
* searchNoMatchMode — controls how List.Item behaves when match=false (default "remove"):
|
|
38793
|
+
* "remove" — remove from DOM
|
|
38794
|
+
* "invisible_and_inert" — keep in DOM, invisible and non-interactive (preserves layout)
|
|
38795
|
+
* "muted" — keep in DOM, visible but opacified and still interactive
|
|
38796
|
+
* separator — element or function(index, { previousItem, currentItem }) inserted between visible items.
|
|
38797
|
+
* lockSize — captures the container's dimensions on first render so filtering
|
|
38798
|
+
* cannot collapse the layout (sets min-width/min-height).
|
|
38799
|
+
* horizontal — lays items out in a row instead of a column.
|
|
38800
|
+
* spacing — gap between items (forwarded to Box spacing prop).
|
|
38801
|
+
* ...rest — forwarded to the outer container <Box>.
|
|
38802
|
+
*/
|
|
38673
38803
|
const List = createComponentResolver([ListFirstResolver, ListSelectableResolver, ListUI]);
|
|
38674
38804
|
const ListContent = ({
|
|
38675
38805
|
role,
|
|
38676
38806
|
fallback,
|
|
38677
|
-
|
|
38678
|
-
|
|
38807
|
+
searchFallback,
|
|
38808
|
+
searchNoMatchMode,
|
|
38679
38809
|
separator,
|
|
38680
38810
|
expandX,
|
|
38681
38811
|
expand,
|
|
@@ -38693,8 +38823,8 @@ const ListContent = ({
|
|
|
38693
38823
|
children: jsx(UnorderedList, {
|
|
38694
38824
|
role: role,
|
|
38695
38825
|
fallback: fallback,
|
|
38696
|
-
|
|
38697
|
-
|
|
38826
|
+
searchFallback: searchFallback,
|
|
38827
|
+
searchNoMatchMode: searchNoMatchMode,
|
|
38698
38828
|
separator: separator === true ? jsx(Separator, {
|
|
38699
38829
|
margin: "0"
|
|
38700
38830
|
}) : separator,
|
|
@@ -39121,8 +39251,8 @@ const UnorderedList = ({
|
|
|
39121
39251
|
renderWindow,
|
|
39122
39252
|
virtualItemSizeSignal,
|
|
39123
39253
|
fallback,
|
|
39124
|
-
|
|
39125
|
-
|
|
39254
|
+
searchFallback,
|
|
39255
|
+
searchNoMatchMode,
|
|
39126
39256
|
separator,
|
|
39127
39257
|
horizontal,
|
|
39128
39258
|
spacing,
|
|
@@ -39139,20 +39269,22 @@ const UnorderedList = ({
|
|
|
39139
39269
|
children: [jsx(BeforeFiller, {
|
|
39140
39270
|
virtualItemSizeSignal: virtualItemSizeSignal,
|
|
39141
39271
|
renderWindowStart: renderWindow.start
|
|
39142
|
-
}), jsx(
|
|
39143
|
-
|
|
39144
|
-
tracker: tracker
|
|
39145
|
-
searchText: searchText
|
|
39272
|
+
}), jsx(SearchFallback, {
|
|
39273
|
+
searchFallback: searchFallback,
|
|
39274
|
+
tracker: tracker
|
|
39146
39275
|
}), jsx(Fallback, {
|
|
39147
39276
|
fallback: fallback,
|
|
39148
39277
|
tracker: tracker
|
|
39149
|
-
}), jsx(
|
|
39150
|
-
value:
|
|
39151
|
-
children: jsx(
|
|
39152
|
-
value:
|
|
39153
|
-
children: jsx(
|
|
39154
|
-
value:
|
|
39155
|
-
children:
|
|
39278
|
+
}), jsx(SearchNoMatchModeContext.Provider, {
|
|
39279
|
+
value: searchNoMatchMode,
|
|
39280
|
+
children: jsx(RenderWindowContext.Provider, {
|
|
39281
|
+
value: renderWindow,
|
|
39282
|
+
children: jsx(SeparatorContext.Provider, {
|
|
39283
|
+
value: separator ?? null,
|
|
39284
|
+
children: jsx(ListItemTrackerContext.Provider, {
|
|
39285
|
+
value: tracker,
|
|
39286
|
+
children: children
|
|
39287
|
+
})
|
|
39156
39288
|
})
|
|
39157
39289
|
})
|
|
39158
39290
|
}), jsx(AfterFiller, {
|
|
@@ -39162,31 +39294,33 @@ const UnorderedList = ({
|
|
|
39162
39294
|
})]
|
|
39163
39295
|
});
|
|
39164
39296
|
};
|
|
39165
|
-
|
|
39297
|
+
|
|
39298
|
+
// Show when all matchable items (those with a match prop) are non-matching.
|
|
39299
|
+
// The match prop on List.Item signals participation in a matching system
|
|
39300
|
+
// (search, filter, etc.). searchFallback appears when every such item has match=false.
|
|
39301
|
+
const SearchFallback = ({
|
|
39166
39302
|
tracker,
|
|
39167
|
-
|
|
39168
|
-
searchText
|
|
39303
|
+
searchFallback
|
|
39169
39304
|
}) => {
|
|
39170
39305
|
const itemCount = tracker.countSignal.value;
|
|
39171
|
-
const
|
|
39172
|
-
const
|
|
39173
|
-
|
|
39174
|
-
|
|
39175
|
-
|
|
39176
|
-
|
|
39177
|
-
|
|
39178
|
-
|
|
39179
|
-
noMatchFallback = allHidden ? naviI18n("list.no_match") : naviI18n("list.no_match_rest_shown");
|
|
39306
|
+
const noMatchCount = tracker.noMatchCountSignal.value;
|
|
39307
|
+
const showMatchFallback = noMatchCount > 0 && noMatchCount === itemCount;
|
|
39308
|
+
if (searchFallback === undefined) {
|
|
39309
|
+
searchFallback = naviI18n("list.no_match");
|
|
39310
|
+
}
|
|
39311
|
+
if (!searchFallback) {
|
|
39312
|
+
// explicitely disabled by user (<List searchFallback={false|null|''}>)
|
|
39313
|
+
return null;
|
|
39180
39314
|
}
|
|
39181
39315
|
if (!showMatchFallback) {
|
|
39182
39316
|
return null;
|
|
39183
39317
|
}
|
|
39184
39318
|
return jsx(ListItem, {
|
|
39185
39319
|
role: "presentation",
|
|
39186
|
-
className: "navi_list_item
|
|
39320
|
+
className: "navi_list_item navi_list_search_fallback",
|
|
39187
39321
|
hidden: !showMatchFallback,
|
|
39188
|
-
"navi-default": typeof
|
|
39189
|
-
children:
|
|
39322
|
+
"navi-default": typeof searchFallback === "string" ? "" : undefined,
|
|
39323
|
+
children: searchFallback
|
|
39190
39324
|
});
|
|
39191
39325
|
};
|
|
39192
39326
|
const Fallback = ({
|
|
@@ -39291,6 +39425,18 @@ const ListItemUI = props => {
|
|
|
39291
39425
|
props.id = props.id || idDefault;
|
|
39292
39426
|
const renderWindow = useContext(RenderWindowContext);
|
|
39293
39427
|
const tracker = useContext(ListItemTrackerContext);
|
|
39428
|
+
const searchNoMatchMode = useContext(SearchNoMatchModeContext);
|
|
39429
|
+
// Derive filtered/hidden/nonMatching from the `match` prop + searchNoMatchMode context.
|
|
39430
|
+
// The `match` prop replaces the older `filtered`/`hidden` per-item props.
|
|
39431
|
+
if (props.match === false) {
|
|
39432
|
+
if (searchNoMatchMode === "remove") {
|
|
39433
|
+
props.filtered = true;
|
|
39434
|
+
} else if (searchNoMatchMode === "invisible_and_inert") {
|
|
39435
|
+
props.hidden = true;
|
|
39436
|
+
} else if (searchNoMatchMode === "muted") {
|
|
39437
|
+
props.muted = true;
|
|
39438
|
+
}
|
|
39439
|
+
}
|
|
39294
39440
|
const item = props;
|
|
39295
39441
|
const visibleIndex = tracker.useTrackItem(item);
|
|
39296
39442
|
const groupTracker = useContext(GroupItemTrackerContext);
|
|
@@ -39350,6 +39496,7 @@ const ListItemReal = props => {
|
|
|
39350
39496
|
ref,
|
|
39351
39497
|
id,
|
|
39352
39498
|
hidden,
|
|
39499
|
+
muted,
|
|
39353
39500
|
highlight,
|
|
39354
39501
|
children,
|
|
39355
39502
|
...rest
|
|
@@ -39382,7 +39529,15 @@ const ListItemReal = props => {
|
|
|
39382
39529
|
index: undefined,
|
|
39383
39530
|
selected: undefined,
|
|
39384
39531
|
matchScore: undefined,
|
|
39385
|
-
|
|
39532
|
+
match: undefined
|
|
39533
|
+
// We use aria-hidden and not hidden because hidden would be forced to
|
|
39534
|
+
// display: none while here we want to keep it in the DOM to avoid layout shift
|
|
39535
|
+
// but visually hidden
|
|
39536
|
+
,
|
|
39537
|
+
|
|
39538
|
+
"aria-hidden": hidden,
|
|
39539
|
+
inert: hidden ? true : undefined,
|
|
39540
|
+
"navi-muted": muted ? "" : undefined,
|
|
39386
39541
|
ref: ref,
|
|
39387
39542
|
children: children
|
|
39388
39543
|
});
|
|
@@ -40454,6 +40609,7 @@ installImportMetaCssBuild(import.meta);const css$i = /* css */`
|
|
|
40454
40609
|
outline: none;
|
|
40455
40610
|
cursor: inherit;
|
|
40456
40611
|
pointer-events: auto;
|
|
40612
|
+
user-select: all;
|
|
40457
40613
|
|
|
40458
40614
|
&::-webkit-calendar-picker-indicator {
|
|
40459
40615
|
cursor: inherit;
|