@jsenv/navi 0.29.444 → 0.29.446

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.
@@ -56668,7 +56668,8 @@ a.navi_button {
56668
56668
 
56669
56669
  &[data-icon] {
56670
56670
  --button-padding: 0;
56671
- display: inline-flex;
56671
+ justify-content: center;
56672
+ align-items: center;
56672
56673
  }
56673
56674
 
56674
56675
  &[data-cta] {
@@ -56766,7 +56767,12 @@ const ButtonUI = props => {
56766
56767
  });
56767
56768
  return jsxs(Box, {
56768
56769
  inline: true,
56769
- block: true,
56770
+ block: true
56771
+ // An icon is laid out as a box rather than on a line of text that is not
56772
+ // there, which is also what makes alignX/alignY place it. Before the
56773
+ // caller's props, so their own flex direction wins.
56774
+ ,
56775
+ flex: icon ? "x" : undefined,
56770
56776
  ...buttonControlRootProps,
56771
56777
  ...buttonControlHostProps,
56772
56778
  // eslint-disable-next-line react/no-children-prop
@@ -81357,7 +81363,6 @@ const css$w = /* css */`@layer navi;
81357
81363
  background: var(--x-background);
81358
81364
  background-color: var(--x-background-color);
81359
81365
  border-radius: 1em;
81360
- align-items: stretch;
81361
81366
  display: inline;
81362
81367
  position: relative;
81363
81368
 
@@ -81367,13 +81372,25 @@ const css$w = /* css */`@layer navi;
81367
81372
 
81368
81373
  &[data-text-overflow] {
81369
81374
  display: inline;
81375
+ }
81370
81376
 
81371
- & .navi_text_overflow_wrapper {
81372
- gap: 0;
81373
- }
81377
+ &[data-has-button] {
81378
+ align-items: center;
81379
+ display: inline-flex;
81380
+ }
81381
+
81382
+ & .navi_badge_label {
81383
+ text-overflow: ellipsis;
81384
+ text-box: trim-both cap alphabetic;
81385
+ overflow-clip-margin: padding-box calc((1lh - 1em) / 2);
81386
+ align-self: baseline;
81387
+ min-width: 0;
81388
+ overflow-x: clip;
81374
81389
  }
81375
81390
 
81376
81391
  & [role="button"] {
81392
+ box-sizing: content-box;
81393
+ height: 1cap;
81377
81394
  margin-top: calc(-1 * var(--x-badge-padding-top));
81378
81395
  margin-bottom: calc(-1 * var(--x-badge-padding-bottom));
81379
81396
  padding-top: var(--x-badge-padding-top);
@@ -81383,6 +81400,7 @@ const css$w = /* css */`@layer navi;
81383
81400
  cursor: pointer;
81384
81401
  pointer-events: auto;
81385
81402
  user-select: none;
81403
+ flex-shrink: 0;
81386
81404
  align-items: center;
81387
81405
  display: inline-flex;
81388
81406
 
@@ -81431,6 +81449,16 @@ const BadgeUI = ({
81431
81449
  ref
81432
81450
  } = props;
81433
81451
  useAccentColorAttributes(ref, null);
81452
+ const childArray = toChildArray(children);
81453
+ if (childArray.some(isBadgeButton)) {
81454
+ props = {
81455
+ "inline": true,
81456
+ "flex": true,
81457
+ ...props,
81458
+ "data-has-button": ""
81459
+ };
81460
+ children = wrapLabels(childArray);
81461
+ }
81434
81462
  return jsx(Text, {
81435
81463
  className: withPropsClassName("navi_badge", className),
81436
81464
  bold: true,
@@ -81491,6 +81519,35 @@ const BadgeButtonUI = props => {
81491
81519
  });
81492
81520
  };
81493
81521
  Badge.Button = BadgeButton;
81522
+ const isBadgeButton = child => {
81523
+ return isValidElement(child) && child.type === BadgeButton;
81524
+ };
81525
+ // Each run of children between buttons becomes one label: a single flex item
81526
+ // holding its text, so the trim reaches a bare string and the text keeps its
81527
+ // own baseline alignment inside.
81528
+ const wrapLabels = childArray => {
81529
+ const items = [];
81530
+ let run = [];
81531
+ const closeRun = () => {
81532
+ if (run.length > 0) {
81533
+ items.push(jsx("span", {
81534
+ className: "navi_badge_label",
81535
+ children: run
81536
+ }));
81537
+ run = [];
81538
+ }
81539
+ };
81540
+ for (const child of childArray) {
81541
+ if (isBadgeButton(child)) {
81542
+ closeRun();
81543
+ items.push(child);
81544
+ } else {
81545
+ run.push(child);
81546
+ }
81547
+ }
81548
+ closeRun();
81549
+ return items;
81550
+ };
81494
81551
 
81495
81552
  installImportMetaCssBuild(import.meta);
81496
81553
  const css$v = /* css */`@layer navi;
@@ -82230,8 +82287,6 @@ const PickerChip = ({
82230
82287
  ...rest
82231
82288
  }) => {
82232
82289
  return jsxs(Badge, {
82233
- inline: true,
82234
- flex: true,
82235
82290
  ...rest,
82236
82291
  children: [children, jsx(Badge.Button, {
82237
82292
  selfInteractions: "click",
@@ -86925,7 +86980,10 @@ const css$n = /* css */`.navi_split_button {
86925
86980
  * `pressOutside`, `escapeEffect`, `closeOnFocusOut`,
86926
86981
  * `scrollCapture`, `focusCapture`, `popupBackgroundColor`,
86927
86982
  * `popupBorderRadius`, `animation`. See picker.jsx for what each one says.
86928
- * Anything else lands on the split button's own box.
86983
+ * An `aria-*` attribute describes the button and reaches the main half —
86984
+ * `aria-pressed` for a split button whose main half toggles a mode;
86985
+ * `aria-hidden` excepted, which hides the whole control. Anything else lands
86986
+ * on the split button's own box.
86929
86987
  */
86930
86988
  const SplitButton = props => {
86931
86989
  import.meta.css = [css$n, "@jsenv/navi/src/control/input/split_button.jsx"];
@@ -86962,11 +87020,12 @@ const SplitButton = props => {
86962
87020
  id,
86963
87021
  ...rest
86964
87022
  } = props;
86965
- // Everything the popup answers to travels to the Picker; everything else is
86966
- // the split button's own box (margins, width, data-*). Sorted by name rather
86967
- // than named one by one so a Picker popup prop is forwarded by adding it to
86968
- // that list, not by threading it through here.
86969
- const [popupProps, boxProps] = splitPopupProps(rest);
87023
+ // Everything the popup answers to travels to the Picker; an aria-* describes
87024
+ // the button a screen reader meets, which is the main half; everything else
87025
+ // is the split button's own box (margins, width, data-*). Sorted by name
87026
+ // rather than named one by one so a Picker popup prop is forwarded by adding
87027
+ // it to that list, not by threading it through here.
87028
+ const [popupProps, buttonAriaProps, boxProps] = sortRestProps(rest);
86970
87029
  // A split button is a control on the page, not a place one goes: its menu
86971
87030
  // hangs off it even on a phone, where a picker left to itself would decide a
86972
87031
  // small screen means a dialog. Passing mode="dialog" asks for that back.
@@ -87036,6 +87095,7 @@ const SplitButton = props => {
87036
87095
  commandFor: commandFor,
87037
87096
  "command-value": commandValue,
87038
87097
  prefetch: prefetch,
87098
+ ...buttonAriaProps,
87039
87099
  ...halfProps,
87040
87100
  children: label === undefined ? optionShown?.label : label
87041
87101
  }), jsxs("div", {
@@ -87043,14 +87103,7 @@ const SplitButton = props => {
87043
87103
  children: [jsx(Button, {
87044
87104
  icon: true,
87045
87105
  paddingX: "s",
87046
- expandY: true
87047
- // flex + align: the icon is the whole content, so it is laid out as
87048
- // its own box in the middle of the button. Left to flow inline it
87049
- // would sit on the baseline of a line of text that is not there,
87050
- // with the descender space still kept below it.
87051
- ,
87052
- flex: true,
87053
- align: "center",
87106
+ expandY: true,
87054
87107
  "aria-label": menuLabel,
87055
87108
  command: "--navi-open",
87056
87109
  commandFor: menuId,
@@ -87131,17 +87184,22 @@ const SplitButton = props => {
87131
87184
  // a caller reaches all of them through the split button (see picker.jsx's JSDoc
87132
87185
  // for what each one says).
87133
87186
  const POPUP_PROP_SET = new Set(["mode", "popupLayer", "popupTestId", "positionArea", "popoverMode", "popoverSpacing", "popupWidthFitContent", "popoverMaxHeight", "dialogMinWidth", "dialogMinHeight", "dialogMaxWidth", "dialogMaxHeight", "dialogExpand", "dialogExpandX", "dialogExpandY", "dockedOnSmallTouchScreen", "marginWithContainer", "backdrop", "backdropVariant", "backdropColor", "backdropFilter", "pressOutside", "escapeEffect", "closeOnFocusOut", "scrollCapture", "focusCapture", "popupBackgroundColor", "popupBorderRadius", "animation"]);
87134
- const splitPopupProps = props => {
87187
+ const sortRestProps = props => {
87135
87188
  const popupProps = {};
87189
+ const buttonAriaProps = {};
87136
87190
  const boxProps = {};
87137
87191
  for (const key of Object.keys(props)) {
87138
87192
  if (POPUP_PROP_SET.has(key)) {
87139
87193
  popupProps[key] = props[key];
87194
+ } else if (key.startsWith("aria-") && key !== "aria-hidden") {
87195
+ // aria-hidden hides a subtree rather than describing a button: on the
87196
+ // main half alone it would leave the chevron half exposed.
87197
+ buttonAriaProps[key] = props[key];
87140
87198
  } else {
87141
87199
  boxProps[key] = props[key];
87142
87200
  }
87143
87201
  }
87144
- return [popupProps, boxProps];
87202
+ return [popupProps, buttonAriaProps, boxProps];
87145
87203
  };
87146
87204
 
87147
87205
  /**
@@ -94169,8 +94227,6 @@ const ButtonCopyToClipboard = ({
94169
94227
  children: "Copié !"
94170
94228
  }), jsx(Button, {
94171
94229
  className: "navi_copy_button",
94172
- flex: "y",
94173
- alignY: "center",
94174
94230
  icon: true,
94175
94231
  revealOnInteraction: true,
94176
94232
  square: true,
@@ -95059,8 +95115,6 @@ const MessageBox = ({
95059
95115
  action: onClose,
95060
95116
  icon: true,
95061
95117
  border: "none",
95062
- alignX: "center",
95063
- alignY: "center",
95064
95118
  style: {
95065
95119
  ":hover": {
95066
95120
  backgroundColor: "rgba(0, 0, 0, 0.1)"