@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.
@@ -55465,7 +55465,8 @@ a.navi_button {
55465
55465
 
55466
55466
  &[data-icon] {
55467
55467
  --button-padding: 0;
55468
- display: inline-flex;
55468
+ justify-content: center;
55469
+ align-items: center;
55469
55470
  }
55470
55471
 
55471
55472
  &[data-cta] {
@@ -55563,7 +55564,12 @@ const ButtonUI = props => {
55563
55564
  });
55564
55565
  return jsxs(Box, {
55565
55566
  inline: true,
55566
- block: true,
55567
+ block: true
55568
+ // An icon is laid out as a box rather than on a line of text that is not
55569
+ // there, which is also what makes alignX/alignY place it. Before the
55570
+ // caller's props, so their own flex direction wins.
55571
+ ,
55572
+ flex: icon ? "x" : undefined,
55567
55573
  ...buttonControlRootProps,
55568
55574
  ...buttonControlHostProps,
55569
55575
  // eslint-disable-next-line react/no-children-prop
@@ -79792,7 +79798,6 @@ const css$w = /* css */`@layer navi;
79792
79798
  background: var(--x-background);
79793
79799
  background-color: var(--x-background-color);
79794
79800
  border-radius: 1em;
79795
- align-items: stretch;
79796
79801
  display: inline;
79797
79802
  position: relative;
79798
79803
 
@@ -79802,13 +79807,25 @@ const css$w = /* css */`@layer navi;
79802
79807
 
79803
79808
  &[data-text-overflow] {
79804
79809
  display: inline;
79810
+ }
79805
79811
 
79806
- & .navi_text_overflow_wrapper {
79807
- gap: 0;
79808
- }
79812
+ &[data-has-button] {
79813
+ align-items: center;
79814
+ display: inline-flex;
79815
+ }
79816
+
79817
+ & .navi_badge_label {
79818
+ text-overflow: ellipsis;
79819
+ text-box: trim-both cap alphabetic;
79820
+ overflow-clip-margin: padding-box calc((1lh - 1em) / 2);
79821
+ align-self: baseline;
79822
+ min-width: 0;
79823
+ overflow-x: clip;
79809
79824
  }
79810
79825
 
79811
79826
  & [role="button"] {
79827
+ box-sizing: content-box;
79828
+ height: 1cap;
79812
79829
  margin-top: calc(-1 * var(--x-badge-padding-top));
79813
79830
  margin-bottom: calc(-1 * var(--x-badge-padding-bottom));
79814
79831
  padding-top: var(--x-badge-padding-top);
@@ -79818,6 +79835,7 @@ const css$w = /* css */`@layer navi;
79818
79835
  cursor: pointer;
79819
79836
  pointer-events: auto;
79820
79837
  user-select: none;
79838
+ flex-shrink: 0;
79821
79839
  align-items: center;
79822
79840
  display: inline-flex;
79823
79841
 
@@ -79866,6 +79884,16 @@ const BadgeUI = ({
79866
79884
  ref
79867
79885
  } = props;
79868
79886
  useAccentColorAttributes(ref, null);
79887
+ const childArray = toChildArray(children);
79888
+ if (childArray.some(isBadgeButton)) {
79889
+ props = {
79890
+ "inline": true,
79891
+ "flex": true,
79892
+ ...props,
79893
+ "data-has-button": ""
79894
+ };
79895
+ children = wrapLabels(childArray);
79896
+ }
79869
79897
  return jsx(Text, {
79870
79898
  className: withPropsClassName("navi_badge", className),
79871
79899
  bold: true,
@@ -79926,6 +79954,35 @@ const BadgeButtonUI = props => {
79926
79954
  });
79927
79955
  };
79928
79956
  Badge.Button = BadgeButton;
79957
+ const isBadgeButton = child => {
79958
+ return isValidElement(child) && child.type === BadgeButton;
79959
+ };
79960
+ // Each run of children between buttons becomes one label: a single flex item
79961
+ // holding its text, so the trim reaches a bare string and the text keeps its
79962
+ // own baseline alignment inside.
79963
+ const wrapLabels = childArray => {
79964
+ const items = [];
79965
+ let run = [];
79966
+ const closeRun = () => {
79967
+ if (run.length > 0) {
79968
+ items.push(jsx("span", {
79969
+ className: "navi_badge_label",
79970
+ children: run
79971
+ }));
79972
+ run = [];
79973
+ }
79974
+ };
79975
+ for (const child of childArray) {
79976
+ if (isBadgeButton(child)) {
79977
+ closeRun();
79978
+ items.push(child);
79979
+ } else {
79980
+ run.push(child);
79981
+ }
79982
+ }
79983
+ closeRun();
79984
+ return items;
79985
+ };
79929
79986
 
79930
79987
  installImportMetaCssBuild(import.meta);
79931
79988
  const css$v = /* css */`@layer navi;
@@ -80665,8 +80722,6 @@ const PickerChip = ({
80665
80722
  ...rest
80666
80723
  }) => {
80667
80724
  return jsxs(Badge, {
80668
- inline: true,
80669
- flex: true,
80670
80725
  ...rest,
80671
80726
  children: [children, jsx(Badge.Button, {
80672
80727
  selfInteractions: "click",
@@ -84694,7 +84749,10 @@ const css$n = /* css */`.navi_split_button {
84694
84749
  * `pressOutside`, `escapeEffect`, `closeOnFocusOut`,
84695
84750
  * `scrollCapture`, `focusCapture`, `popupBackgroundColor`,
84696
84751
  * `popupBorderRadius`, `animation`. See picker.jsx for what each one says.
84697
- * Anything else lands on the split button's own box.
84752
+ * An `aria-*` attribute describes the button and reaches the main half —
84753
+ * `aria-pressed` for a split button whose main half toggles a mode;
84754
+ * `aria-hidden` excepted, which hides the whole control. Anything else lands
84755
+ * on the split button's own box.
84698
84756
  */
84699
84757
  const SplitButton = props => {
84700
84758
  import.meta.css = [css$n, "@jsenv/navi/src/control/input/split_button.jsx"];
@@ -84731,11 +84789,12 @@ const SplitButton = props => {
84731
84789
  id,
84732
84790
  ...rest
84733
84791
  } = props;
84734
- // Everything the popup answers to travels to the Picker; everything else is
84735
- // the split button's own box (margins, width, data-*). Sorted by name rather
84736
- // than named one by one so a Picker popup prop is forwarded by adding it to
84737
- // that list, not by threading it through here.
84738
- const [popupProps, boxProps] = splitPopupProps(rest);
84792
+ // Everything the popup answers to travels to the Picker; an aria-* describes
84793
+ // the button a screen reader meets, which is the main half; everything else
84794
+ // is the split button's own box (margins, width, data-*). Sorted by name
84795
+ // rather than named one by one so a Picker popup prop is forwarded by adding
84796
+ // it to that list, not by threading it through here.
84797
+ const [popupProps, buttonAriaProps, boxProps] = sortRestProps(rest);
84739
84798
  // A split button is a control on the page, not a place one goes: its menu
84740
84799
  // hangs off it even on a phone, where a picker left to itself would decide a
84741
84800
  // small screen means a dialog. Passing mode="dialog" asks for that back.
@@ -84805,6 +84864,7 @@ const SplitButton = props => {
84805
84864
  commandFor: commandFor,
84806
84865
  "command-value": commandValue,
84807
84866
  prefetch: prefetch,
84867
+ ...buttonAriaProps,
84808
84868
  ...halfProps,
84809
84869
  children: label === undefined ? optionShown?.label : label
84810
84870
  }), jsxs("div", {
@@ -84812,14 +84872,7 @@ const SplitButton = props => {
84812
84872
  children: [jsx(Button, {
84813
84873
  icon: true,
84814
84874
  paddingX: "s",
84815
- expandY: true
84816
- // flex + align: the icon is the whole content, so it is laid out as
84817
- // its own box in the middle of the button. Left to flow inline it
84818
- // would sit on the baseline of a line of text that is not there,
84819
- // with the descender space still kept below it.
84820
- ,
84821
- flex: true,
84822
- align: "center",
84875
+ expandY: true,
84823
84876
  "aria-label": menuLabel,
84824
84877
  command: "--navi-open",
84825
84878
  commandFor: menuId,
@@ -84900,17 +84953,22 @@ const SplitButton = props => {
84900
84953
  // a caller reaches all of them through the split button (see picker.jsx's JSDoc
84901
84954
  // for what each one says).
84902
84955
  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"]);
84903
- const splitPopupProps = props => {
84956
+ const sortRestProps = props => {
84904
84957
  const popupProps = {};
84958
+ const buttonAriaProps = {};
84905
84959
  const boxProps = {};
84906
84960
  for (const key of Object.keys(props)) {
84907
84961
  if (POPUP_PROP_SET.has(key)) {
84908
84962
  popupProps[key] = props[key];
84963
+ } else if (key.startsWith("aria-") && key !== "aria-hidden") {
84964
+ // aria-hidden hides a subtree rather than describing a button: on the
84965
+ // main half alone it would leave the chevron half exposed.
84966
+ buttonAriaProps[key] = props[key];
84909
84967
  } else {
84910
84968
  boxProps[key] = props[key];
84911
84969
  }
84912
84970
  }
84913
- return [popupProps, boxProps];
84971
+ return [popupProps, buttonAriaProps, boxProps];
84914
84972
  };
84915
84973
 
84916
84974
  /**
@@ -91930,8 +91988,6 @@ const ButtonCopyToClipboard = ({
91930
91988
  children: "Copié !"
91931
91989
  }), jsx(Button, {
91932
91990
  className: "navi_copy_button",
91933
- flex: "y",
91934
- alignY: "center",
91935
91991
  icon: true,
91936
91992
  revealOnInteraction: true,
91937
91993
  square: true,
@@ -92820,8 +92876,6 @@ const MessageBox = ({
92820
92876
  action: onClose,
92821
92877
  icon: true,
92822
92878
  border: "none",
92823
- alignX: "center",
92824
- alignY: "center",
92825
92879
  style: {
92826
92880
  ":hover": {
92827
92881
  backgroundColor: "rgba(0, 0, 0, 0.1)"