@jsenv/navi 0.29.306 → 0.29.307
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 +228 -181
- package/dist/dev/jsenv_navi.js.map +10 -10
- package/dist/jsenv_navi.js +202 -175
- package/dist/jsenv_navi.js.map +10 -10
- 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:
|
|
@@ -48862,10 +48858,11 @@ const ButtonUI = props => {
|
|
|
48862
48858
|
cta,
|
|
48863
48859
|
spacing,
|
|
48864
48860
|
contentDisplay,
|
|
48865
|
-
//
|
|
48866
|
-
//
|
|
48867
|
-
// the outline belongs around the whole
|
|
48868
|
-
|
|
48861
|
+
// Who draws the loading outline. Left unsaid, the button does; "custom"
|
|
48862
|
+
// says someone else does — a button that is one half of a bigger control:
|
|
48863
|
+
// what is busy is the control, and the outline belongs around the whole
|
|
48864
|
+
// of it (see split_button.jsx).
|
|
48865
|
+
loadingOutline
|
|
48869
48866
|
} = props;
|
|
48870
48867
|
const [buttonControlRootProps, buttonControlHostProps, controlChildrenWrapperProps] = useControlProps(props, {
|
|
48871
48868
|
controlType: "button"
|
|
@@ -48991,7 +48988,7 @@ const ButtonUI = props => {
|
|
|
48991
48988
|
visualSelector: visualSelector,
|
|
48992
48989
|
hasChildUsingForwardedProps: true,
|
|
48993
48990
|
children: [jsx(LoadingOutline, {
|
|
48994
|
-
loading: loadingOutline
|
|
48991
|
+
loading: loadingOutline === "custom" ? false : loading,
|
|
48995
48992
|
inset: -1,
|
|
48996
48993
|
color: "var(--button-loader-color)"
|
|
48997
48994
|
}), jsx(ControlChildrenWrapper, {
|
|
@@ -61238,6 +61235,9 @@ const DIALOG_STYLE_CSS_VARS = {
|
|
|
61238
61235
|
animationDuration: "--popup-animation-duration",
|
|
61239
61236
|
backdropColor: "--backdrop-background",
|
|
61240
61237
|
backdropFilter: "--backdrop-filter",
|
|
61238
|
+
backgroundColor: "--dialog-background-color",
|
|
61239
|
+
boxShadow: "--dialog-box-shadow",
|
|
61240
|
+
borderWidth: "--dialog-border-width",
|
|
61241
61241
|
borderRadius: "--dialog-border-radius",
|
|
61242
61242
|
minWidth: "--dialog-min-width",
|
|
61243
61243
|
maxWidth: "--dialog-max-width",
|
|
@@ -62831,10 +62831,17 @@ const POPOVER_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible",
|
|
|
62831
62831
|
// Lets consumers pass animationDuration="0.5s"/borderRadius="8px" as regular
|
|
62832
62832
|
// props; Box maps them to the CSS vars for us (see box.jsx's styleCSSVars
|
|
62833
62833
|
// handling).
|
|
62834
|
+
// The paint props go through the popover's own vars rather than the properties
|
|
62835
|
+
// themselves, so the stylesheet keeps the last word on them (the same reason
|
|
62836
|
+
// dialog.jsx gives for borderRadius).
|
|
62834
62837
|
const POPUP_STYLE_CSS_VARS = {
|
|
62835
62838
|
animationDuration: "--popup-animation-duration",
|
|
62836
62839
|
backdropColor: "--backdrop-background",
|
|
62837
62840
|
backdropFilter: "--backdrop-filter",
|
|
62841
|
+
backgroundColor: "--popover-background-color",
|
|
62842
|
+
boxShadow: "--popover-box-shadow",
|
|
62843
|
+
borderWidth: "--popover-border-width",
|
|
62844
|
+
borderRadius: "--popover-border-radius",
|
|
62838
62845
|
minWidth: "--popover-min-width",
|
|
62839
62846
|
maxWidth: "--popover-max-width",
|
|
62840
62847
|
minHeight: "--popover-min-height",
|
|
@@ -63097,83 +63104,56 @@ const Popup = props => {
|
|
|
63097
63104
|
Popup.Close = PopupClose;
|
|
63098
63105
|
|
|
63099
63106
|
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%;
|
|
63107
|
+
const css$B = /* css */`.navi_popover[data-picker-popup] {
|
|
63108
|
+
--popover-border-radius: var(--picker-border-radius);
|
|
63109
|
+
--popover-border-width: var(--picker-border-width);
|
|
63110
|
+
--popover-border-color: var(--x-picker-border-color);
|
|
63111
|
+
--popover-outline-width: var(--picker-outline-width);
|
|
63112
|
+
--popover-outline-color: var(--picker-outline-color);
|
|
63113
|
+
cursor: default;
|
|
63119
63114
|
|
|
63120
|
-
|
|
63121
|
-
|
|
63122
|
-
|
|
63123
|
-
|
|
63124
|
-
}
|
|
63115
|
+
&:not([navi-hidden]) {
|
|
63116
|
+
flex-direction: column;
|
|
63117
|
+
display: flex;
|
|
63118
|
+
}
|
|
63125
63119
|
|
|
63126
|
-
|
|
63127
|
-
|
|
63128
|
-
border-
|
|
63129
|
-
|
|
63120
|
+
& .navi_list_container {
|
|
63121
|
+
--list-border-radius: max(0px,
|
|
63122
|
+
var(--popover-border-radius) - var(--popover-border-width));
|
|
63123
|
+
overscroll-behavior: none;
|
|
63124
|
+
width: 100%;
|
|
63130
63125
|
|
|
63131
|
-
|
|
63132
|
-
|
|
63133
|
-
display: flex;
|
|
63134
|
-
}
|
|
63126
|
+
&:not([data-overflow-visible]) {
|
|
63127
|
+
overflow: auto;
|
|
63135
63128
|
}
|
|
63136
63129
|
}
|
|
63130
|
+
}
|
|
63137
63131
|
|
|
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;
|
|
63132
|
+
.navi_picker[aria-haspopup="listbox"][aria-expanded="true"][navi-popover-mode="overlay"] {
|
|
63133
|
+
border-color: #0000;
|
|
63134
|
+
}
|
|
63152
63135
|
|
|
63153
|
-
|
|
63154
|
-
|
|
63155
|
-
|
|
63136
|
+
.navi_dialog[data-picker-popup] {
|
|
63137
|
+
--dialog-border-radius: var(--picker-border-radius);
|
|
63138
|
+
--dialog-border-color: var(--x-picker-border-color);
|
|
63139
|
+
--dialog-outline-width: var(--picker-outline-width);
|
|
63140
|
+
--dialog-outline-color: var(--picker-outline-color);
|
|
63141
|
+
cursor: default;
|
|
63156
63142
|
|
|
63157
|
-
|
|
63158
|
-
|
|
63159
|
-
|
|
63160
|
-
overscroll-behavior: none;
|
|
63161
|
-
width: 100%;
|
|
63143
|
+
&[open] {
|
|
63144
|
+
flex-direction: column;
|
|
63145
|
+
}
|
|
63162
63146
|
|
|
63163
|
-
|
|
63164
|
-
|
|
63165
|
-
|
|
63166
|
-
|
|
63167
|
-
|
|
63147
|
+
& .navi_list_container {
|
|
63148
|
+
--list-border-radius: max(0px,
|
|
63149
|
+
var(--dialog-border-radius) - var(--dialog-border-width));
|
|
63150
|
+
overscroll-behavior: none;
|
|
63151
|
+
width: 100%;
|
|
63168
63152
|
|
|
63169
|
-
|
|
63170
|
-
|
|
63153
|
+
&:not([data-overflow-visible]) {
|
|
63154
|
+
overflow: auto;
|
|
63171
63155
|
}
|
|
63172
63156
|
}
|
|
63173
|
-
|
|
63174
|
-
&[data-popup-width-fit-content] {
|
|
63175
|
-
--picker-popover-min-width: 0px;
|
|
63176
|
-
}
|
|
63177
63157
|
}
|
|
63178
63158
|
`;
|
|
63179
63159
|
const PickerCustomResolver = props => {
|
|
@@ -63937,6 +63917,22 @@ const PickerContentInsidePopup = props => {
|
|
|
63937
63917
|
// dialogMaxWidth="var(--anchor-width)", as a ceiling) — what keeps a card
|
|
63938
63918
|
// its own width once lifted. Dialog's own `sizeFromAnchor`.
|
|
63939
63919
|
dialogSizeFromAnchor,
|
|
63920
|
+
// The caller's word on the popup's own box. Written on the popup element,
|
|
63921
|
+
// where Popover/Dialog map them to their own vars, rather than as vars on
|
|
63922
|
+
// the picker: a var on the picker inherits into everything the popup
|
|
63923
|
+
// holds, and the pickers in there would read it as their own.
|
|
63924
|
+
popupBackgroundColor,
|
|
63925
|
+
popupBorderRadius,
|
|
63926
|
+
popupBoxShadow,
|
|
63927
|
+
popoverMaxHeight,
|
|
63928
|
+
dialogBorderWidth,
|
|
63929
|
+
dialogMinWidth,
|
|
63930
|
+
dialogMinHeight,
|
|
63931
|
+
dialogMaxWidth,
|
|
63932
|
+
dialogMaxHeight,
|
|
63933
|
+
// The popover is at least as wide as the trigger. True when the CONTENT
|
|
63934
|
+
// should size it (a Wheel) instead of being stretched to the trigger.
|
|
63935
|
+
popupWidthFitContent,
|
|
63940
63936
|
animation,
|
|
63941
63937
|
grow,
|
|
63942
63938
|
animationDuration,
|
|
@@ -63955,7 +63951,6 @@ const PickerContentInsidePopup = props => {
|
|
|
63955
63951
|
return jsx(Next, {
|
|
63956
63952
|
"aria-haspopup": isPopover ? "listbox" : "dialog",
|
|
63957
63953
|
"navi-popover-mode": isPopover ? popoverMode : undefined,
|
|
63958
|
-
"data-dialog-size-from-anchor": !isPopover && dialogSizeFromAnchor ? "" : undefined,
|
|
63959
63954
|
...rest,
|
|
63960
63955
|
// On popupProps already (see the picker's popup assembly); they mean
|
|
63961
63956
|
// nothing to the picker element.
|
|
@@ -63997,7 +63992,23 @@ const PickerContentInsidePopup = props => {
|
|
|
63997
63992
|
})
|
|
63998
63993
|
}) : jsx(Popup, {
|
|
63999
63994
|
...popupProps,
|
|
64000
|
-
"data-testid": popupTestId
|
|
63995
|
+
"data-testid": popupTestId
|
|
63996
|
+
// What the CSS above keys on: this picker's own popup, and no other
|
|
63997
|
+
// popup below the picker.
|
|
63998
|
+
,
|
|
63999
|
+
"data-picker-popup": "",
|
|
64000
|
+
backgroundColor: popupBackgroundColor,
|
|
64001
|
+
borderRadius: popupBorderRadius,
|
|
64002
|
+
boxShadow: popupBoxShadow,
|
|
64003
|
+
borderWidth: isPopover ? undefined : dialogBorderWidth,
|
|
64004
|
+
minWidth: isPopover ? popupWidthFitContent ? undefined : "var(--anchor-width, 0px)" : dialogMinWidth,
|
|
64005
|
+
minHeight: isPopover ? undefined : dialogMinHeight
|
|
64006
|
+
// As wide as the trigger under dialogSizeFromAnchor: Dialog's own
|
|
64007
|
+
// sizeFromAnchor is a floor, this is the ceiling. A dialogMaxWidth of
|
|
64008
|
+
// the caller's still wins.
|
|
64009
|
+
,
|
|
64010
|
+
maxWidth: isPopover ? undefined : dialogMaxWidth === undefined && dialogSizeFromAnchor ? "var(--anchor-width)" : dialogMaxWidth,
|
|
64011
|
+
maxHeight: isPopover ? popoverMaxHeight : dialogMaxHeight,
|
|
64001
64012
|
mode: mode,
|
|
64002
64013
|
layer: popupLayer,
|
|
64003
64014
|
animation: animation,
|
|
@@ -72095,6 +72106,26 @@ const css$t = /* css */`@layer navi {
|
|
|
72095
72106
|
}
|
|
72096
72107
|
}
|
|
72097
72108
|
|
|
72109
|
+
& [data-picker-content] {
|
|
72110
|
+
--picker-padding: initial;
|
|
72111
|
+
--picker-padding-x: initial;
|
|
72112
|
+
--picker-padding-y: initial;
|
|
72113
|
+
--picker-padding-top: initial;
|
|
72114
|
+
--picker-padding-right: initial;
|
|
72115
|
+
--picker-padding-bottom: initial;
|
|
72116
|
+
--picker-padding-left: initial;
|
|
72117
|
+
--picker-press-padding: initial;
|
|
72118
|
+
--picker-press-padding-x: initial;
|
|
72119
|
+
--picker-press-padding-y: initial;
|
|
72120
|
+
--picker-press-padding-top: initial;
|
|
72121
|
+
--picker-press-padding-right: initial;
|
|
72122
|
+
--picker-press-padding-bottom: initial;
|
|
72123
|
+
--picker-press-padding-left: initial;
|
|
72124
|
+
--picker-slot-spacing: initial;
|
|
72125
|
+
--picker-align-x: initial;
|
|
72126
|
+
--picker-align-y: initial;
|
|
72127
|
+
}
|
|
72128
|
+
|
|
72098
72129
|
& .navi_picker_content {
|
|
72099
72130
|
--x-corner-top-left-radius: initial;
|
|
72100
72131
|
--x-corner-top-right-radius: initial;
|
|
@@ -72298,11 +72329,6 @@ const PickerButton = props => {
|
|
|
72298
72329
|
placeholder,
|
|
72299
72330
|
ui,
|
|
72300
72331
|
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
72332
|
// Adds a clear button to the right slot, the same one type="search" puts at
|
|
72307
72333
|
// the end of an input: a picker holds a value the user chose, and unsetting
|
|
72308
72334
|
// it should not require reopening the popup to hunt for a "none" entry.
|
|
@@ -72327,7 +72353,13 @@ const PickerButton = props => {
|
|
|
72327
72353
|
// (see PickerInput below).
|
|
72328
72354
|
role,
|
|
72329
72355
|
readOnly,
|
|
72330
|
-
error
|
|
72356
|
+
error,
|
|
72357
|
+
// Who draws the loading outline. Left unsaid, the picker does, around its
|
|
72358
|
+
// own box; "custom" says someone else does — a bigger surface this box is
|
|
72359
|
+
// a piece of, waiting as a whole (see the `loadingOutline` doc).
|
|
72360
|
+
loadingOutline,
|
|
72361
|
+
// Where the outline runs, in px from the picker's box: negative is outside.
|
|
72362
|
+
loadingOutlineInset = -2
|
|
72331
72363
|
} = props;
|
|
72332
72364
|
// A word in a sentence is never truncated — and the clamp's overflow: hidden
|
|
72333
72365
|
// would cut its dotted underline, which sits on the edge of the line box
|
|
@@ -72447,7 +72479,6 @@ const PickerButton = props => {
|
|
|
72447
72479
|
"navi-single-line": isSingleLine ? "" : undefined,
|
|
72448
72480
|
"navi-ui-custom": ui === "default" ? undefined : "",
|
|
72449
72481
|
"data-readonly-opens": readOnlyOpens ? "" : undefined,
|
|
72450
|
-
"data-popup-width-fit-content": popupWidthFitContent ? "" : undefined,
|
|
72451
72482
|
...pickerRemainingProps,
|
|
72452
72483
|
basePseudoState: basePseudoState,
|
|
72453
72484
|
styleCSSVars: PickerStyleCSSVars,
|
|
@@ -72462,9 +72493,10 @@ const PickerButton = props => {
|
|
|
72462
72493
|
openWhileReadOnly: undefined,
|
|
72463
72494
|
ui: undefined,
|
|
72464
72495
|
maxLines: undefined,
|
|
72465
|
-
popupWidthFitContent: undefined,
|
|
72466
72496
|
error: undefined,
|
|
72467
|
-
dayLabel: undefined
|
|
72497
|
+
dayLabel: undefined,
|
|
72498
|
+
loadingOutline: undefined,
|
|
72499
|
+
loadingOutlineInset: undefined
|
|
72468
72500
|
// This wrapper will receive keyboard event bubbling from the picker popup content
|
|
72469
72501
|
// we re-dispatch on the input (to get escape to close for instance)
|
|
72470
72502
|
,
|
|
@@ -72495,9 +72527,9 @@ const PickerButton = props => {
|
|
|
72495
72527
|
children: jsxs(PickerContext.Provider, {
|
|
72496
72528
|
value: pickerContext,
|
|
72497
72529
|
children: [variant === "headless" ? null : jsx(LoadingOutline, {
|
|
72498
|
-
loading: loading,
|
|
72530
|
+
loading: loadingOutline === "custom" ? false : loading,
|
|
72499
72531
|
color: "var(--picker-loader-color)",
|
|
72500
|
-
inset:
|
|
72532
|
+
inset: loadingOutlineInset
|
|
72501
72533
|
}), jsx(PickerInput, {
|
|
72502
72534
|
role: hostRole,
|
|
72503
72535
|
"aria-labelledby": hostLabelId,
|
|
@@ -72732,7 +72764,7 @@ const PickerClear = ({
|
|
|
72732
72764
|
// removed is the whole field's, and the picker already draws the wait
|
|
72733
72765
|
// around all of it. Two outlines for one wait is one too many.
|
|
72734
72766
|
,
|
|
72735
|
-
loadingOutline:
|
|
72767
|
+
loadingOutline: "custom"
|
|
72736
72768
|
// preventDefault, not just tabIndex="-1": a mousedown focuses its target
|
|
72737
72769
|
// before any click happens, and this button should never hold focus at
|
|
72738
72770
|
// all — the field keeps it.
|
|
@@ -72906,21 +72938,16 @@ const PICKER_BUTTON_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":fo
|
|
|
72906
72938
|
const PickerInputPseudoClasses = [":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading", ":-navi-has-value", ":-navi-expanded"];
|
|
72907
72939
|
|
|
72908
72940
|
// A pair is [the css variable, the style whose values the prop is written in]:
|
|
72909
|
-
//
|
|
72910
|
-
//
|
|
72941
|
+
// slotSpacing takes what margin takes, pressPadding what padding takes — see
|
|
72942
|
+
// box.jsx's readCSSVarEntry.
|
|
72943
|
+
// What the props say about the picker's own box only. The popup props
|
|
72944
|
+
// (popupBackgroundColor, dialogMaxWidth…) are handed to the popup element by
|
|
72945
|
+
// picker_custom.jsx: a variable on the root inherits into everything the popup
|
|
72946
|
+
// holds, and the pickers in there would read it as their own.
|
|
72911
72947
|
const PickerStyleCSSVars = {
|
|
72912
72948
|
"outlineWidth": "--picker-outline-width",
|
|
72913
72949
|
"borderWidth": "--picker-border-width",
|
|
72914
72950
|
"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
72951
|
"slotSpacing": ["--picker-slot-spacing", "margin"],
|
|
72925
72952
|
"pressPadding": ["--picker-press-padding", "padding"],
|
|
72926
72953
|
"pressPaddingX": ["--picker-press-padding-x", "padding"],
|
|
@@ -73027,6 +73054,8 @@ const PickerFirstResolver = props => {
|
|
|
73027
73054
|
* popoverMode?: "nearby" | "overlay",
|
|
73028
73055
|
* positionArea?: string,
|
|
73029
73056
|
* popupWidthFitContent?: boolean,
|
|
73057
|
+
* loadingOutline?: "custom",
|
|
73058
|
+
* loadingOutlineInset?: number,
|
|
73030
73059
|
* variant?: "icon" | "circle" | "headless" | "discrete" | "button" | "text" | "bare" | "picker",
|
|
73031
73060
|
* icon?: boolean,
|
|
73032
73061
|
* alignX?: "start" | "center" | "end",
|
|
@@ -73144,9 +73173,12 @@ const PickerFirstResolver = props => {
|
|
|
73144
73173
|
* its own as well. Either way a card shows the score the moment the sheet
|
|
73145
73174
|
* leaves and takes it back on a refusal, with nothing held by the caller.
|
|
73146
73175
|
* `loading` is the wait it wears meanwhile: navi draws its loading outline
|
|
73147
|
-
* on every trigger,
|
|
73148
|
-
*
|
|
73149
|
-
*
|
|
73176
|
+
* on every trigger, two pixels out of the box. On a card-sized
|
|
73177
|
+
* `variant="bare"` that run sits on the card's own border and reads as a
|
|
73178
|
+
* border blinking; `loadingOutlineInset` moves it clear of it. And when the
|
|
73179
|
+
* picker's box is not the shape of what waits, `loadingOutline="custom"`
|
|
73180
|
+
* lets the drawing draw the wait itself, from that flag or from
|
|
73181
|
+
* `[data-loading]` on the picker root in css.
|
|
73150
73182
|
* @param {boolean} [readOnly] Nothing in this picker can be changed — and it
|
|
73151
73183
|
* still opens, so what is in the popup can be read: everything in there is
|
|
73152
73184
|
* held read-only in turn, each control greying out and saying why on its own.
|
|
@@ -73273,6 +73305,21 @@ const PickerFirstResolver = props => {
|
|
|
73273
73305
|
* nearest positioned ancestor it happens to find. `"picker"` (or an explicit
|
|
73274
73306
|
* `variant={undefined}`) asks a confirm or callout picker for the field-like
|
|
73275
73307
|
* drawing every other picker has.
|
|
73308
|
+
* @param {"custom"} [loadingOutline] Who draws the loading outline while the
|
|
73309
|
+
* action runs. Left unsaid, the picker does, around its own box. `"custom"`
|
|
73310
|
+
* says someone else does — what it means on a `Button` too — for a picker
|
|
73311
|
+
* that carries a wait drawn elsewhere: two nested pickers sharing one run
|
|
73312
|
+
* (a score picker drawn inside the card an edit picker wraps, see
|
|
73313
|
+
* `12_picker_card_demo.html`) are one wait, and one outline; and a
|
|
73314
|
+
* `variant="bare"` whose box is not
|
|
73315
|
+
* the shape of what waits (a card with a note pinned under it) leaves the
|
|
73316
|
+
* outline to the card, which knows its own box. The wait itself is still
|
|
73317
|
+
* worn: `aria-busy`, the busy refusal, the error callout, `[data-loading]`.
|
|
73318
|
+
* @param {number} [loadingOutlineInset=-2] Where the loading outline runs, in
|
|
73319
|
+
* px from the picker's box — negative is outside. A field wants it right on
|
|
73320
|
+
* its border; a card-sized trigger wants it a few pixels out, clear of the
|
|
73321
|
+
* card's own frame, so it reads as a run around the card rather than as its
|
|
73322
|
+
* border blinking.
|
|
73276
73323
|
* @param {boolean} [icon] The trigger is one icon — the `ui`, or the chevron
|
|
73277
73324
|
* when there is none. Its box is that icon's box plus the padding asked for
|
|
73278
73325
|
* and nothing else: no right slot, and no control line to be as tall as, so
|
|
@@ -73371,9 +73418,9 @@ const PickerFirstResolver = props => {
|
|
|
73371
73418
|
* as a ceiling, unless a `dialogMaxWidth` says otherwise. What keeps a card
|
|
73372
73419
|
* its own width once lifted out of the page (`animation="growing"`, with
|
|
73373
73420
|
* `data-grow` on the card inside the popup): it moves, and nothing else
|
|
73374
|
-
* about it changes.
|
|
73375
|
-
*
|
|
73376
|
-
*
|
|
73421
|
+
* about it changes. `dialogMaxWidth="var(--anchor-width)"` says the same
|
|
73422
|
+
* ceiling by hand: the popup props are written on the dialog element, where
|
|
73423
|
+
* that variable lives.
|
|
73377
73424
|
* @param {"cancel"|"close"} [escapeEffect="cancel"] What Escape does to an open
|
|
73378
73425
|
* picker. "cancel" puts back the value the picker had at open, and a dialog
|
|
73379
73426
|
* picker also goes back in history — so anything written to the url while it
|
|
@@ -76019,7 +76066,7 @@ const SplitButton = props => {
|
|
|
76019
76066
|
readOnly,
|
|
76020
76067
|
disabled,
|
|
76021
76068
|
// The outline belongs around the pair, drawn below.
|
|
76022
|
-
loadingOutline:
|
|
76069
|
+
loadingOutline: "custom"
|
|
76023
76070
|
};
|
|
76024
76071
|
return jsxs(Box, {
|
|
76025
76072
|
ref: rootRef,
|