@jsenv/navi 0.29.306 → 0.29.308
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/dev/jsenv_navi.js +237 -182
- package/dist/dev/jsenv_navi.js.map +11 -11
- package/dist/jsenv_navi.js +211 -176
- package/dist/jsenv_navi.js.map +11 -11
- package/docs/dialog_shape.md +2 -2
- package/docs/popup_open.md +6 -2
- package/package.json +3 -3
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -12,7 +12,7 @@ import { useErrorBoundary, useLayoutEffect, useContext, useCallback, useRef, use
|
|
|
12
12
|
import { humanizeI18n, prefixFirstAndIndentRemainingLines, setRuntimeLangSource, formatDuration, formatMonth, formatDay, resolveTimeRangePrecision, formatDatePlaceholder, toDate, getRelativeDay, formatDayRelative, formatMonthPlaceholder, formatWeekPlaceholder, formatDatetimePlaceholder, formatDatetime, toTimeOfDay, formatTimeOfDay, formatTime, formatMinuteDuration, formatSecondDuration, formatHourDuration, formatTimeRelative, formatNumber, interpolateText, installInterpolateJsx } from "@jsenv/humanize";
|
|
13
13
|
export { createI18n, formatDatetime, formatDay, formatDayRelative, formatDuration, formatHourDuration, formatMinuteDuration, formatMonth, formatNumber, formatSecondDuration, formatTime, formatTimeOfDay, formatTimeRange, formatTimeRelative, interpolateText } from "@jsenv/humanize";
|
|
14
14
|
import { jsxs, jsx, Fragment } from "preact/jsx-runtime";
|
|
15
|
-
import { durationContainsNaN, compareTwoDurations, durationToSeconds, DISPLAYABLE_RULE, MAX_LINE_BREAKS_RULE, NO_EMOJI_RULE, SINGLE_SPACE_RULE, createValidity, resolveCharClass, getCharClassMessageKey, compileCharClassAnchored, compileCharClass, CHAR_CLASS_PRESETS, parseDuration, durationToISOString } from "@jsenv/validity";
|
|
15
|
+
import { TYPE_RULE, durationContainsNaN, compareTwoDurations, durationToSeconds, DISPLAYABLE_RULE, MAX_LINE_BREAKS_RULE, NO_EMOJI_RULE, SINGLE_SPACE_RULE, createValidity, resolveCharClass, getCharClassMessageKey, compileCharClassAnchored, compileCharClass, CHAR_CLASS_PRESETS, parseDuration, durationToISOString } from "@jsenv/validity";
|
|
16
16
|
export { compareTwoDurations, durationContainsNaN, durationToHours, durationToISOString, durationToMinutes, durationToNumber, durationToSeconds, durationToString, parseDuration } from "@jsenv/validity";
|
|
17
17
|
import { Suspense, createPortal, forwardRef } from "preact/compat";
|
|
18
18
|
|
|
@@ -8444,6 +8444,75 @@ const languagesSignal = computed(() => {
|
|
|
8444
8444
|
// (nor the "languagechange" listener above).
|
|
8445
8445
|
setRuntimeLangSource(() => languagesSignal.value);
|
|
8446
8446
|
|
|
8447
|
+
/**
|
|
8448
|
+
* Where navi meets @jsenv/validity.
|
|
8449
|
+
*
|
|
8450
|
+
* validity names a refusal with a key and its parameters rather than a
|
|
8451
|
+
* sentence, so that a field and a server can refuse in the same words in the
|
|
8452
|
+
* language of the person reading. navi is one of those two callers: it says the
|
|
8453
|
+
* sentence, in the browser, through `naviI18n`. The keys line up on purpose —
|
|
8454
|
+
* validity's `"single_space.start"` is navi's `"constraint.single_space.start"`
|
|
8455
|
+
* — so overriding a message is looking up one key, not going through a
|
|
8456
|
+
* translation table.
|
|
8457
|
+
*
|
|
8458
|
+
* The other direction is `constraintFromValidityRule`: a rule an app wrote for
|
|
8459
|
+
* its server, worn by a control as a constraint.
|
|
8460
|
+
*/
|
|
8461
|
+
|
|
8462
|
+
|
|
8463
|
+
/**
|
|
8464
|
+
* Turns a @jsenv/validity rule into a constraint a control can wear, so an app
|
|
8465
|
+
* rule written once — in the package its server reads too — is checked on both
|
|
8466
|
+
* sides instead of being written twice.
|
|
8467
|
+
*
|
|
8468
|
+
* @param {object} rule
|
|
8469
|
+
* `{ name, applyOn(ruleValue, value, ruleConfig) }`, the same object passed
|
|
8470
|
+
* to `createValidity({ rules })`.
|
|
8471
|
+
* @param {object} [ruleConfig]
|
|
8472
|
+
* What parameterizes the rule, under its own name — `{ maxWords: 40 }` for a
|
|
8473
|
+
* rule named `maxWords`. Pass `formatMessage` here to say the refusal through
|
|
8474
|
+
* the app's own i18n; without it the key is looked up in `naviI18n` under
|
|
8475
|
+
* `constraint.<key>`, and a rule answering with a finished sentence is shown
|
|
8476
|
+
* as-is.
|
|
8477
|
+
*
|
|
8478
|
+
* Call it once, at module level: a constraint rebuilt on every render is a new
|
|
8479
|
+
* object on every check.
|
|
8480
|
+
*/
|
|
8481
|
+
const constraintFromValidityRule = (rule, ruleConfig = {}) => {
|
|
8482
|
+
const { formatMessage, ...ruleParams } = ruleConfig;
|
|
8483
|
+
return {
|
|
8484
|
+
name: rule.name,
|
|
8485
|
+
check: (field) => {
|
|
8486
|
+
const result = rule.applyOn(
|
|
8487
|
+
ruleParams[rule.name],
|
|
8488
|
+
field.uiState,
|
|
8489
|
+
ruleParams,
|
|
8490
|
+
);
|
|
8491
|
+
if (!result) {
|
|
8492
|
+
return null;
|
|
8493
|
+
}
|
|
8494
|
+
if (typeof result === "string") {
|
|
8495
|
+
return result;
|
|
8496
|
+
}
|
|
8497
|
+
if (formatMessage) {
|
|
8498
|
+
return formatMessage(result.key, result.params);
|
|
8499
|
+
}
|
|
8500
|
+
return naviI18nFromValidityMessage(result);
|
|
8501
|
+
},
|
|
8502
|
+
};
|
|
8503
|
+
};
|
|
8504
|
+
|
|
8505
|
+
const naviI18nFromValidityMessage = ({ key, params }) => {
|
|
8506
|
+
if (params && typeof params.max === "number") {
|
|
8507
|
+
// Lets a template pluralize on the bound it names: "[max] retour[s]".
|
|
8508
|
+
return naviI18n(`constraint.${key}`, {
|
|
8509
|
+
...params,
|
|
8510
|
+
s: params.max > 1 ? "s" : "",
|
|
8511
|
+
});
|
|
8512
|
+
}
|
|
8513
|
+
return naviI18n(`constraint.${key}`, params);
|
|
8514
|
+
};
|
|
8515
|
+
|
|
8447
8516
|
/**
|
|
8448
8517
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
|
|
8449
8518
|
*/
|
|
@@ -8593,9 +8662,8 @@ const PATTERN_CONSTRAINT = {
|
|
|
8593
8662
|
};
|
|
8594
8663
|
CONSTRAINT_ATTRIBUTE_SET.add("pattern");
|
|
8595
8664
|
|
|
8596
|
-
//
|
|
8597
|
-
|
|
8598
|
-
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
8665
|
+
// What an address is, is @jsenv/validity's `type: "email"`: a server checking
|
|
8666
|
+
// the value again refuses it for the same reason and in the same words.
|
|
8599
8667
|
const TYPE_EMAIL_CONSTRAINT = {
|
|
8600
8668
|
name: "type_email",
|
|
8601
8669
|
messageAttribute: "data-type-message",
|
|
@@ -8609,14 +8677,11 @@ const TYPE_EMAIL_CONSTRAINT = {
|
|
|
8609
8677
|
if (!valueAsString) {
|
|
8610
8678
|
return null;
|
|
8611
8679
|
}
|
|
8612
|
-
|
|
8680
|
+
const result = TYPE_RULE.applyOn("email", valueAsString);
|
|
8681
|
+
if (!result) {
|
|
8613
8682
|
return null;
|
|
8614
8683
|
}
|
|
8615
|
-
|
|
8616
|
-
if (!valueAsString.includes("@")) {
|
|
8617
|
-
return naviI18n("constraint.type.email.at", { value: valueAsString });
|
|
8618
|
-
}
|
|
8619
|
-
return naviI18n("constraint.type.email.invalid");
|
|
8684
|
+
return naviI18nFromValidityMessage(result);
|
|
8620
8685
|
},
|
|
8621
8686
|
};
|
|
8622
8687
|
|
|
@@ -11917,75 +11982,6 @@ const isFunctionButNotAnActionFunction = (action) => {
|
|
|
11917
11982
|
return typeof action === "function" && !action.isAction;
|
|
11918
11983
|
};
|
|
11919
11984
|
|
|
11920
|
-
/**
|
|
11921
|
-
* Where navi meets @jsenv/validity.
|
|
11922
|
-
*
|
|
11923
|
-
* validity names a refusal with a key and its parameters rather than a
|
|
11924
|
-
* sentence, so that a field and a server can refuse in the same words in the
|
|
11925
|
-
* language of the person reading. navi is one of those two callers: it says the
|
|
11926
|
-
* sentence, in the browser, through `naviI18n`. The keys line up on purpose —
|
|
11927
|
-
* validity's `"single_space.start"` is navi's `"constraint.single_space.start"`
|
|
11928
|
-
* — so overriding a message is looking up one key, not going through a
|
|
11929
|
-
* translation table.
|
|
11930
|
-
*
|
|
11931
|
-
* The other direction is `constraintFromValidityRule`: a rule an app wrote for
|
|
11932
|
-
* its server, worn by a control as a constraint.
|
|
11933
|
-
*/
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
/**
|
|
11937
|
-
* Turns a @jsenv/validity rule into a constraint a control can wear, so an app
|
|
11938
|
-
* rule written once — in the package its server reads too — is checked on both
|
|
11939
|
-
* sides instead of being written twice.
|
|
11940
|
-
*
|
|
11941
|
-
* @param {object} rule
|
|
11942
|
-
* `{ name, applyOn(ruleValue, value, ruleConfig) }`, the same object passed
|
|
11943
|
-
* to `createValidity({ rules })`.
|
|
11944
|
-
* @param {object} [ruleConfig]
|
|
11945
|
-
* What parameterizes the rule, under its own name — `{ maxWords: 40 }` for a
|
|
11946
|
-
* rule named `maxWords`. Pass `formatMessage` here to say the refusal through
|
|
11947
|
-
* the app's own i18n; without it the key is looked up in `naviI18n` under
|
|
11948
|
-
* `constraint.<key>`, and a rule answering with a finished sentence is shown
|
|
11949
|
-
* as-is.
|
|
11950
|
-
*
|
|
11951
|
-
* Call it once, at module level: a constraint rebuilt on every render is a new
|
|
11952
|
-
* object on every check.
|
|
11953
|
-
*/
|
|
11954
|
-
const constraintFromValidityRule = (rule, ruleConfig = {}) => {
|
|
11955
|
-
const { formatMessage, ...ruleParams } = ruleConfig;
|
|
11956
|
-
return {
|
|
11957
|
-
name: rule.name,
|
|
11958
|
-
check: (field) => {
|
|
11959
|
-
const result = rule.applyOn(
|
|
11960
|
-
ruleParams[rule.name],
|
|
11961
|
-
field.uiState,
|
|
11962
|
-
ruleParams,
|
|
11963
|
-
);
|
|
11964
|
-
if (!result) {
|
|
11965
|
-
return null;
|
|
11966
|
-
}
|
|
11967
|
-
if (typeof result === "string") {
|
|
11968
|
-
return result;
|
|
11969
|
-
}
|
|
11970
|
-
if (formatMessage) {
|
|
11971
|
-
return formatMessage(result.key, result.params);
|
|
11972
|
-
}
|
|
11973
|
-
return naviI18nFromValidityMessage(result);
|
|
11974
|
-
},
|
|
11975
|
-
};
|
|
11976
|
-
};
|
|
11977
|
-
|
|
11978
|
-
const naviI18nFromValidityMessage = ({ key, params }) => {
|
|
11979
|
-
if (params && typeof params.max === "number") {
|
|
11980
|
-
// Lets a template pluralize on the bound it names: "[max] retour[s]".
|
|
11981
|
-
return naviI18n(`constraint.${key}`, {
|
|
11982
|
-
...params,
|
|
11983
|
-
s: params.max > 1 ? "s" : "",
|
|
11984
|
-
});
|
|
11985
|
-
}
|
|
11986
|
-
return naviI18n(`constraint.${key}`, params);
|
|
11987
|
-
};
|
|
11988
|
-
|
|
11989
11985
|
/**
|
|
11990
11986
|
* `data-displayable` — the value must be something the layout can actually
|
|
11991
11987
|
* draw. What it refuses and why lives in @jsenv/validity's DISPLAYABLE_RULE:
|
|
@@ -40674,7 +40670,15 @@ const LoadingRectangleSvg = ({
|
|
|
40674
40670
|
strokeWidth,
|
|
40675
40671
|
networkSpeed: networkSpeedForced
|
|
40676
40672
|
}) => {
|
|
40677
|
-
|
|
40673
|
+
// The stroke is centered on the path, so half of it falls outside: drawing
|
|
40674
|
+
// at half the stroke width puts its outer edge exactly on the box, whatever
|
|
40675
|
+
// the box. It used to be a share of the smaller dimension (3%, floored at
|
|
40676
|
+
// 2px), which held the line further and further inside as the box grew — a
|
|
40677
|
+
// caller placing the outline with `inset` got the distance it asked for on a
|
|
40678
|
+
// field and something several pixels inward on a card. Nothing needs the
|
|
40679
|
+
// extra room: the svg is `overflow: visible` and whoever positions the
|
|
40680
|
+
// wrapper already reserves the half stroke.
|
|
40681
|
+
const margin = strokeWidth / 2;
|
|
40678
40682
|
|
|
40679
40683
|
// Calculate the drawable area
|
|
40680
40684
|
const drawableWidth = width - margin * 2;
|
|
@@ -48862,10 +48866,11 @@ const ButtonUI = props => {
|
|
|
48862
48866
|
cta,
|
|
48863
48867
|
spacing,
|
|
48864
48868
|
contentDisplay,
|
|
48865
|
-
//
|
|
48866
|
-
//
|
|
48867
|
-
// the outline belongs around the whole
|
|
48868
|
-
|
|
48869
|
+
// Who draws the loading outline. Left unsaid, the button does; "custom"
|
|
48870
|
+
// says someone else does — a button that is one half of a bigger control:
|
|
48871
|
+
// what is busy is the control, and the outline belongs around the whole
|
|
48872
|
+
// of it (see split_button.jsx).
|
|
48873
|
+
loadingOutline
|
|
48869
48874
|
} = props;
|
|
48870
48875
|
const [buttonControlRootProps, buttonControlHostProps, controlChildrenWrapperProps] = useControlProps(props, {
|
|
48871
48876
|
controlType: "button"
|
|
@@ -48991,7 +48996,7 @@ const ButtonUI = props => {
|
|
|
48991
48996
|
visualSelector: visualSelector,
|
|
48992
48997
|
hasChildUsingForwardedProps: true,
|
|
48993
48998
|
children: [jsx(LoadingOutline, {
|
|
48994
|
-
loading: loadingOutline
|
|
48999
|
+
loading: loadingOutline === "custom" ? false : loading,
|
|
48995
49000
|
inset: -1,
|
|
48996
49001
|
color: "var(--button-loader-color)"
|
|
48997
49002
|
}), jsx(ControlChildrenWrapper, {
|
|
@@ -61238,6 +61243,9 @@ const DIALOG_STYLE_CSS_VARS = {
|
|
|
61238
61243
|
animationDuration: "--popup-animation-duration",
|
|
61239
61244
|
backdropColor: "--backdrop-background",
|
|
61240
61245
|
backdropFilter: "--backdrop-filter",
|
|
61246
|
+
backgroundColor: "--dialog-background-color",
|
|
61247
|
+
boxShadow: "--dialog-box-shadow",
|
|
61248
|
+
borderWidth: "--dialog-border-width",
|
|
61241
61249
|
borderRadius: "--dialog-border-radius",
|
|
61242
61250
|
minWidth: "--dialog-min-width",
|
|
61243
61251
|
maxWidth: "--dialog-max-width",
|
|
@@ -62831,10 +62839,17 @@ const POPOVER_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible",
|
|
|
62831
62839
|
// Lets consumers pass animationDuration="0.5s"/borderRadius="8px" as regular
|
|
62832
62840
|
// props; Box maps them to the CSS vars for us (see box.jsx's styleCSSVars
|
|
62833
62841
|
// handling).
|
|
62842
|
+
// The paint props go through the popover's own vars rather than the properties
|
|
62843
|
+
// themselves, so the stylesheet keeps the last word on them (the same reason
|
|
62844
|
+
// dialog.jsx gives for borderRadius).
|
|
62834
62845
|
const POPUP_STYLE_CSS_VARS = {
|
|
62835
62846
|
animationDuration: "--popup-animation-duration",
|
|
62836
62847
|
backdropColor: "--backdrop-background",
|
|
62837
62848
|
backdropFilter: "--backdrop-filter",
|
|
62849
|
+
backgroundColor: "--popover-background-color",
|
|
62850
|
+
boxShadow: "--popover-box-shadow",
|
|
62851
|
+
borderWidth: "--popover-border-width",
|
|
62852
|
+
borderRadius: "--popover-border-radius",
|
|
62838
62853
|
minWidth: "--popover-min-width",
|
|
62839
62854
|
maxWidth: "--popover-max-width",
|
|
62840
62855
|
minHeight: "--popover-min-height",
|
|
@@ -63097,83 +63112,56 @@ const Popup = props => {
|
|
|
63097
63112
|
Popup.Close = PopupClose;
|
|
63098
63113
|
|
|
63099
63114
|
installImportMetaCssBuild(import.meta);
|
|
63100
|
-
const css$B = /* css */`.
|
|
63101
|
-
|
|
63102
|
-
|
|
63103
|
-
|
|
63104
|
-
|
|
63105
|
-
|
|
63106
|
-
|
|
63107
|
-
--popover-outline-width: var(--picker-outline-width);
|
|
63108
|
-
--popover-outline-color: var(--picker-outline-color);
|
|
63109
|
-
--popover-box-shadow: var(--picker-popup-box-shadow, var(--navi-popup-box-shadow));
|
|
63110
|
-
--popover-max-height: var(--picker-popover-max-height);
|
|
63111
|
-
min-width: var(--picker-popover-min-width, var(--anchor-width, 0px));
|
|
63112
|
-
cursor: default;
|
|
63113
|
-
|
|
63114
|
-
& .navi_list_container {
|
|
63115
|
-
--list-border-radius: max(0px,
|
|
63116
|
-
var(--popover-border-radius) - var(--popover-border-width));
|
|
63117
|
-
overscroll-behavior: none;
|
|
63118
|
-
width: 100%;
|
|
63115
|
+
const css$B = /* css */`.navi_popover[data-picker-popup] {
|
|
63116
|
+
--popover-border-radius: var(--picker-border-radius);
|
|
63117
|
+
--popover-border-width: var(--picker-border-width);
|
|
63118
|
+
--popover-border-color: var(--x-picker-border-color);
|
|
63119
|
+
--popover-outline-width: var(--picker-outline-width);
|
|
63120
|
+
--popover-outline-color: var(--picker-outline-color);
|
|
63121
|
+
cursor: default;
|
|
63119
63122
|
|
|
63120
|
-
|
|
63121
|
-
|
|
63122
|
-
|
|
63123
|
-
|
|
63124
|
-
}
|
|
63123
|
+
&:not([navi-hidden]) {
|
|
63124
|
+
flex-direction: column;
|
|
63125
|
+
display: flex;
|
|
63126
|
+
}
|
|
63125
63127
|
|
|
63126
|
-
|
|
63127
|
-
|
|
63128
|
-
border-
|
|
63129
|
-
|
|
63128
|
+
& .navi_list_container {
|
|
63129
|
+
--list-border-radius: max(0px,
|
|
63130
|
+
var(--popover-border-radius) - var(--popover-border-width));
|
|
63131
|
+
overscroll-behavior: none;
|
|
63132
|
+
width: 100%;
|
|
63130
63133
|
|
|
63131
|
-
|
|
63132
|
-
|
|
63133
|
-
display: flex;
|
|
63134
|
-
}
|
|
63134
|
+
&:not([data-overflow-visible]) {
|
|
63135
|
+
overflow: auto;
|
|
63135
63136
|
}
|
|
63136
63137
|
}
|
|
63138
|
+
}
|
|
63137
63139
|
|
|
63138
|
-
|
|
63139
|
-
|
|
63140
|
-
|
|
63141
|
-
--dialog-border-width: var(--picker-dialog-border-width, 0px);
|
|
63142
|
-
--dialog-border-color: var(--x-picker-border-color);
|
|
63143
|
-
--dialog-background-color: var(--picker-popup-background-color, var(--navi-popup-background-color));
|
|
63144
|
-
--dialog-outline-width: var(--picker-outline-width);
|
|
63145
|
-
--dialog-outline-color: var(--picker-outline-color);
|
|
63146
|
-
--dialog-box-shadow: var(--picker-popup-box-shadow, var(--navi-popup-box-shadow));
|
|
63147
|
-
--dialog-min-width: var(--picker-dialog-min-width);
|
|
63148
|
-
--dialog-min-height: var(--picker-dialog-min-height);
|
|
63149
|
-
--dialog-max-width: var(--picker-dialog-max-width);
|
|
63150
|
-
--dialog-max-height: var(--picker-dialog-max-height);
|
|
63151
|
-
cursor: default;
|
|
63140
|
+
.navi_picker[aria-haspopup="listbox"][aria-expanded="true"][navi-popover-mode="overlay"] {
|
|
63141
|
+
border-color: #0000;
|
|
63142
|
+
}
|
|
63152
63143
|
|
|
63153
|
-
|
|
63154
|
-
|
|
63155
|
-
|
|
63144
|
+
.navi_dialog[data-picker-popup] {
|
|
63145
|
+
--dialog-border-radius: var(--picker-border-radius);
|
|
63146
|
+
--dialog-border-color: var(--x-picker-border-color);
|
|
63147
|
+
--dialog-outline-width: var(--picker-outline-width);
|
|
63148
|
+
--dialog-outline-color: var(--picker-outline-color);
|
|
63149
|
+
cursor: default;
|
|
63156
63150
|
|
|
63157
|
-
|
|
63158
|
-
|
|
63159
|
-
|
|
63160
|
-
overscroll-behavior: none;
|
|
63161
|
-
width: 100%;
|
|
63151
|
+
&[open] {
|
|
63152
|
+
flex-direction: column;
|
|
63153
|
+
}
|
|
63162
63154
|
|
|
63163
|
-
|
|
63164
|
-
|
|
63165
|
-
|
|
63166
|
-
|
|
63167
|
-
|
|
63155
|
+
& .navi_list_container {
|
|
63156
|
+
--list-border-radius: max(0px,
|
|
63157
|
+
var(--dialog-border-radius) - var(--dialog-border-width));
|
|
63158
|
+
overscroll-behavior: none;
|
|
63159
|
+
width: 100%;
|
|
63168
63160
|
|
|
63169
|
-
|
|
63170
|
-
|
|
63161
|
+
&:not([data-overflow-visible]) {
|
|
63162
|
+
overflow: auto;
|
|
63171
63163
|
}
|
|
63172
63164
|
}
|
|
63173
|
-
|
|
63174
|
-
&[data-popup-width-fit-content] {
|
|
63175
|
-
--picker-popover-min-width: 0px;
|
|
63176
|
-
}
|
|
63177
63165
|
}
|
|
63178
63166
|
`;
|
|
63179
63167
|
const PickerCustomResolver = props => {
|
|
@@ -63937,6 +63925,22 @@ const PickerContentInsidePopup = props => {
|
|
|
63937
63925
|
// dialogMaxWidth="var(--anchor-width)", as a ceiling) — what keeps a card
|
|
63938
63926
|
// its own width once lifted. Dialog's own `sizeFromAnchor`.
|
|
63939
63927
|
dialogSizeFromAnchor,
|
|
63928
|
+
// The caller's word on the popup's own box. Written on the popup element,
|
|
63929
|
+
// where Popover/Dialog map them to their own vars, rather than as vars on
|
|
63930
|
+
// the picker: a var on the picker inherits into everything the popup
|
|
63931
|
+
// holds, and the pickers in there would read it as their own.
|
|
63932
|
+
popupBackgroundColor,
|
|
63933
|
+
popupBorderRadius,
|
|
63934
|
+
popupBoxShadow,
|
|
63935
|
+
popoverMaxHeight,
|
|
63936
|
+
dialogBorderWidth,
|
|
63937
|
+
dialogMinWidth,
|
|
63938
|
+
dialogMinHeight,
|
|
63939
|
+
dialogMaxWidth,
|
|
63940
|
+
dialogMaxHeight,
|
|
63941
|
+
// The popover is at least as wide as the trigger. True when the CONTENT
|
|
63942
|
+
// should size it (a Wheel) instead of being stretched to the trigger.
|
|
63943
|
+
popupWidthFitContent,
|
|
63940
63944
|
animation,
|
|
63941
63945
|
grow,
|
|
63942
63946
|
animationDuration,
|
|
@@ -63955,7 +63959,6 @@ const PickerContentInsidePopup = props => {
|
|
|
63955
63959
|
return jsx(Next, {
|
|
63956
63960
|
"aria-haspopup": isPopover ? "listbox" : "dialog",
|
|
63957
63961
|
"navi-popover-mode": isPopover ? popoverMode : undefined,
|
|
63958
|
-
"data-dialog-size-from-anchor": !isPopover && dialogSizeFromAnchor ? "" : undefined,
|
|
63959
63962
|
...rest,
|
|
63960
63963
|
// On popupProps already (see the picker's popup assembly); they mean
|
|
63961
63964
|
// nothing to the picker element.
|
|
@@ -63997,7 +64000,23 @@ const PickerContentInsidePopup = props => {
|
|
|
63997
64000
|
})
|
|
63998
64001
|
}) : jsx(Popup, {
|
|
63999
64002
|
...popupProps,
|
|
64000
|
-
"data-testid": popupTestId
|
|
64003
|
+
"data-testid": popupTestId
|
|
64004
|
+
// What the CSS above keys on: this picker's own popup, and no other
|
|
64005
|
+
// popup below the picker.
|
|
64006
|
+
,
|
|
64007
|
+
"data-picker-popup": "",
|
|
64008
|
+
backgroundColor: popupBackgroundColor,
|
|
64009
|
+
borderRadius: popupBorderRadius,
|
|
64010
|
+
boxShadow: popupBoxShadow,
|
|
64011
|
+
borderWidth: isPopover ? undefined : dialogBorderWidth,
|
|
64012
|
+
minWidth: isPopover ? popupWidthFitContent ? undefined : "var(--anchor-width, 0px)" : dialogMinWidth,
|
|
64013
|
+
minHeight: isPopover ? undefined : dialogMinHeight
|
|
64014
|
+
// As wide as the trigger under dialogSizeFromAnchor: Dialog's own
|
|
64015
|
+
// sizeFromAnchor is a floor, this is the ceiling. A dialogMaxWidth of
|
|
64016
|
+
// the caller's still wins.
|
|
64017
|
+
,
|
|
64018
|
+
maxWidth: isPopover ? undefined : dialogMaxWidth === undefined && dialogSizeFromAnchor ? "var(--anchor-width)" : dialogMaxWidth,
|
|
64019
|
+
maxHeight: isPopover ? popoverMaxHeight : dialogMaxHeight,
|
|
64001
64020
|
mode: mode,
|
|
64002
64021
|
layer: popupLayer,
|
|
64003
64022
|
animation: animation,
|
|
@@ -72095,6 +72114,26 @@ const css$t = /* css */`@layer navi {
|
|
|
72095
72114
|
}
|
|
72096
72115
|
}
|
|
72097
72116
|
|
|
72117
|
+
& [data-picker-content] {
|
|
72118
|
+
--picker-padding: initial;
|
|
72119
|
+
--picker-padding-x: initial;
|
|
72120
|
+
--picker-padding-y: initial;
|
|
72121
|
+
--picker-padding-top: initial;
|
|
72122
|
+
--picker-padding-right: initial;
|
|
72123
|
+
--picker-padding-bottom: initial;
|
|
72124
|
+
--picker-padding-left: initial;
|
|
72125
|
+
--picker-press-padding: initial;
|
|
72126
|
+
--picker-press-padding-x: initial;
|
|
72127
|
+
--picker-press-padding-y: initial;
|
|
72128
|
+
--picker-press-padding-top: initial;
|
|
72129
|
+
--picker-press-padding-right: initial;
|
|
72130
|
+
--picker-press-padding-bottom: initial;
|
|
72131
|
+
--picker-press-padding-left: initial;
|
|
72132
|
+
--picker-slot-spacing: initial;
|
|
72133
|
+
--picker-align-x: initial;
|
|
72134
|
+
--picker-align-y: initial;
|
|
72135
|
+
}
|
|
72136
|
+
|
|
72098
72137
|
& .navi_picker_content {
|
|
72099
72138
|
--x-corner-top-left-radius: initial;
|
|
72100
72139
|
--x-corner-top-right-radius: initial;
|
|
@@ -72298,11 +72337,6 @@ const PickerButton = props => {
|
|
|
72298
72337
|
placeholder,
|
|
72299
72338
|
ui,
|
|
72300
72339
|
maxLines: maxLinesProp = 1,
|
|
72301
|
-
// By default the popover is at least as wide as the trigger (min-width:
|
|
72302
|
-
// --anchor-width). Set true when the CONTENT should dictate the popover width
|
|
72303
|
-
// (e.g. a Wheel) instead of being stretched to the trigger — see
|
|
72304
|
-
// picker_custom.jsx.
|
|
72305
|
-
popupWidthFitContent,
|
|
72306
72340
|
// Adds a clear button to the right slot, the same one type="search" puts at
|
|
72307
72341
|
// the end of an input: a picker holds a value the user chose, and unsetting
|
|
72308
72342
|
// it should not require reopening the popup to hunt for a "none" entry.
|
|
@@ -72327,7 +72361,13 @@ const PickerButton = props => {
|
|
|
72327
72361
|
// (see PickerInput below).
|
|
72328
72362
|
role,
|
|
72329
72363
|
readOnly,
|
|
72330
|
-
error
|
|
72364
|
+
error,
|
|
72365
|
+
// Who draws the loading outline. Left unsaid, the picker does, around its
|
|
72366
|
+
// own box; "custom" says someone else does — a bigger surface this box is
|
|
72367
|
+
// a piece of, waiting as a whole (see the `loadingOutline` doc).
|
|
72368
|
+
loadingOutline,
|
|
72369
|
+
// Where the outline runs, in px from the picker's box: negative is outside.
|
|
72370
|
+
loadingOutlineInset = -2
|
|
72331
72371
|
} = props;
|
|
72332
72372
|
// A word in a sentence is never truncated — and the clamp's overflow: hidden
|
|
72333
72373
|
// would cut its dotted underline, which sits on the edge of the line box
|
|
@@ -72447,7 +72487,6 @@ const PickerButton = props => {
|
|
|
72447
72487
|
"navi-single-line": isSingleLine ? "" : undefined,
|
|
72448
72488
|
"navi-ui-custom": ui === "default" ? undefined : "",
|
|
72449
72489
|
"data-readonly-opens": readOnlyOpens ? "" : undefined,
|
|
72450
|
-
"data-popup-width-fit-content": popupWidthFitContent ? "" : undefined,
|
|
72451
72490
|
...pickerRemainingProps,
|
|
72452
72491
|
basePseudoState: basePseudoState,
|
|
72453
72492
|
styleCSSVars: PickerStyleCSSVars,
|
|
@@ -72462,9 +72501,10 @@ const PickerButton = props => {
|
|
|
72462
72501
|
openWhileReadOnly: undefined,
|
|
72463
72502
|
ui: undefined,
|
|
72464
72503
|
maxLines: undefined,
|
|
72465
|
-
popupWidthFitContent: undefined,
|
|
72466
72504
|
error: undefined,
|
|
72467
|
-
dayLabel: undefined
|
|
72505
|
+
dayLabel: undefined,
|
|
72506
|
+
loadingOutline: undefined,
|
|
72507
|
+
loadingOutlineInset: undefined
|
|
72468
72508
|
// This wrapper will receive keyboard event bubbling from the picker popup content
|
|
72469
72509
|
// we re-dispatch on the input (to get escape to close for instance)
|
|
72470
72510
|
,
|
|
@@ -72495,9 +72535,9 @@ const PickerButton = props => {
|
|
|
72495
72535
|
children: jsxs(PickerContext.Provider, {
|
|
72496
72536
|
value: pickerContext,
|
|
72497
72537
|
children: [variant === "headless" ? null : jsx(LoadingOutline, {
|
|
72498
|
-
loading: loading,
|
|
72538
|
+
loading: loadingOutline === "custom" ? false : loading,
|
|
72499
72539
|
color: "var(--picker-loader-color)",
|
|
72500
|
-
inset:
|
|
72540
|
+
inset: loadingOutlineInset
|
|
72501
72541
|
}), jsx(PickerInput, {
|
|
72502
72542
|
role: hostRole,
|
|
72503
72543
|
"aria-labelledby": hostLabelId,
|
|
@@ -72732,7 +72772,7 @@ const PickerClear = ({
|
|
|
72732
72772
|
// removed is the whole field's, and the picker already draws the wait
|
|
72733
72773
|
// around all of it. Two outlines for one wait is one too many.
|
|
72734
72774
|
,
|
|
72735
|
-
loadingOutline:
|
|
72775
|
+
loadingOutline: "custom"
|
|
72736
72776
|
// preventDefault, not just tabIndex="-1": a mousedown focuses its target
|
|
72737
72777
|
// before any click happens, and this button should never hold focus at
|
|
72738
72778
|
// all — the field keeps it.
|
|
@@ -72906,21 +72946,16 @@ const PICKER_BUTTON_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":fo
|
|
|
72906
72946
|
const PickerInputPseudoClasses = [":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading", ":-navi-has-value", ":-navi-expanded"];
|
|
72907
72947
|
|
|
72908
72948
|
// A pair is [the css variable, the style whose values the prop is written in]:
|
|
72909
|
-
//
|
|
72910
|
-
//
|
|
72949
|
+
// slotSpacing takes what margin takes, pressPadding what padding takes — see
|
|
72950
|
+
// box.jsx's readCSSVarEntry.
|
|
72951
|
+
// What the props say about the picker's own box only. The popup props
|
|
72952
|
+
// (popupBackgroundColor, dialogMaxWidth…) are handed to the popup element by
|
|
72953
|
+
// picker_custom.jsx: a variable on the root inherits into everything the popup
|
|
72954
|
+
// holds, and the pickers in there would read it as their own.
|
|
72911
72955
|
const PickerStyleCSSVars = {
|
|
72912
72956
|
"outlineWidth": "--picker-outline-width",
|
|
72913
72957
|
"borderWidth": "--picker-border-width",
|
|
72914
72958
|
"borderRadius": "--picker-border-radius",
|
|
72915
|
-
"popoverMaxHeight": ["--picker-popover-max-height", "maxHeight"],
|
|
72916
|
-
"dialogMinWidth": ["--picker-dialog-min-width", "minWidth"],
|
|
72917
|
-
"dialogMinHeight": ["--picker-dialog-min-height", "minHeight"],
|
|
72918
|
-
"dialogMaxWidth": ["--picker-dialog-max-width", "maxWidth"],
|
|
72919
|
-
"dialogMaxHeight": ["--picker-dialog-max-height", "maxHeight"],
|
|
72920
|
-
"popupBackgroundColor": "--picker-popup-background-color",
|
|
72921
|
-
"popupBorderRadius": ["--picker-popup-border-radius", "borderRadius"],
|
|
72922
|
-
"popupBoxShadow": ["--picker-popup-box-shadow", "boxShadow"],
|
|
72923
|
-
"dialogBorderWidth": ["--picker-dialog-border-width", "borderWidth"],
|
|
72924
72959
|
"slotSpacing": ["--picker-slot-spacing", "margin"],
|
|
72925
72960
|
"pressPadding": ["--picker-press-padding", "padding"],
|
|
72926
72961
|
"pressPaddingX": ["--picker-press-padding-x", "padding"],
|
|
@@ -73027,6 +73062,8 @@ const PickerFirstResolver = props => {
|
|
|
73027
73062
|
* popoverMode?: "nearby" | "overlay",
|
|
73028
73063
|
* positionArea?: string,
|
|
73029
73064
|
* popupWidthFitContent?: boolean,
|
|
73065
|
+
* loadingOutline?: "custom",
|
|
73066
|
+
* loadingOutlineInset?: number,
|
|
73030
73067
|
* variant?: "icon" | "circle" | "headless" | "discrete" | "button" | "text" | "bare" | "picker",
|
|
73031
73068
|
* icon?: boolean,
|
|
73032
73069
|
* alignX?: "start" | "center" | "end",
|
|
@@ -73144,9 +73181,12 @@ const PickerFirstResolver = props => {
|
|
|
73144
73181
|
* its own as well. Either way a card shows the score the moment the sheet
|
|
73145
73182
|
* leaves and takes it back on a refusal, with nothing held by the caller.
|
|
73146
73183
|
* `loading` is the wait it wears meanwhile: navi draws its loading outline
|
|
73147
|
-
* on every trigger,
|
|
73148
|
-
*
|
|
73149
|
-
*
|
|
73184
|
+
* on every trigger, two pixels out of the box. On a card-sized
|
|
73185
|
+
* `variant="bare"` that run sits on the card's own border and reads as a
|
|
73186
|
+
* border blinking; `loadingOutlineInset` moves it clear of it. And when the
|
|
73187
|
+
* picker's box is not the shape of what waits, `loadingOutline="custom"`
|
|
73188
|
+
* lets the drawing draw the wait itself, from that flag or from
|
|
73189
|
+
* `[data-loading]` on the picker root in css.
|
|
73150
73190
|
* @param {boolean} [readOnly] Nothing in this picker can be changed — and it
|
|
73151
73191
|
* still opens, so what is in the popup can be read: everything in there is
|
|
73152
73192
|
* held read-only in turn, each control greying out and saying why on its own.
|
|
@@ -73273,6 +73313,21 @@ const PickerFirstResolver = props => {
|
|
|
73273
73313
|
* nearest positioned ancestor it happens to find. `"picker"` (or an explicit
|
|
73274
73314
|
* `variant={undefined}`) asks a confirm or callout picker for the field-like
|
|
73275
73315
|
* drawing every other picker has.
|
|
73316
|
+
* @param {"custom"} [loadingOutline] Who draws the loading outline while the
|
|
73317
|
+
* action runs. Left unsaid, the picker does, around its own box. `"custom"`
|
|
73318
|
+
* says someone else does — what it means on a `Button` too — for a picker
|
|
73319
|
+
* that carries a wait drawn elsewhere: two nested pickers sharing one run
|
|
73320
|
+
* (a score picker drawn inside the card an edit picker wraps, see
|
|
73321
|
+
* `12_picker_card_demo.html`) are one wait, and one outline; and a
|
|
73322
|
+
* `variant="bare"` whose box is not
|
|
73323
|
+
* the shape of what waits (a card with a note pinned under it) leaves the
|
|
73324
|
+
* outline to the card, which knows its own box. The wait itself is still
|
|
73325
|
+
* worn: `aria-busy`, the busy refusal, the error callout, `[data-loading]`.
|
|
73326
|
+
* @param {number} [loadingOutlineInset=-2] Where the loading outline runs, in
|
|
73327
|
+
* px from the picker's box — negative is outside. A field wants it right on
|
|
73328
|
+
* its border; a card-sized trigger wants it a few pixels out, clear of the
|
|
73329
|
+
* card's own frame, so it reads as a run around the card rather than as its
|
|
73330
|
+
* border blinking.
|
|
73276
73331
|
* @param {boolean} [icon] The trigger is one icon — the `ui`, or the chevron
|
|
73277
73332
|
* when there is none. Its box is that icon's box plus the padding asked for
|
|
73278
73333
|
* and nothing else: no right slot, and no control line to be as tall as, so
|
|
@@ -73371,9 +73426,9 @@ const PickerFirstResolver = props => {
|
|
|
73371
73426
|
* as a ceiling, unless a `dialogMaxWidth` says otherwise. What keeps a card
|
|
73372
73427
|
* its own width once lifted out of the page (`animation="growing"`, with
|
|
73373
73428
|
* `data-grow` on the card inside the popup): it moves, and nothing else
|
|
73374
|
-
* about it changes.
|
|
73375
|
-
*
|
|
73376
|
-
*
|
|
73429
|
+
* about it changes. `dialogMaxWidth="var(--anchor-width)"` says the same
|
|
73430
|
+
* ceiling by hand: the popup props are written on the dialog element, where
|
|
73431
|
+
* that variable lives.
|
|
73377
73432
|
* @param {"cancel"|"close"} [escapeEffect="cancel"] What Escape does to an open
|
|
73378
73433
|
* picker. "cancel" puts back the value the picker had at open, and a dialog
|
|
73379
73434
|
* picker also goes back in history — so anything written to the url while it
|
|
@@ -76019,7 +76074,7 @@ const SplitButton = props => {
|
|
|
76019
76074
|
readOnly,
|
|
76020
76075
|
disabled,
|
|
76021
76076
|
// The outline belongs around the pair, drawn below.
|
|
76022
|
-
loadingOutline:
|
|
76077
|
+
loadingOutline: "custom"
|
|
76023
76078
|
};
|
|
76024
76079
|
return jsxs(Box, {
|
|
76025
76080
|
ref: rootRef,
|