@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.
@@ -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
 
@@ -8211,6 +8211,75 @@ const languagesSignal = computed(() => {
8211
8211
  // (nor the "languagechange" listener above).
8212
8212
  setRuntimeLangSource(() => languagesSignal.value);
8213
8213
 
8214
+ /**
8215
+ * Where navi meets @jsenv/validity.
8216
+ *
8217
+ * validity names a refusal with a key and its parameters rather than a
8218
+ * sentence, so that a field and a server can refuse in the same words in the
8219
+ * language of the person reading. navi is one of those two callers: it says the
8220
+ * sentence, in the browser, through `naviI18n`. The keys line up on purpose —
8221
+ * validity's `"single_space.start"` is navi's `"constraint.single_space.start"`
8222
+ * — so overriding a message is looking up one key, not going through a
8223
+ * translation table.
8224
+ *
8225
+ * The other direction is `constraintFromValidityRule`: a rule an app wrote for
8226
+ * its server, worn by a control as a constraint.
8227
+ */
8228
+
8229
+
8230
+ /**
8231
+ * Turns a @jsenv/validity rule into a constraint a control can wear, so an app
8232
+ * rule written once — in the package its server reads too — is checked on both
8233
+ * sides instead of being written twice.
8234
+ *
8235
+ * @param {object} rule
8236
+ * `{ name, applyOn(ruleValue, value, ruleConfig) }`, the same object passed
8237
+ * to `createValidity({ rules })`.
8238
+ * @param {object} [ruleConfig]
8239
+ * What parameterizes the rule, under its own name — `{ maxWords: 40 }` for a
8240
+ * rule named `maxWords`. Pass `formatMessage` here to say the refusal through
8241
+ * the app's own i18n; without it the key is looked up in `naviI18n` under
8242
+ * `constraint.<key>`, and a rule answering with a finished sentence is shown
8243
+ * as-is.
8244
+ *
8245
+ * Call it once, at module level: a constraint rebuilt on every render is a new
8246
+ * object on every check.
8247
+ */
8248
+ const constraintFromValidityRule = (rule, ruleConfig = {}) => {
8249
+ const { formatMessage, ...ruleParams } = ruleConfig;
8250
+ return {
8251
+ name: rule.name,
8252
+ check: (field) => {
8253
+ const result = rule.applyOn(
8254
+ ruleParams[rule.name],
8255
+ field.uiState,
8256
+ ruleParams,
8257
+ );
8258
+ if (!result) {
8259
+ return null;
8260
+ }
8261
+ if (typeof result === "string") {
8262
+ return result;
8263
+ }
8264
+ if (formatMessage) {
8265
+ return formatMessage(result.key, result.params);
8266
+ }
8267
+ return naviI18nFromValidityMessage(result);
8268
+ },
8269
+ };
8270
+ };
8271
+
8272
+ const naviI18nFromValidityMessage = ({ key, params }) => {
8273
+ if (params && typeof params.max === "number") {
8274
+ // Lets a template pluralize on the bound it names: "[max] retour[s]".
8275
+ return naviI18n(`constraint.${key}`, {
8276
+ ...params,
8277
+ s: params.max > 1 ? "s" : "",
8278
+ });
8279
+ }
8280
+ return naviI18n(`constraint.${key}`, params);
8281
+ };
8282
+
8214
8283
  /**
8215
8284
  * https://developer.mozilla.org/en-US/docs/Web/HTML/Guides/Constraint_validation
8216
8285
  */
@@ -8360,9 +8429,8 @@ const PATTERN_CONSTRAINT = {
8360
8429
  };
8361
8430
  CONSTRAINT_ATTRIBUTE_SET.add("pattern");
8362
8431
 
8363
- // https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/email#validation
8364
- const emailregex =
8365
- /^[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])?)*$/;
8432
+ // What an address is, is @jsenv/validity's `type: "email"`: a server checking
8433
+ // the value again refuses it for the same reason and in the same words.
8366
8434
  const TYPE_EMAIL_CONSTRAINT = {
8367
8435
  name: "type_email",
8368
8436
  messageAttribute: "data-type-message",
@@ -8376,14 +8444,11 @@ const TYPE_EMAIL_CONSTRAINT = {
8376
8444
  if (!valueAsString) {
8377
8445
  return null;
8378
8446
  }
8379
- if (emailregex.test(valueAsString)) {
8447
+ const result = TYPE_RULE.applyOn("email", valueAsString);
8448
+ if (!result) {
8380
8449
  return null;
8381
8450
  }
8382
-
8383
- if (!valueAsString.includes("@")) {
8384
- return naviI18n("constraint.type.email.at", { value: valueAsString });
8385
- }
8386
- return naviI18n("constraint.type.email.invalid");
8451
+ return naviI18nFromValidityMessage(result);
8387
8452
  },
8388
8453
  };
8389
8454
 
@@ -11542,75 +11607,6 @@ const isFunctionButNotAnActionFunction = (action) => {
11542
11607
  return typeof action === "function" && !action.isAction;
11543
11608
  };
11544
11609
 
11545
- /**
11546
- * Where navi meets @jsenv/validity.
11547
- *
11548
- * validity names a refusal with a key and its parameters rather than a
11549
- * sentence, so that a field and a server can refuse in the same words in the
11550
- * language of the person reading. navi is one of those two callers: it says the
11551
- * sentence, in the browser, through `naviI18n`. The keys line up on purpose —
11552
- * validity's `"single_space.start"` is navi's `"constraint.single_space.start"`
11553
- * — so overriding a message is looking up one key, not going through a
11554
- * translation table.
11555
- *
11556
- * The other direction is `constraintFromValidityRule`: a rule an app wrote for
11557
- * its server, worn by a control as a constraint.
11558
- */
11559
-
11560
-
11561
- /**
11562
- * Turns a @jsenv/validity rule into a constraint a control can wear, so an app
11563
- * rule written once — in the package its server reads too — is checked on both
11564
- * sides instead of being written twice.
11565
- *
11566
- * @param {object} rule
11567
- * `{ name, applyOn(ruleValue, value, ruleConfig) }`, the same object passed
11568
- * to `createValidity({ rules })`.
11569
- * @param {object} [ruleConfig]
11570
- * What parameterizes the rule, under its own name — `{ maxWords: 40 }` for a
11571
- * rule named `maxWords`. Pass `formatMessage` here to say the refusal through
11572
- * the app's own i18n; without it the key is looked up in `naviI18n` under
11573
- * `constraint.<key>`, and a rule answering with a finished sentence is shown
11574
- * as-is.
11575
- *
11576
- * Call it once, at module level: a constraint rebuilt on every render is a new
11577
- * object on every check.
11578
- */
11579
- const constraintFromValidityRule = (rule, ruleConfig = {}) => {
11580
- const { formatMessage, ...ruleParams } = ruleConfig;
11581
- return {
11582
- name: rule.name,
11583
- check: (field) => {
11584
- const result = rule.applyOn(
11585
- ruleParams[rule.name],
11586
- field.uiState,
11587
- ruleParams,
11588
- );
11589
- if (!result) {
11590
- return null;
11591
- }
11592
- if (typeof result === "string") {
11593
- return result;
11594
- }
11595
- if (formatMessage) {
11596
- return formatMessage(result.key, result.params);
11597
- }
11598
- return naviI18nFromValidityMessage(result);
11599
- },
11600
- };
11601
- };
11602
-
11603
- const naviI18nFromValidityMessage = ({ key, params }) => {
11604
- if (params && typeof params.max === "number") {
11605
- // Lets a template pluralize on the bound it names: "[max] retour[s]".
11606
- return naviI18n(`constraint.${key}`, {
11607
- ...params,
11608
- s: params.max > 1 ? "s" : "",
11609
- });
11610
- }
11611
- return naviI18n(`constraint.${key}`, params);
11612
- };
11613
-
11614
11610
  /**
11615
11611
  * `data-displayable` — the value must be something the layout can actually
11616
11612
  * draw. What it refuses and why lives in @jsenv/validity's DISPLAYABLE_RULE:
@@ -48125,10 +48121,11 @@ const ButtonUI = props => {
48125
48121
  cta,
48126
48122
  spacing,
48127
48123
  contentDisplay,
48128
- // Whether the button draws the loading outline itself. A button that is
48129
- // one half of a bigger control says no: what is busy is the control, and
48130
- // the outline belongs around the whole of it (see split_button.jsx).
48131
- loadingOutline = true
48124
+ // Who draws the loading outline. Left unsaid, the button does; "custom"
48125
+ // says someone else does — a button that is one half of a bigger control:
48126
+ // what is busy is the control, and the outline belongs around the whole
48127
+ // of it (see split_button.jsx).
48128
+ loadingOutline
48132
48129
  } = props;
48133
48130
  const [buttonControlRootProps, buttonControlHostProps, controlChildrenWrapperProps] = useControlProps(props, {
48134
48131
  controlType: "button"
@@ -48254,7 +48251,7 @@ const ButtonUI = props => {
48254
48251
  visualSelector: visualSelector,
48255
48252
  hasChildUsingForwardedProps: true,
48256
48253
  children: [jsx(LoadingOutline, {
48257
- loading: loadingOutline && loading,
48254
+ loading: loadingOutline === "custom" ? false : loading,
48258
48255
  inset: -1,
48259
48256
  color: "var(--button-loader-color)"
48260
48257
  }), jsx(ControlChildrenWrapper, {
@@ -60436,6 +60433,9 @@ const DIALOG_STYLE_CSS_VARS = {
60436
60433
  animationDuration: "--popup-animation-duration",
60437
60434
  backdropColor: "--backdrop-background",
60438
60435
  backdropFilter: "--backdrop-filter",
60436
+ backgroundColor: "--dialog-background-color",
60437
+ boxShadow: "--dialog-box-shadow",
60438
+ borderWidth: "--dialog-border-width",
60439
60439
  borderRadius: "--dialog-border-radius",
60440
60440
  minWidth: "--dialog-min-width",
60441
60441
  maxWidth: "--dialog-max-width",
@@ -62023,10 +62023,17 @@ const POPOVER_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible",
62023
62023
  // Lets consumers pass animationDuration="0.5s"/borderRadius="8px" as regular
62024
62024
  // props; Box maps them to the CSS vars for us (see box.jsx's styleCSSVars
62025
62025
  // handling).
62026
+ // The paint props go through the popover's own vars rather than the properties
62027
+ // themselves, so the stylesheet keeps the last word on them (the same reason
62028
+ // dialog.jsx gives for borderRadius).
62026
62029
  const POPUP_STYLE_CSS_VARS = {
62027
62030
  animationDuration: "--popup-animation-duration",
62028
62031
  backdropColor: "--backdrop-background",
62029
62032
  backdropFilter: "--backdrop-filter",
62033
+ backgroundColor: "--popover-background-color",
62034
+ boxShadow: "--popover-box-shadow",
62035
+ borderWidth: "--popover-border-width",
62036
+ borderRadius: "--popover-border-radius",
62030
62037
  minWidth: "--popover-min-width",
62031
62038
  maxWidth: "--popover-max-width",
62032
62039
  minHeight: "--popover-min-height",
@@ -62289,83 +62296,56 @@ const Popup = props => {
62289
62296
  Popup.Close = PopupClose;
62290
62297
 
62291
62298
  installImportMetaCssBuild(import.meta);
62292
- const css$B = /* css */`.navi_picker {
62293
- &[aria-haspopup="listbox"] {
62294
- & .navi_popover {
62295
- --popover-border-radius: var(--picker-popup-border-radius, var(--picker-border-radius));
62296
- --popover-border-width: var(--picker-border-width);
62297
- --popover-border-color: var(--x-picker-border-color);
62298
- --popover-background-color: var(--picker-popup-background-color, var(--navi-popup-background-color));
62299
- --popover-outline-width: var(--picker-outline-width);
62300
- --popover-outline-color: var(--picker-outline-color);
62301
- --popover-box-shadow: var(--picker-popup-box-shadow, var(--navi-popup-box-shadow));
62302
- --popover-max-height: var(--picker-popover-max-height);
62303
- min-width: var(--picker-popover-min-width, var(--anchor-width, 0px));
62304
- cursor: default;
62305
-
62306
- & .navi_list_container {
62307
- --list-border-radius: max(0px,
62308
- var(--popover-border-radius) - var(--popover-border-width));
62309
- overscroll-behavior: none;
62310
- width: 100%;
62299
+ const css$B = /* css */`.navi_popover[data-picker-popup] {
62300
+ --popover-border-radius: var(--picker-border-radius);
62301
+ --popover-border-width: var(--picker-border-width);
62302
+ --popover-border-color: var(--x-picker-border-color);
62303
+ --popover-outline-width: var(--picker-outline-width);
62304
+ --popover-outline-color: var(--picker-outline-color);
62305
+ cursor: default;
62311
62306
 
62312
- &:not([data-overflow-visible]) {
62313
- overflow: auto;
62314
- }
62315
- }
62316
- }
62307
+ &:not([navi-hidden]) {
62308
+ flex-direction: column;
62309
+ display: flex;
62310
+ }
62317
62311
 
