@jsenv/navi 0.23.2 → 0.23.4

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.
@@ -6919,6 +6919,8 @@ const getDefaultDisplay = (tagName) => {
6919
6919
  return TAG_NAME_TO_DEFAULT_DISPLAY.get(normalizedTagName) || "inline";
6920
6920
  };
6921
6921
 
6922
+ const pressedElements = new WeakSet();
6923
+
6922
6924
  const PSEUDO_CLASSES = {
6923
6925
  ":hover": {
6924
6926
  attribute: "data-hover",
@@ -6976,15 +6978,58 @@ const PSEUDO_CLASSES = {
6976
6978
  ":active": {
6977
6979
  attribute: "data-active",
6978
6980
  setup: (el, callback) => {
6979
- el.addEventListener("mousedown", callback);
6980
- document.addEventListener("mouseup", callback);
6981
+ const onPointerDown = (e) => {
6982
+ el.setPointerCapture(e.pointerId);
6983
+ const onRelease = () => {
6984
+ el.releasePointerCapture(e.pointerId);
6985
+ el.removeEventListener("lostpointercapture", onRelease);
6986
+ el.removeEventListener("pointercancel", onRelease);
6987
+ el.removeEventListener("pointerup", onRelease);
6988
+ callback();
6989
+ };
6990
+ el.addEventListener("lostpointercapture", onRelease);
6991
+ el.addEventListener("pointercancel", onRelease);
6992
+ el.addEventListener("pointerup", onRelease);
6993
+ callback();
6994
+ };
6995
+ el.addEventListener("pointerdown", onPointerDown);
6981
6996
  return () => {
6982
- el.removeEventListener("mousedown", callback);
6983
- document.removeEventListener("mouseup", callback);
6997
+ el.removeEventListener("pointerdown", onPointerDown);
6984
6998
  };
6985
6999
  },
6986
7000
  test: (el) => el.matches(":active"),
6987
7001
  },
7002
+ ":-navi-pressed": {
7003
+ attribute: "data-pressed",
7004
+ setup: (el, callback) => {
7005
+ const onPointerDown = (e) => {
7006
+ if (e.button !== 0) {
7007
+ // only left pointer (mouse left click, touch, pen)
7008
+ return;
7009
+ }
7010
+ pressedElements.add(el);
7011
+ el.setPointerCapture(e.pointerId);
7012
+ const onRelease = () => {
7013
+ pressedElements.delete(el);
7014
+ el.releasePointerCapture(e.pointerId);
7015
+ el.removeEventListener("lostpointercapture", onRelease);
7016
+ el.removeEventListener("pointercancel", onRelease);
7017
+ el.removeEventListener("pointerup", onRelease);
7018
+ callback();
7019
+ };
7020
+ el.addEventListener("lostpointercapture", onRelease);
7021
+ el.addEventListener("pointercancel", onRelease);
7022
+ el.addEventListener("pointerup", onRelease);
7023
+ callback();
7024
+ };
7025
+ el.addEventListener("pointerdown", onPointerDown);
7026
+ return () => {
7027
+ el.removeEventListener("pointerdown", onPointerDown);
7028
+ pressedElements.delete(el);
7029
+ };
7030
+ },
7031
+ test: (el) => pressedElements.has(el),
7032
+ },
6988
7033
  ":visited": {
6989
7034
  attribute: "data-visited",
6990
7035
  },
@@ -21402,7 +21447,8 @@ const useUIState = (uiStateController) => {
21402
21447
  return trackedUIState;
21403
21448
  };
21404
21449
 
21405
- installImportMetaCssBuild(import.meta);const css$r = /* css */`
21450
+ installImportMetaCssBuild(import.meta);/* eslint-disable jsenv/no-unknown-params */
21451
+ const css$r = /* css */`
21406
21452
  @layer navi {
21407
21453
  .navi_button {
21408
21454
  --button-outline-width: 1px;
@@ -21436,8 +21482,8 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
21436
21482
  black
21437
21483
  );
21438
21484
  --button-color-hover: var(--button-color);
21439
- /* Active */
21440
- --button-border-color-active: color-mix(
21485
+ /* Pressed */
21486
+ --button-border-color-pressed: color-mix(
21441
21487
  in srgb,
21442
21488
  var(--button-border-color) 90%,
21443
21489
  black
@@ -21463,6 +21509,11 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
21463
21509
  }
21464
21510
  }
21465
21511
 
21512
+ a.navi_button {
21513
+ color: inherit;
21514
+ text-decoration: none;
21515
+ }
21516
+
21466
21517
  .navi_button {
21467
21518
  /* Internal vars — prefixed with --x- to signal they are private, do not use from outside */
21468
21519
  --x-button-outline-width: var(--button-outline-width);
@@ -21487,6 +21538,9 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
21487
21538
  border-radius: var(--x-button-border-radius);
21488
21539
  outline: none;
21489
21540
  cursor: var(--x-button-cursor);
21541
+ -webkit-tap-highlight-color: transparent;
21542
+ touch-action: manipulation;
21543
+ user-select: none;
21490
21544
 
21491
21545
  &[data-icon] {
21492
21546
  --button-padding: 0;
@@ -21577,16 +21631,16 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
21577
21631
  --x-button-background-color: var(--button-background-color);
21578
21632
  --x-button-color: var(--button-color);
21579
21633
  }
21580
- /* Active */
21581
- &[data-active] {
21582
- --x-button-outline-color: var(--button-border-color-active);
21634
+ /* Pressed */
21635
+ &[data-pressed] {
21636
+ --x-button-outline-color: var(--button-border-color-pressed);
21583
21637
  }
21584
- &[data-active] {
21638
+ &[data-pressed] {
21585
21639
  .navi_button_content {
21586
21640
  transform: scale(0.9);
21587
21641
  }
21588
21642
  }
21589
- &[data-active] {
21643
+ &[data-pressed] {
21590
21644
  .navi_button_shadow {
21591
21645
  box-shadow:
21592
21646
  inset 0 3px 6px rgba(0, 0, 0, 0.2),
@@ -21622,7 +21676,7 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
21622
21676
 
21623
21677
  color: unset;
21624
21678
 
21625
- /* Remove active effects */
21679
+ /* Remove pressed effects */
21626
21680
  .navi_button_content {
21627
21681
  transform: none;
21628
21682
 
@@ -21658,11 +21712,40 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
21658
21712
  const Button = props => {
21659
21713
  import.meta.css = [css$r, "@jsenv/navi/src/field/button.jsx"];
21660
21714
  return renderActionableComponent(props, {
21661
- Basic: ButtonBasic,
21715
+ Basic: ButtonBasicDispatch,
21662
21716
  WithAction: ButtonWithAction,
21663
21717
  WithActionInsideForm: ButtonWithActionInsideForm
21664
21718
  });
21665
21719
  };
21720
+ const ButtonBasicDispatch = props => {
21721
+ if (props.route) {
21722
+ return jsx(ButtonWithRoute, {
21723
+ ...props
21724
+ });
21725
+ }
21726
+ return jsx(ButtonBasic, {
21727
+ ...props
21728
+ });
21729
+ };
21730
+ const ButtonWithRoute = ({
21731
+ route,
21732
+ routeParams,
21733
+ children,
21734
+ ...rest
21735
+ }) => {
21736
+ const url = route.buildUrl(routeParams);
21737
+ const {
21738
+ matching
21739
+ } = useRouteStatus(route);
21740
+ const paramsAreMatching = route.matchesParams(routeParams);
21741
+ const linkMatching = matching && paramsAreMatching;
21742
+ return jsx(ButtonBasic, {
21743
+ href: url,
21744
+ "data-href-current": linkMatching ? "" : undefined,
21745
+ ...rest,
21746
+ children: children || route.buildRelativeUrl(routeParams)
21747
+ });
21748
+ };
21666
21749
  const ButtonStyleCSSVars = {
21667
21750
  "outlineWidth": "--button-outline-width",
21668
21751
  "borderWidth": "--button-border-width",
@@ -21684,8 +21767,8 @@ const ButtonStyleCSSVars = {
21684
21767
  borderColor: "--button-border-color-hover",
21685
21768
  color: "--button-color-hover"
21686
21769
  },
21687
- ":active": {
21688
- borderColor: "--button-border-color-active"
21770
+ ":-navi-pressed": {
21771
+ borderColor: "--button-border-color-pressed"
21689
21772
  },
21690
21773
  ":read-only": {
21691
21774
  backgroundColor: "--button-background-color-readonly",
@@ -21698,7 +21781,7 @@ const ButtonStyleCSSVars = {
21698
21781
  color: "--button-color-disabled"
21699
21782
  }
21700
21783
  };
21701
- const ButtonPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
21784
+ const ButtonPseudoClasses = [":hover", ":active", ":-navi-pressed", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
21702
21785
  const ButtonPseudoElements = ["::-navi-loader"];
21703
21786
  const ButtonBasic = props => {
21704
21787
  const contextLoading = useContext(LoadingContext);
@@ -21710,6 +21793,10 @@ const ButtonBasic = props => {
21710
21793
  disabled,
21711
21794
  loading,
21712
21795
  autoFocus,
21796
+ // href/link
21797
+ href,
21798
+ target,
21799
+ rel,
21713
21800
  // visual
21714
21801
  icon,
21715
21802
  revealOnInteraction = icon,
@@ -21725,6 +21812,18 @@ const ButtonBasic = props => {
21725
21812
  const innerLoading = loading || contextLoading && contextLoadingElement === ref.current;
21726
21813
  const innerReadOnly = readOnly || contextReadOnly || innerLoading;
21727
21814
  const innerDisabled = disabled || contextDisabled;
21815
+ const isLink = href !== undefined;
21816
+ let as = "button";
21817
+ let innerTarget;
21818
+ let innerRel;
21819
+ if (isLink) {
21820
+ as = "a";
21821
+ const {
21822
+ isSameSite
21823
+ } = getHrefTargetInfo(href);
21824
+ innerTarget = target === undefined ? isSameSite ? undefined : "_blank" : target;
21825
+ innerRel = rel === undefined ? isSameSite ? undefined : "noopener noreferrer" : rel;
21826
+ }
21728
21827
  const renderButtonContent = buttonProps => {
21729
21828
  return jsxs(Text, {
21730
21829
  ...buttonProps,
@@ -21737,8 +21836,21 @@ const ButtonBasic = props => {
21737
21836
  return jsxs(Box, {
21738
21837
  "data-readonly-silent": innerLoading ? "" : undefined,
21739
21838
  ...remainingProps,
21740
- as: "button",
21839
+ as: as,
21840
+ href: href,
21841
+ target: innerTarget,
21842
+ rel: innerRel,
21741
21843
  ref: ref,
21844
+ onContextMenu: e => {
21845
+ if (e.pointerType === "touch") {
21846
+ // Suppress the native context menu triggered by long-press on touch devices.
21847
+ // Buttons have no meaningful context menu (no text to copy/paste/search),
21848
+ // and the long-press visual state would get stuck if we let the menu open.
21849
+ // Note: e.button === -1 is equivalent — it means no physical button triggered
21850
+ // the event, i.e. it was synthesized from a long-press gesture (right-click gives e.button === 2).
21851
+ e.preventDefault();
21852
+ }
21853
+ },
21742
21854
  "data-icon": icon ? "" : undefined,
21743
21855
  "data-reveal-on-interaction": revealOnInteraction ? "" : undefined,
21744
21856
  "data-discrete": discrete ? "" : undefined,
@@ -21801,7 +21913,7 @@ const ButtonWithAction = props => {
21801
21913
  onError: onActionError,
21802
21914
  onEnd: onActionEnd
21803
21915
  });
21804
- return jsx(ButtonBasic
21916
+ return jsx(ButtonBasicDispatch
21805
21917
  // put data-action first to help find it in devtools
21806
21918
  , {
21807
21919
  "data-action": boundAction.name,
@@ -21860,7 +21972,7 @@ const ButtonWithActionInsideForm = props => {
21860
21972
  }
21861
21973
  }
21862
21974
  });
21863
- return jsx(ButtonBasic, {
21975
+ return jsx(ButtonBasicDispatch, {
21864
21976
  "data-action": actionBoundToFormParams.name,
21865
21977
  ...rest,
21866
21978
  ref: ref,
@@ -22233,7 +22345,7 @@ const css$q = /* css */`
22233
22345
  --link-color: rgb(0, 0, 238);
22234
22346
  --link-color-visited: color-mix(in srgb, var(--link-color), black 40%);
22235
22347
 
22236
- --link-color-active: red;
22348
+ --link-color-pressed: red;
22237
22349
  --link-text-decoration: underline;
22238
22350
  --link-text-decoration-hover: var(--link-text-decoration);
22239
22351
  --link-cursor: pointer;
@@ -22268,7 +22380,7 @@ const css$q = /* css */`
22268
22380
  --x-link-color-hover: var(--link-color-hover, var(--link-color));
22269
22381
  --x-link-color-visited: var(--link-color-visited);
22270
22382
  --x-link-color-current: var(--link-color-current);
22271
- --x-link-color-active: var(--link-color-active);
22383
+ --x-link-color-pressed: var(--link-color-pressed);
22272
22384
  --x-link-text-decoration: var(--link-text-decoration);
22273
22385
  --x-link-text-decoration-hover: var(--link-text-decoration-hover);
22274
22386
  --x-link-cursor: var(--link-cursor);
@@ -22362,10 +22474,10 @@ const css$q = /* css */`
22362
22474
  &[data-focus-visible] {
22363
22475
  outline-width: 2px;
22364
22476
  }
22365
- /* Active */
22366
- &[data-active] {
22477
+ /* Pressed */
22478
+ &[data-pressed] {
22367
22479
  /* Redefine it otherwise [data-visited] prevails */
22368
- --x-link-color: var(--x-link-color-active);
22480
+ --x-link-color: var(--x-link-color-pressed);
22369
22481
  }
22370
22482
  /* Current */
22371
22483
  &[data-href-current] {
@@ -22508,8 +22620,8 @@ const LinkStyleCSSVars = {
22508
22620
  color: "--link-color-hover",
22509
22621
  textDecoration: "--link-text-decoration-hover"
22510
22622
  },
22511
- ":active": {
22512
- color: "--link-color-active"
22623
+ ":-navi-pressed": {
22624
+ color: "--link-color-pressed"
22513
22625
  },
22514
22626
  ":-navi-href-current": {
22515
22627
  background: "--link-background-current",
@@ -22522,7 +22634,7 @@ const LinkStyleCSSVars = {
22522
22634
  color: "--link-color-selected"
22523
22635
  }
22524
22636
  };
22525
- const LinkPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":visited", ":-navi-loading", ":-navi-href-internal", ":-navi-href-external", ":-navi-href-anchor", ":-navi-href-current", ":-navi-selected"];
22637
+ const LinkPseudoClasses = [":hover", ":active", ":-navi-pressed", ":focus", ":focus-visible", ":read-only", ":disabled", ":visited", ":-navi-loading", ":-navi-href-internal", ":-navi-href-external", ":-navi-href-anchor", ":-navi-href-current", ":-navi-selected"];
22526
22638
  const LinkPseudoElements = ["::-navi-loader", "::-navi-indicator"];
22527
22639
  Object.assign(PSEUDO_CLASSES, {
22528
22640
  ":-navi-href-internal": {
@@ -24860,20 +24972,20 @@ installImportMetaCssBuild(import.meta);const css$j = /* css */`
24860
24972
  --track-color-hover: color-mix(in srgb, var(--fill-color) 95%, black);
24861
24973
  --fill-color-hover: color-mix(in srgb, var(--fill-color) 80%, black);
24862
24974
  --thumb-color-hover: color-mix(in srgb, var(--thumb-color) 80%, black);
24863
- /* Active */
24864
- --border-color-active: color-mix(
24975
+ /* Pressed */
24976
+ --border-color-pressed: color-mix(
24865
24977
  in srgb,
24866
24978
  var(--border-color) 50%,
24867
24979
  transparent
24868
24980
  );
24869
- --track-border-color-active: var(--border-color-active);
24870
- --background-color-active: color-mix(
24981
+ --track-border-color-pressed: var(--border-color-pressed);
24982
+ --background-color-pressed: color-mix(
24871
24983
  in srgb,
24872
24984
  var(--background-color) 75%,
24873
24985
  white
24874
24986
  );
24875
- --fill-color-active: color-mix(in srgb, var(--fill-color) 75%, white);
24876
- --thumb-color-active: color-mix(in srgb, var(--thumb-color) 75%, white);
24987
+ --fill-color-pressed: color-mix(in srgb, var(--fill-color) 75%, white);
24988
+ --thumb-color-pressed: color-mix(in srgb, var(--thumb-color) 75%, white);
24877
24989
  /* Readonly */
24878
24990
  --border-color-readonly: color-mix(
24879
24991
  in srgb,
@@ -24991,13 +25103,13 @@ installImportMetaCssBuild(import.meta);const css$j = /* css */`
24991
25103
  --x-fill-color: var(--fill-color-hover);
24992
25104
  --x-thumb-color: var(--thumb-color-hover);
24993
25105
  }
24994
- /* Active */
24995
- &[data-active] {
24996
- --x-border-color: var(--border-color-active);
24997
- --x-track-border-color: var(--track-border-color-active);
24998
- --x-background-color: var(--background-color-active);
24999
- --x-fill-color: var(--fill-color-active);
25000
- --x-thumb-color: var(--thumb-color-active);
25106
+ /* Pressed */
25107
+ &[data-pressed] {
25108
+ --x-border-color: var(--border-color-pressed);
25109
+ --x-track-border-color: var(--track-border-color-pressed);
25110
+ --x-background-color: var(--background-color-pressed);
25111
+ --x-fill-color: var(--fill-color-pressed);
25112
+ --x-thumb-color: var(--thumb-color-pressed);
25001
25113
  }
25002
25114
  /* Focus */
25003
25115
  &[data-focus-visible] {
@@ -25061,11 +25173,11 @@ const RangeStyleCSSVars = {
25061
25173
  fillColor: "--fill-color-hover",
25062
25174
  thumbColor: "--thumb-color-hover"
25063
25175
  },
25064
- ":active": {
25176
+ ":-navi-pressed": {
25065
25177
  borderColor: "--border-color-hover",
25066
25178
  backgroundColor: "--background-color-hover",
25067
- fillColor: "--fill-color-active",
25068
- thumbColor: "--thumb-color-active"
25179
+ fillColor: "--fill-color-pressed",
25180
+ thumbColor: "--thumb-color-pressed"
25069
25181
  },
25070
25182
  ":read-only": {
25071
25183
  borderColor: "--border-color-readonly",
@@ -25080,7 +25192,7 @@ const RangeStyleCSSVars = {
25080
25192
  thumbColor: "--thumb-color-disabled"
25081
25193
  }
25082
25194
  };
25083
- const RangePseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
25195
+ const RangePseudoClasses = [":hover", ":active", ":-navi-pressed", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
25084
25196
  const RangePseudoElements = ["::-navi-loader"];
25085
25197
  const RangeChildPropSet = new Set([...fieldPropSet]);
25086
25198
  const InputRangeBasic = props => {