62318
- &[aria-expanded="true"] {
62319
- &[navi-popover-mode="overlay"] {
62320
- border-color: #0000;
62321
- }
62312
+ & .navi_list_container {
62313
+ --list-border-radius: max(0px,
62314
+ var(--popover-border-radius) - var(--popover-border-width));
62315
+ overscroll-behavior: none;
62316
+ width: 100%;
62322
62317
 
62323
- & .navi_popover {
62324
- flex-direction: column;
62325
- display: flex;
62326
- }
62318
+ &:not([data-overflow-visible]) {
62319
+ overflow: auto;
62327
62320
  }
62328
62321
  }
62322
+ }
62329
62323
 
62330
- &[aria-haspopup="dialog"] {
62331
- & .navi_dialog {
62332
- --dialog-border-radius: var(--picker-popup-border-radius, var(--picker-border-radius));
62333
- --dialog-border-width: var(--picker-dialog-border-width, 0px);
62334
- --dialog-border-color: var(--x-picker-border-color);
62335
- --dialog-background-color: var(--picker-popup-background-color, var(--navi-popup-background-color));
62336
- --dialog-outline-width: var(--picker-outline-width);
62337
- --dialog-outline-color: var(--picker-outline-color);
62338
- --dialog-box-shadow: var(--picker-popup-box-shadow, var(--navi-popup-box-shadow));
62339
- --dialog-min-width: var(--picker-dialog-min-width);
62340
- --dialog-min-height: var(--picker-dialog-min-height);
62341
- --dialog-max-width: var(--picker-dialog-max-width);
62342
- --dialog-max-height: var(--picker-dialog-max-height);
62343
- cursor: default;
62324
+ .navi_picker[aria-haspopup="listbox"][aria-expanded="true"][navi-popover-mode="overlay"] {
62325
+ border-color: #0000;
62326
+ }
62344
62327
 
62345
- &[open] {
62346
- flex-direction: column;
62347
- }
62328
+ .navi_dialog[data-picker-popup] {
62329
+ --dialog-border-radius: var(--picker-border-radius);
62330
+ --dialog-border-color: var(--x-picker-border-color);
62331
+ --dialog-outline-width: var(--picker-outline-width);
62332
+ --dialog-outline-color: var(--picker-outline-color);
62333
+ cursor: default;
62348
62334
 
62349
- & .navi_list_container {
62350
- --list-border-radius: max(0px,
62351
- var(--dialog-border-radius) - var(--dialog-border-width));
62352
- overscroll-behavior: none;
62353
- width: 100%;
62335
+ &[open] {
62336
+ flex-direction: column;
62337
+ }
62354
62338
 
62355
- &:not([data-overflow-visible]) {
62356
- overflow: auto;
62357
- }
62358
- }
62359
- }
62339
+ & .navi_list_container {
62340
+ --list-border-radius: max(0px,
62341
+ var(--dialog-border-radius) - var(--dialog-border-width));
62342
+ overscroll-behavior: none;
62343
+ width: 100%;
62360
62344
 
62361
- &[data-dialog-size-from-anchor] .navi_dialog {
62362
- --dialog-max-width: var(--picker-dialog-max-width, var(--anchor-width));
62345
+ &:not([data-overflow-visible]) {
62346
+ overflow: auto;
62363
62347
  }
62364
62348
  }
62365
-
62366
- &[data-popup-width-fit-content] {
62367
- --picker-popover-min-width: 0px;
62368
- }
62369
62349
  }
62370
62350
  `;
62371
62351
  const PickerCustomResolver = props => {
@@ -63129,6 +63109,22 @@ const PickerContentInsidePopup = props => {
63129
63109
  // dialogMaxWidth="var(--anchor-width)", as a ceiling) — what keeps a card
63130
63110
  // its own width once lifted. Dialog's own `sizeFromAnchor`.
63131
63111
  dialogSizeFromAnchor,
63112
+ // The caller's word on the popup's own box. Written on the popup element,
63113
+ // where Popover/Dialog map them to their own vars, rather than as vars on
63114
+ // the picker: a var on the picker inherits into everything the popup
63115
+ // holds, and the pickers in there would read it as their own.
63116
+ popupBackgroundColor,
63117
+ popupBorderRadius,
63118
+ popupBoxShadow,
63119
+ popoverMaxHeight,
63120
+ dialogBorderWidth,
63121
+ dialogMinWidth,
63122
+ dialogMinHeight,
63123
+ dialogMaxWidth,
63124
+ dialogMaxHeight,
63125
+ // The popover is at least as wide as the trigger. True when the CONTENT
63126
+ // should size it (a Wheel) instead of being stretched to the trigger.
63127
+ popupWidthFitContent,
63132
63128
  animation,
63133
63129
  grow,
63134
63130
  animationDuration,
@@ -63147,7 +63143,6 @@ const PickerContentInsidePopup = props => {
63147
63143
  return jsx(Next, {
63148
63144
  "aria-haspopup": isPopover ? "listbox" : "dialog",
63149
63145
  "navi-popover-mode": isPopover ? popoverMode : undefined,
63150
- "data-dialog-size-from-anchor": !isPopover && dialogSizeFromAnchor ? "" : undefined,
63151
63146
  ...rest,
63152
63147
  // On popupProps already (see the picker's popup assembly); they mean
63153
63148
  // nothing to the picker element.
@@ -63189,7 +63184,23 @@ const PickerContentInsidePopup = props => {
63189
63184
  })
63190
63185
  }) : jsx(Popup, {
63191
63186
  ...popupProps,
63192
- "data-testid": popupTestId,
63187
+ "data-testid": popupTestId
63188
+ // What the CSS above keys on: this picker's own popup, and no other
63189
+ // popup below the picker.
63190
+ ,
63191
+ "data-picker-popup": "",
63192
+ backgroundColor: popupBackgroundColor,
63193
+ borderRadius: popupBorderRadius,
63194
+ boxShadow: popupBoxShadow,
63195
+ borderWidth: isPopover ? undefined : dialogBorderWidth,
63196
+ minWidth: isPopover ? popupWidthFitContent ? undefined : "var(--anchor-width, 0px)" : dialogMinWidth,
63197
+ minHeight: isPopover ? undefined : dialogMinHeight
63198
+ // As wide as the trigger under dialogSizeFromAnchor: Dialog's own
63199
+ // sizeFromAnchor is a floor, this is the ceiling. A dialogMaxWidth of
63200
+ // the caller's still wins.
63201
+ ,
63202
+ maxWidth: isPopover ? undefined : dialogMaxWidth === undefined && dialogSizeFromAnchor ? "var(--anchor-width)" : dialogMaxWidth,
63203
+ maxHeight: isPopover ? popoverMaxHeight : dialogMaxHeight,
63193
63204
  mode: mode,
63194
63205
  layer: popupLayer,
63195
63206
  animation: animation,
@@ -71229,6 +71240,26 @@ const css$t = /* css */`@layer navi {
71229
71240
  }
71230
71241
  }
71231
71242
 
71243
+ & [data-picker-content] {
71244
+ --picker-padding: initial;
71245
+ --picker-padding-x: initial;
71246
+ --picker-padding-y: initial;
71247
+ --picker-padding-top: initial;
71248
+ --picker-padding-right: initial;
71249
+ --picker-padding-bottom: initial;
71250
+ --picker-padding-left: initial;
71251
+ --picker-press-padding: initial;
71252
+ --picker-press-padding-x: initial;
71253
+ --picker-press-padding-y: initial;
71254
+ --picker-press-padding-top: initial;
71255
+ --picker-press-padding-right: initial;
71256
+ --picker-press-padding-bottom: initial;
71257
+ --picker-press-padding-left: initial;
71258
+ --picker-slot-spacing: initial;
71259
+ --picker-align-x: initial;
71260
+ --picker-align-y: initial;
71261
+ }
71262
+
71232
71263
  & .navi_picker_content {
71233
71264
  --x-corner-top-left-radius: initial;
71234
71265
  --x-corner-top-right-radius: initial;
@@ -71430,11 +71461,6 @@ const PickerButton = props => {
71430
71461
  placeholder,
71431
71462
  ui,
71432
71463
  maxLines: maxLinesProp = 1,
71433
- // By default the popover is at least as wide as the trigger (min-width:
71434
- // --anchor-width). Set true when the CONTENT should dictate the popover width
71435
- // (e.g. a Wheel) instead of being stretched to the trigger — see
71436
- // picker_custom.jsx.
71437
- popupWidthFitContent,
71438
71464
  // Adds a clear button to the right slot, the same one type="search" puts at
71439
71465
  // the end of an input: a picker holds a value the user chose, and unsetting
71440
71466
  // it should not require reopening the popup to hunt for a "none" entry.
@@ -71459,7 +71485,13 @@ const PickerButton = props => {
71459
71485
  // (see PickerInput below).
71460
71486
  role,
71461
71487
  readOnly,
71462
- error
71488
+ error,
71489
+ // Who draws the loading outline. Left unsaid, the picker does, around its
71490
+ // own box; "custom" says someone else does — a bigger surface this box is
71491
+ // a piece of, waiting as a whole (see the `loadingOutline` doc).
71492
+ loadingOutline,
71493
+ // Where the outline runs, in px from the picker's box: negative is outside.
71494
+ loadingOutlineInset = -2
71463
71495
  } = props;
71464
71496
  // A word in a sentence is never truncated — and the clamp's overflow: hidden
71465
71497
  // would cut its dotted underline, which sits on the edge of the line box
@@ -71578,7 +71610,6 @@ const PickerButton = props => {
71578
71610
  "navi-single-line": isSingleLine ? "" : undefined,
71579
71611
  "navi-ui-custom": ui === "default" ? undefined : "",
71580
71612
  "data-readonly-opens": readOnlyOpens ? "" : undefined,
71581
- "data-popup-width-fit-content": popupWidthFitContent ? "" : undefined,
71582
71613
  ...pickerRemainingProps,
71583
71614
  basePseudoState: basePseudoState,
71584
71615
  styleCSSVars: PickerStyleCSSVars,
@@ -71593,9 +71624,10 @@ const PickerButton = props => {
71593
71624
  openWhileReadOnly: undefined,
71594
71625
  ui: undefined,
71595
71626
  maxLines: undefined,
71596
- popupWidthFitContent: undefined,
71597
71627
  error: undefined,
71598
- dayLabel: undefined
71628
+ dayLabel: undefined,
71629
+ loadingOutline: undefined,
71630
+ loadingOutlineInset: undefined
71599
71631
  // This wrapper will receive keyboard event bubbling from the picker popup content
71600
71632
  // we re-dispatch on the input (to get escape to close for instance)
71601
71633
  ,
@@ -71626,9 +71658,9 @@ const PickerButton = props => {
71626
71658
  children: jsxs(PickerContext.Provider, {
71627
71659
  value: pickerContext,
71628
71660
  children: [variant === "headless" ? null : jsx(LoadingOutline, {
71629
- loading: loading,
71661
+ loading: loadingOutline === "custom" ? false : loading,
71630
71662
  color: "var(--picker-loader-color)",
71631
- inset: -2
71663
+ inset: loadingOutlineInset
71632
71664
  }), jsx(PickerInput, {
71633
71665
  role: hostRole,
71634
71666
  "aria-labelledby": hostLabelId,
@@ -71862,7 +71894,7 @@ const PickerClear = ({
71862
71894
  // removed is the whole field's, and the picker already draws the wait
71863
71895
  // around all of it. Two outlines for one wait is one too many.
71864
71896
  ,
71865
- loadingOutline: false
71897
+ loadingOutline: "custom"
71866
71898
  // preventDefault, not just tabIndex="-1": a mousedown focuses its target
71867
71899
  // before any click happens, and this button should never hold focus at
71868
71900
  // all — the field keeps it.
@@ -72025,21 +72057,16 @@ const PICKER_BUTTON_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":fo
72025
72057
  const PickerInputPseudoClasses = [":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading", ":-navi-has-value", ":-navi-expanded"];
72026
72058
 
72027
72059
  // A pair is [the css variable, the style whose values the prop is written in]:
72028
- // popupBorderRadius takes what borderRadius takes, dialogMinWidth what minWidth
72029
- // takes — see box.jsx's readCSSVarEntry.
72060
+ // slotSpacing takes what margin takes, pressPadding what padding takes — see
72061
+ // box.jsx's readCSSVarEntry.
72062
+ // What the props say about the picker's own box only. The popup props
72063
+ // (popupBackgroundColor, dialogMaxWidth…) are handed to the popup element by
72064
+ // picker_custom.jsx: a variable on the root inherits into everything the popup
72065
+ // holds, and the pickers in there would read it as their own.
72030
72066
  const PickerStyleCSSVars = {
72031
72067
  "outlineWidth": "--picker-outline-width",
72032
72068
  "borderWidth": "--picker-border-width",
72033
72069
  "borderRadius": "--picker-border-radius",
72034
- "popoverMaxHeight": ["--picker-popover-max-height", "maxHeight"],
72035
- "dialogMinWidth": ["--picker-dialog-min-width", "minWidth"],
72036
- "dialogMinHeight": ["--picker-dialog-min-height", "minHeight"],
72037
- "dialogMaxWidth": ["--picker-dialog-max-width", "maxWidth"],
72038
- "dialogMaxHeight": ["--picker-dialog-max-height", "maxHeight"],
72039
- "popupBackgroundColor": "--picker-popup-background-color",
72040
- "popupBorderRadius": ["--picker-popup-border-radius", "borderRadius"],
72041
- "popupBoxShadow": ["--picker-popup-box-shadow", "boxShadow"],
72042
- "dialogBorderWidth": ["--picker-dialog-border-width", "borderWidth"],
72043
72070
  "slotSpacing": ["--picker-slot-spacing", "margin"],
72044
72071
  "pressPadding": ["--picker-press-padding", "padding"],
72045
72072
  "pressPaddingX": ["--picker-press-padding-x", "padding"],
@@ -74604,7 +74631,7 @@ const SplitButton = props => {
74604
74631
  readOnly,
74605
74632
  disabled,
74606
74633
  // The outline belongs around the pair, drawn below.
74607
- loadingOutline: false
74634
+ loadingOutline: "custom"
74608
74635
  };
74609
74636
  return jsxs(Box, {
74610
74637
  ref: rootRef,