@planningcenter/topbar 12.4.1 → 12.5.0-qa-988.0

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/topbar.js CHANGED
@@ -7,16 +7,18 @@ var general = require('@planningcenter/icons/paths/general');
7
7
  var Jolt = require('@planningcenter/jolt-client');
8
8
  var shim = require('use-sync-external-store/shim');
9
9
  require('react/jsx-runtime');
10
+ var toolbar = require('@planningcenter/icons/paths/toolbar');
11
+ var datetimeFmt = require('@planningcenter/datetime-fmt');
12
+ var pluralize = require('pluralize');
13
+ var logomarks = require('@planningcenter/icons/paths/logomark');
10
14
  var tapestryReact = require('@planningcenter/tapestry-react');
11
15
  var addOns = require('@planningcenter/add-ons');
12
16
  var churchCenter = require('@planningcenter/icons/paths/church-center');
13
17
  var people = require('@planningcenter/icons/paths/people');
14
- var toolbar = require('@planningcenter/icons/paths/toolbar');
15
18
  var reactCalendly = require('react-calendly');
16
19
  var algoliasearch = require('algoliasearch');
17
20
  var reactInstantsearchCore = require('react-instantsearch-core');
18
21
  var reactTransitionGroup = require('react-transition-group');
19
- var datetimeFmt = require('@planningcenter/datetime-fmt');
20
22
 
21
23
  function _interopNamespaceDefault(e) {
22
24
  var n = Object.create(null);
@@ -37,11 +39,12 @@ function _interopNamespaceDefault(e) {
37
39
 
38
40
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
39
41
  var general__namespace = /*#__PURE__*/_interopNamespaceDefault(general);
42
+ var toolbar__namespace = /*#__PURE__*/_interopNamespaceDefault(toolbar);
43
+ var logomarks__namespace = /*#__PURE__*/_interopNamespaceDefault(logomarks);
40
44
  var churchCenter__namespace = /*#__PURE__*/_interopNamespaceDefault(churchCenter);
41
45
  var people__namespace = /*#__PURE__*/_interopNamespaceDefault(people);
42
- var toolbar__namespace = /*#__PURE__*/_interopNamespaceDefault(toolbar);
43
46
 
44
- var styles$m = {"accessibility-toolbar":"accessibility-toolbar-jgjUG"};
47
+ var styles$u = {"accessibility-toolbar":"accessibility-toolbar-jgjUG"};
45
48
 
46
49
  const AccessibilityToolbar = ({
47
50
  children
@@ -53,7 +56,7 @@ const AccessibilityToolbar = ({
53
56
  (_a = document.getElementById("main-content")) === null || _a === void 0 ? void 0 : _a.focus();
54
57
  };
55
58
  return /*#__PURE__*/React.createElement("div", {
56
- className: styles$m["accessibility-toolbar"]
59
+ className: styles$u["accessibility-toolbar"]
57
60
  }, /*#__PURE__*/React.createElement(tapestry.Link, {
58
61
  href: "#main-content",
59
62
  kind: "primary",
@@ -372,11 +375,11 @@ const X = ({
372
375
  fill: fill
373
376
  })));
374
377
 
375
- var styles$l = {"announcement":"announcement-pI5tM","announcement--platform":"announcement--platform-EcUn2","announcement--promo":"announcement--promo-FarUk","announcement-icon":"announcement-icon-Ov39-","announcement-content":"announcement-content-q2ad6","dismiss":"dismiss-wUAoU","dismiss--promo":"dismiss--promo-7zvO4"};
378
+ var styles$t = {"announcement":"announcement-pI5tM","announcement--platform":"announcement--platform-EcUn2","announcement--promo":"announcement--promo-FarUk","announcement-icon":"announcement-icon-Ov39-","announcement-content":"announcement-content-q2ad6","dismiss":"dismiss-wUAoU","dismiss--promo":"dismiss--promo-7zvO4"};
376
379
 
377
380
  function AnnouncementIcon() {
378
381
  return /*#__PURE__*/React.createElement("svg", {
379
- className: styles$l["announcement-icon"],
382
+ className: styles$t["announcement-icon"],
380
383
  width: "16",
381
384
  height: "16",
382
385
  viewBox: "0 0 16 16",
@@ -501,7 +504,7 @@ let StyledAnnouncement$1 = class StyledAnnouncement extends React.Component {
501
504
  } = this.props;
502
505
  const isPromo = variant === "promo";
503
506
  return /*#__PURE__*/React.createElement("div", {
504
- className: classnames(styles$l["announcement"], styles$l[`announcement--${variant !== null && variant !== void 0 ? variant : "platform"}`]),
507
+ className: classnames(styles$t["announcement"], styles$t[`announcement--${variant !== null && variant !== void 0 ? variant : "platform"}`]),
505
508
  "data-announcement-variant": variant !== null && variant !== void 0 ? variant : "platform",
506
509
  style: isPromo ? {
507
510
  backgroundImage: promoBackgroundUrl,
@@ -510,7 +513,7 @@ let StyledAnnouncement$1 = class StyledAnnouncement extends React.Component {
510
513
  backgroundSize: "cover"
511
514
  } : undefined
512
515
  }, !isPromo && /*#__PURE__*/React.createElement(AnnouncementIcon, null), /*#__PURE__*/React.createElement("div", {
513
- className: styles$l["announcement-content"],
516
+ className: styles$t["announcement-content"],
514
517
  style: style,
515
518
  ...platformProps
516
519
  }));
@@ -559,7 +562,7 @@ function StyledDismissButton$1({
559
562
  const isPromo = variant === "promo";
560
563
  return /*#__PURE__*/React.createElement("button", {
561
564
  type: "button",
562
- className: classnames(styles$l.dismiss, isPromo && styles$l["dismiss--promo"]),
565
+ className: classnames(styles$t.dismiss, isPromo && styles$t["dismiss--promo"]),
563
566
  ...props
564
567
  }, /*#__PURE__*/React.createElement(X, {
565
568
  fill: isPromo ? "currentColor" : "white",
@@ -639,9 +642,9 @@ class StyledAnnouncement extends React.Component {
639
642
  ...platformProps
640
643
  } = this.props;
641
644
  return /*#__PURE__*/React.createElement("div", {
642
- className: styles$l["announcement"]
645
+ className: styles$t["announcement"]
643
646
  }, /*#__PURE__*/React.createElement(AnnouncementIcon, null), /*#__PURE__*/React.createElement("div", {
644
- className: styles$l["announcement-content"],
647
+ className: styles$t["announcement-content"],
645
648
  style: style,
646
649
  ...platformProps
647
650
  }));
@@ -652,7 +655,7 @@ function StyledDismissButton({
652
655
  }) {
653
656
  return /*#__PURE__*/React.createElement("button", {
654
657
  type: "button",
655
- className: styles$l.dismiss,
658
+ className: styles$t.dismiss,
656
659
  ...props
657
660
  }, /*#__PURE__*/React.createElement(X, {
658
661
  fill: "white",
@@ -1774,7 +1777,7 @@ function MonoAppIcon({
1774
1777
  })) : (/*#__PURE__*/React.createElement("div", null, "appName not supported")));
1775
1778
  }
1776
1779
 
1777
- var styles$k = {"icon-slot":"icon-slot-m3ZIk","name":"name-UNqbW"};
1780
+ var styles$s = {"name":"name-UNqbW"};
1778
1781
 
1779
1782
  const AppRow = ({
1780
1783
  appName,
@@ -1782,25 +1785,23 @@ const AppRow = ({
1782
1785
  iconSize = 24
1783
1786
  }) => {
1784
1787
  if (appName === "Accounts") {
1785
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
1786
- className: styles$k["icon-slot"]
1787
- }, /*#__PURE__*/React.createElement(MonoAppIcon, {
1788
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(MonoAppIcon, {
1788
1789
  appName: "Accounts",
1789
1790
  colors: colors,
1790
1791
  size: iconSize
1791
- })), /*#__PURE__*/React.createElement("span", {
1792
- className: styles$k.name
1792
+ }), /*#__PURE__*/React.createElement("span", {
1793
+ className: styles$s.name
1793
1794
  }, "Account settings"));
1794
1795
  }
1795
1796
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorAppIcon, {
1796
1797
  appName: appName.replace(/[\s-]/, ""),
1797
1798
  size: iconSize
1798
1799
  }), /*#__PURE__*/React.createElement("span", {
1799
- className: styles$k.name
1800
+ className: styles$s.name
1800
1801
  }, appName));
1801
1802
  };
1802
1803
 
1803
- var styles$j = {"button":"button-XMbeQ","label":"label-884of","chevron":"chevron-RRg9k"};
1804
+ var styles$r = {"button":"button-XMbeQ","label":"label-884of","chevron":"chevron-RRg9k"};
1804
1805
 
1805
1806
  const AppsButton = /*#__PURE__*/React.forwardRef(({
1806
1807
  appName,
@@ -1812,27 +1813,27 @@ const AppsButton = /*#__PURE__*/React.forwardRef(({
1812
1813
  ...restProps,
1813
1814
  ref: ref,
1814
1815
  "aria-label": `App switcher: ${appName}`,
1815
- className: styles$j.button,
1816
+ className: styles$r.button,
1816
1817
  kind: "neutral-inline",
1817
1818
  label: /*#__PURE__*/React.createElement("span", {
1818
- className: styles$j.label
1819
+ className: styles$r.label
1819
1820
  }, isAccounts ? "Account settings" : appName),
1820
1821
  prefix: isAccounts ? (/*#__PURE__*/React.createElement(MonoAppIcon, {
1821
1822
  appName: "Accounts",
1822
1823
  colors: colors,
1823
- size: 22
1824
+ size: 24
1824
1825
  })) : (/*#__PURE__*/React.createElement(ColorAppIcon, {
1825
1826
  appName: appName.replace(/[\s-]/, ""),
1826
- size: 22
1827
+ size: 24
1827
1828
  })),
1828
1829
  suffix: /*#__PURE__*/React.createElement(DisclosureChevronIcon, {
1829
- className: `${styles$j.chevron} symbol`
1830
+ className: `${styles$r.chevron} symbol`
1830
1831
  })
1831
1832
  });
1832
1833
  });
1833
1834
  AppsButton.displayName = "AppsButton";
1834
1835
 
1835
- var styles$i = {"nav":"nav-y-6ML","popover-content":"popover-content-jOAAY","list":"list-jUxvp","link":"link-LMp2h","current":"current-4U4VL","accounts-item":"accounts-item-erJW0","accounts-link":"accounts-link-4jwPW"};
1836
+ var styles$q = {"nav":"nav-y-6ML","popover-content":"popover-content-jOAAY","list":"list-jUxvp","link":"link-LMp2h","current":"current-4U4VL","accounts-item":"accounts-item-erJW0","accounts-link":"accounts-link-4jwPW"};
1836
1837
 
1837
1838
  const AppsMenu = ({
1838
1839
  appName,
@@ -1853,8 +1854,8 @@ const AppsMenu = ({
1853
1854
  }, /*#__PURE__*/React.createElement("a", {
1854
1855
  "aria-current": isCurrent ? "page" : undefined,
1855
1856
  "aria-label": name,
1856
- className: classnames(styles$i.link, {
1857
- [styles$i.current]: isCurrent
1857
+ className: classnames(styles$q.link, {
1858
+ [styles$q.current]: isCurrent
1858
1859
  }),
1859
1860
  "data-pendo": `app-switcher--change-app--${name}`,
1860
1861
  "data-turbolinks": false,
@@ -1870,22 +1871,22 @@ const AppsMenu = ({
1870
1871
  colors: colors
1871
1872
  })), /*#__PURE__*/React.createElement(tapestry.PopoverContent, {
1872
1873
  "aria-label": "Switch app",
1873
- className: styles$i["popover-content"],
1874
+ className: styles$q["popover-content"],
1874
1875
  placement: "bottom start"
1875
1876
  }, /*#__PURE__*/React.createElement("nav", {
1876
- className: styles$i.nav,
1877
+ className: styles$q.nav,
1877
1878
  "data-pendo": "app-switcher"
1878
1879
  }, /*#__PURE__*/React.createElement("ul", {
1879
- className: styles$i.list,
1880
+ className: styles$q.list,
1880
1881
  role: "list"
1881
1882
  }, homeProduct && renderProductLink(homeProduct.name), restProducts.map(({
1882
1883
  name
1883
1884
  }) => renderProductLink(name)), accountsProduct && (/*#__PURE__*/React.createElement("li", {
1884
- className: styles$i["accounts-item"]
1885
+ className: styles$q["accounts-item"]
1885
1886
  }, /*#__PURE__*/React.createElement("a", {
1886
1887
  "aria-current": appName === accountsProduct.name ? "page" : undefined,
1887
1888
  "aria-label": "Account settings",
1888
- className: classnames(styles$i.link, styles$i["accounts-link"]),
1889
+ className: classnames(styles$q.link, styles$q["accounts-link"]),
1889
1890
  "data-pendo": "app-switcher--change-app--Accounts",
1890
1891
  "data-turbolinks": false,
1891
1892
  href: pcoUrl$1(env)("accounts") + getAppsSwitchProductPath(accountsProduct.name)
@@ -2093,7 +2094,7 @@ function MonoAppName({
2093
2094
  })) : (/*#__PURE__*/React.createElement("div", null, "appName not supported"));
2094
2095
  }
2095
2096
 
2096
- var styles$h = {"unbutton":"unbutton-lEbTR"};
2097
+ var styles$p = {"unbutton":"unbutton-lEbTR"};
2097
2098
 
2098
2099
  function Unbutton({
2099
2100
  className,
@@ -2102,7 +2103,7 @@ function Unbutton({
2102
2103
  ...nativeProps
2103
2104
  }) {
2104
2105
  return /*#__PURE__*/React.createElement("button", {
2105
- className: classnames(styles$h.unbutton, className),
2106
+ className: classnames(styles$p.unbutton, className),
2106
2107
  style: {
2107
2108
  ...style
2108
2109
  },
@@ -2111,7 +2112,7 @@ function Unbutton({
2111
2112
  });
2112
2113
  }
2113
2114
 
2114
- var styles$g = {"button":"button-wsipc","button-accounts":"button-accounts-zQmBM","chevron":"chevron-obyBF","is-expanded":"is-expanded-PoCQ9"};
2115
+ var styles$o = {"button":"button-wsipc","button-accounts":"button-accounts-zQmBM","chevron":"chevron-obyBF","is-expanded":"is-expanded-PoCQ9"};
2115
2116
 
2116
2117
  const LegacyAppsButton = ({
2117
2118
  appName,
@@ -2126,8 +2127,8 @@ const LegacyAppsButton = ({
2126
2127
  "aria-haspopup": "true",
2127
2128
  "aria-label": `App switcher: ${appName}`,
2128
2129
  onClick: onClick,
2129
- className: classnames(styles$g.button, {
2130
- [styles$g["is-expanded"]]: expanded
2130
+ className: classnames(styles$o.button, {
2131
+ [styles$o["is-expanded"]]: expanded
2131
2132
  }),
2132
2133
  type: "button",
2133
2134
  style: style,
@@ -2136,7 +2137,7 @@ const LegacyAppsButton = ({
2136
2137
  appName: "Accounts",
2137
2138
  colors: colors
2138
2139
  }), /*#__PURE__*/React.createElement("div", {
2139
- className: styles$g["button-accounts"]
2140
+ className: styles$o["button-accounts"]
2140
2141
  }, "Account settings"))) : (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorAppIcon, {
2141
2142
  appName: appName.replace(/[\s-]/, "")
2142
2143
  }), /*#__PURE__*/React.createElement(MonoAppName, {
@@ -2144,7 +2145,7 @@ const LegacyAppsButton = ({
2144
2145
  key: "mono-app-name",
2145
2146
  size: 24
2146
2147
  }))), /*#__PURE__*/React.createElement(DisclosureChevronIcon, {
2147
- className: styles$g.chevron,
2148
+ className: styles$o.chevron,
2148
2149
  key: "disclosure-chevron-icon"
2149
2150
  }));
2150
2151
  };
@@ -2277,7 +2278,7 @@ class Outsider extends React.Component {
2277
2278
  }
2278
2279
  }
2279
2280
 
2280
- var styles$f = {"popup-root":"popup-root-SeL5u","popup":"popup-nQXYW","is-visible":"is-visible-3DAUP"};
2281
+ var styles$n = {"popup-root":"popup-root-SeL5u","popup":"popup-nQXYW","is-visible":"is-visible-3DAUP"};
2281
2282
 
2282
2283
  const Popup = ({
2283
2284
  className,
@@ -2285,8 +2286,8 @@ const Popup = ({
2285
2286
  isVisible,
2286
2287
  ...nativeProps
2287
2288
  }) => (/*#__PURE__*/React.createElement(C, {
2288
- className: classnames(styles$f.popup, {
2289
- [styles$f["is-visible"]]: isVisible
2289
+ className: classnames(styles$n.popup, {
2290
+ [styles$n["is-visible"]]: isVisible
2290
2291
  }, className),
2291
2292
  ...nativeProps
2292
2293
  }));
@@ -2294,11 +2295,11 @@ const Popup = ({
2294
2295
  const PopupRoot = ({
2295
2296
  ...nativeProps
2296
2297
  }) => (/*#__PURE__*/React.createElement("div", {
2297
- className: styles$f["popup-root"],
2298
+ className: styles$n["popup-root"],
2298
2299
  ...nativeProps
2299
2300
  }));
2300
2301
 
2301
- var styles$e = {"popup":"popup-bVhSa"};
2302
+ var styles$m = {"popup":"popup-bVhSa"};
2302
2303
 
2303
2304
  const LegacyAppsMenu = ({
2304
2305
  appName,
@@ -2336,7 +2337,7 @@ const LegacyAppsMenu = ({
2336
2337
  cleanup: !visible,
2337
2338
  component: Outsider,
2338
2339
  onOutsideClick: toggle,
2339
- className: styles$e.popup,
2340
+ className: styles$m.popup,
2340
2341
  isVisible: visible
2341
2342
  }, /*#__PURE__*/React.createElement("menu", {
2342
2343
  ref: menuRef,
@@ -3246,37 +3247,140 @@ const useUpdateStore = () => React.useCallback(updates => {
3246
3247
  });
3247
3248
  }, []);
3248
3249
 
3250
+ const collections = {
3251
+ general: general__namespace,
3252
+ toolbar: toolbar__namespace
3253
+ };
3254
+ const paths = collections;
3255
+ function Icon({
3256
+ name,
3257
+ size = 16,
3258
+ style,
3259
+ theme,
3260
+ title,
3261
+ ...props
3262
+ }) {
3263
+ const [collection, symbol] = name.split(".");
3264
+ return /*#__PURE__*/React.createElement("svg", {
3265
+ "aria-hidden": title ? undefined : true,
3266
+ fill: "currentColor",
3267
+ height: size,
3268
+ role: title ? "img" : undefined,
3269
+ style: {
3270
+ color: theme && `var(${theme})`,
3271
+ flexShrink: 0,
3272
+ ...style
3273
+ },
3274
+ viewBox: "0 0 16 16",
3275
+ width: size,
3276
+ ...props
3277
+ }, title && /*#__PURE__*/React.createElement("title", null, title), /*#__PURE__*/React.createElement("path", {
3278
+ d: paths[collection][symbol]
3279
+ }));
3280
+ }
3281
+
3282
+ const SEARCHABLE_PRODUCTS = [{
3283
+ appName: "Calendar",
3284
+ slug: "calendar"
3285
+ }, {
3286
+ appName: "Check-Ins",
3287
+ slug: "check-ins"
3288
+ }, {
3289
+ appName: "Giving",
3290
+ slug: "giving"
3291
+ }, {
3292
+ appName: "Groups",
3293
+ slug: "groups"
3294
+ }, {
3295
+ appName: "People",
3296
+ slug: "people"
3297
+ }, {
3298
+ appName: "Publishing",
3299
+ slug: "publishing"
3300
+ }, {
3301
+ appName: "Registrations",
3302
+ slug: "registrations"
3303
+ }, {
3304
+ appName: "Services",
3305
+ slug: "services"
3306
+ }];
3307
+ const KEYBOARD_SHORTCUTS = {
3308
+ copyLink: {
3309
+ key: "c",
3310
+ label: "Copy link",
3311
+ modifierKey: true
3312
+ },
3313
+ openInNewTab: {
3314
+ label: "Open in new tab"},
3315
+ openSearch: {
3316
+ key: "k",
3317
+ label: "Open search",
3318
+ modifierKey: true
3319
+ },
3320
+ select: {
3321
+ label: "Select",
3322
+ modifierKey: false,
3323
+ next: "ArrowDown",
3324
+ previous: "ArrowUp"
3325
+ }
3326
+ };
3327
+
3249
3328
  const isMac = () => /Mac|iPhone|iPad|iPod/.test(navigator.platform);
3250
3329
  const hasCommandKey = event => isMac() ? event.metaKey : event.ctrlKey;
3251
- const commandKeyLabel = () => isMac() ? "⌘" : "Ctrl+";
3252
- const isSearchShortcut = event => event.key.toLowerCase() === "k" && !event.altKey && !event.shiftKey && hasCommandKey(event);
3330
+ const matchesShortcut = (shortcut, event) => event.key.toLowerCase() === shortcut.key && !event.altKey && !event.shiftKey && hasCommandKey(event) === shortcut.modifierKey;
3331
+ const isSearchShortcut = event => matchesShortcut(KEYBOARD_SHORTCUTS.openSearch, event);
3253
3332
  // Products opened their own search with `/` before this one replaced it.
3254
3333
  const isLegacySearchShortcut = event => event.key === "/" && !event.altKey && !event.ctrlKey && !event.metaKey && !isTypingIn(event.target);
3255
- const isCopyShortcut = event => event.key.toLowerCase() === "c" && !event.altKey && !event.shiftKey && hasCommandKey(event);
3334
+ const isCopyShortcut = event => matchesShortcut(KEYBOARD_SHORTCUTS.copyLink, event);
3256
3335
  const isTypingIn = target => target instanceof Element && target.closest('input, select, textarea, [contenteditable]:not([contenteditable="false"])') !== null;
3257
3336
  const isTypingKey = event => event.key.length === 1 && event.key !== " " && !event.altKey && !event.ctrlKey && !event.metaKey;
3258
3337
  const verticalStep = key => ({
3259
- ArrowDown: 1,
3260
- ArrowUp: -1
3338
+ [KEYBOARD_SHORTCUTS.select.next]: 1,
3339
+ [KEYBOARD_SHORTCUTS.select.previous]: -1
3261
3340
  })[key];
3262
3341
  const horizontalStep = key => ({
3263
3342
  ArrowLeft: -1,
3264
3343
  ArrowRight: 1
3265
3344
  })[key];
3266
3345
 
3346
+ var styles$l = {"searchButton":"searchButton-fYa5-"};
3347
+
3267
3348
  function SearchButton({
3349
+ mobile = false,
3268
3350
  onClick
3269
3351
  }) {
3270
3352
  return /*#__PURE__*/React.createElement("button", {
3271
- "aria-keyshortcuts": `${isMac() ? "Meta+K" : "Control+K"} /`,
3353
+ "aria-keyshortcuts": mobile ? undefined : `${isMac() ? "Meta" : "Control"}+${KEYBOARD_SHORTCUTS.openSearch.key.toUpperCase()} /`,
3272
3354
  "aria-label": "Search",
3355
+ className: styles$l.searchButton,
3356
+ "data-search-button": true,
3273
3357
  onClick: onClick,
3274
3358
  type: "button"
3275
- }, /*#__PURE__*/React.createElement(Spyglass, {
3276
- fill: "currentColor"
3359
+ }, /*#__PURE__*/React.createElement(Icon, {
3360
+ name: "general.search",
3361
+ size: mobile ? 18 : 14
3277
3362
  }));
3278
3363
  }
3279
3364
 
3365
+ // With the search's own debounce, about 1.4 seconds after the last keystroke,
3366
+ // as in GOV.UK's accessible-autocomplete.
3367
+ const ANNOUNCEMENT_DELAY_MS = 1100;
3368
+ // Screen readers echo typing themselves, as each person has set them to, so
3369
+ // the message waits until typing settles instead of talking over it. Waiting
3370
+ // also lets VoiceOver finish what focus had to say, since it often skips a
3371
+ // change made as focus moves, as when a tab with cached results is selected,
3372
+ // and only the tab someone stops on when arrowing through them is announced.
3373
+ // The region empties at once, so a message that comes back is read again.
3374
+ function useAnnouncement(message) {
3375
+ const [announcement, setAnnouncement] = React.useState(null);
3376
+ React.useEffect(() => {
3377
+ setAnnouncement(null);
3378
+ const timeout = setTimeout(() => setAnnouncement(message), ANNOUNCEMENT_DELAY_MS);
3379
+ return () => clearTimeout(timeout);
3380
+ }, [message]);
3381
+ return announcement;
3382
+ }
3383
+
3280
3384
  // useId isn't available on React 17, which our peer range still supports.
3281
3385
  let instanceCount$1 = 0;
3282
3386
  function useInstanceId(prefix) {
@@ -3546,7 +3650,7 @@ const store = createStore(getAllPcoMeta());
3546
3650
  const recentlyVisitableMetadataStore = createStore({
3547
3651
  metadata: getRecentlyVisitableMetadata()
3548
3652
  });
3549
- function sync() {
3653
+ function sync$1() {
3550
3654
  const nextState = getAllPcoMeta();
3551
3655
  if (!shallowCompare(store.getState(), nextState)) store.setState(nextState);
3552
3656
  const metadata = getRecentlyVisitableMetadata();
@@ -3556,7 +3660,7 @@ function sync() {
3556
3660
  });
3557
3661
  }
3558
3662
  }
3559
- const observer = new MutationObserver(sync);
3663
+ const observer = new MutationObserver(sync$1);
3560
3664
  let hasTriggeredObserve = false;
3561
3665
  function observe() {
3562
3666
  if (hasTriggeredObserve) return;
@@ -3567,7 +3671,7 @@ function observe() {
3567
3671
  // never mutate afterward, so the observer alone would never catch them.
3568
3672
  // Re-read once now, since observe() is only called once a consumer is
3569
3673
  // actually mounting, which is always after the document has fully parsed.
3570
- sync();
3674
+ sync$1();
3571
3675
  observer.observe(document.head, {
3572
3676
  attributes: true,
3573
3677
  childList: true,
@@ -3583,21 +3687,19 @@ function useRecentlyVisitableMetadata() {
3583
3687
  return shim.useSyncExternalStore(recentlyVisitableMetadataStore.subscribe, () => recentlyVisitableMetadataStore.getState().metadata);
3584
3688
  }
3585
3689
 
3586
- // Entries match the ones home-mobile stores, so one list can sync across web
3587
- // and mobile.
3588
- const ENTRY_VERSION = 3;
3589
3690
  const MAX_ENTRIES = 50;
3691
+ const MAX_ENTRY_BYTES = 1024;
3590
3692
  const MAX_TEXT_LENGTH = 200;
3591
- const PRODUCTS = ["accounts", "calendar", "check-ins", "giving", "groups", "home", "login", "people", "publishing", "registrations", "services"];
3693
+ const PRODUCTS$1 = ["accounts", "calendar", "check-ins", "giving", "groups", "home", "login", "people", "publishing", "registrations", "services"];
3592
3694
  // Login has no pages worth returning to.
3593
- const APPS = PRODUCTS.filter(product => product !== "login");
3695
+ const APPS = PRODUCTS$1.filter(product => product !== "login");
3594
3696
  function isId(value) {
3595
3697
  return value !== "" && Array.from(value).every(character => character >= "0" && character <= "9");
3596
3698
  }
3597
3699
  // A PCRL looks like `<product>/v2/<resource_type>/<id>`.
3598
3700
  function isPcrl(value) {
3599
3701
  const segments = value.split("/");
3600
- return segments.length === 4 && PRODUCTS.some(product => product === segments[0]) && isId(segments[3]);
3702
+ return segments.length === 4 && PRODUCTS$1.some(product => product === segments[0]) && isId(segments[3]);
3601
3703
  }
3602
3704
  function isApp(value) {
3603
3705
  return APPS.some(app => app === value);
@@ -3633,8 +3735,8 @@ function entryKey(entry) {
3633
3735
  return `page:${entry.app}:${entry.path.split("?")[0]}`;
3634
3736
  }
3635
3737
  }
3636
- function isEntry(value) {
3637
- if (!isRecord(value) || value.version !== ENTRY_VERSION || typeof value.visitedAt !== "string") {
3738
+ function hasEntryShape(value) {
3739
+ if (!isRecord(value) || typeof value.visitedAt !== "string") {
3638
3740
  return false;
3639
3741
  } else if (value.type === "resource") {
3640
3742
  return typeof value.pcrl === "string" && isPcrl(value.pcrl);
@@ -3644,15 +3746,38 @@ function isEntry(value) {
3644
3746
  return false;
3645
3747
  }
3646
3748
  }
3749
+ function utf8Length(value) {
3750
+ return Array.from(value).reduce((length, character) => {
3751
+ var _a;
3752
+ const codePoint = (_a = character.codePointAt(0)) !== null && _a !== void 0 ? _a : 0;
3753
+ if (codePoint < 0x80) {
3754
+ return length + 1;
3755
+ } else if (codePoint < 0x800) {
3756
+ return length + 2;
3757
+ } else if (codePoint < 0x10000) {
3758
+ return length + 3;
3759
+ } else {
3760
+ return length + 4;
3761
+ }
3762
+ }, 0);
3763
+ }
3764
+ function excessBytes(entry) {
3765
+ return utf8Length(JSON.stringify(entry)) - MAX_ENTRY_BYTES;
3766
+ }
3767
+ // user-store-sync rejects a whole write over one entry above its size limit,
3768
+ // so an entry that can't fit isn't one this list can hold.
3769
+ function isEntry(value) {
3770
+ return hasEntryShape(value) && excessBytes(value) <= 0;
3771
+ }
3647
3772
  // Cuts on code points so a surrogate pair is never split.
3648
3773
  function clampText(value) {
3649
3774
  return Array.from(value).slice(0, MAX_TEXT_LENGTH).join("");
3650
3775
  }
3651
- function clampMetadata({
3776
+ function metadataFrom({
3652
3777
  details,
3653
3778
  type
3654
3779
  }) {
3655
- return {
3780
+ const metadata = {
3656
3781
  ...(details && {
3657
3782
  details: clampText(details)
3658
3783
  }),
@@ -3660,39 +3785,124 @@ function clampMetadata({
3660
3785
  type: clampText(type)
3661
3786
  })
3662
3787
  };
3788
+ return Object.keys(metadata).length > 0 ? {
3789
+ metadata
3790
+ } : {};
3791
+ }
3792
+ function pageEntry({
3793
+ app,
3794
+ path,
3795
+ visitedAt
3796
+ }, {
3797
+ details,
3798
+ title,
3799
+ type
3800
+ }) {
3801
+ return {
3802
+ app,
3803
+ ...metadataFrom({
3804
+ details,
3805
+ type
3806
+ }),
3807
+ path,
3808
+ title: clampText(title),
3809
+ type: "page",
3810
+ visitedAt
3811
+ };
3812
+ }
3813
+ function texts(entry) {
3814
+ var _a, _b, _c, _d;
3815
+ return {
3816
+ details: (_b = (_a = entry.metadata) === null || _a === void 0 ? void 0 : _a.details) !== null && _b !== void 0 ? _b : "",
3817
+ title: entry.title,
3818
+ type: (_d = (_c = entry.metadata) === null || _c === void 0 ? void 0 : _c.type) !== null && _d !== void 0 ? _d : ""
3819
+ };
3820
+ }
3821
+ function jsonBytes(value) {
3822
+ return utf8Length(JSON.stringify(value)) - 2;
3663
3823
  }
3664
- function clampVisit(visit) {
3665
- if (visit.type === "resource") {
3666
- return visit;
3824
+ function longestText(entry) {
3825
+ return Object.entries(texts(entry)).reduce((longest, candidate) => jsonBytes(candidate[1]) > jsonBytes(longest[1]) ? candidate : longest);
3826
+ }
3827
+ // Takes whole characters off the end until at least `excess` bytes are gone,
3828
+ // so a surrogate pair is never split.
3829
+ function shortenBy(value, excess, minLength) {
3830
+ var _a;
3831
+ const characters = Array.from(value);
3832
+ let removed = 0;
3833
+ while (characters.length > minLength && removed < excess) {
3834
+ removed += jsonBytes((_a = characters.pop()) !== null && _a !== void 0 ? _a : "");
3835
+ }
3836
+ return characters.join("");
3837
+ }
3838
+ // Trims the longest text field by the overflow, repeating until the entry
3839
+ // fits or the title is down to one character.
3840
+ function trimTexts(entry) {
3841
+ const excess = excessBytes(entry);
3842
+ const [field, value] = longestText(entry);
3843
+ const shortened = shortenBy(value, excess, field === "title" ? 1 : 0);
3844
+ if (excess <= 0 || shortened === value) {
3845
+ return entry;
3667
3846
  } else {
3668
- return {
3669
- ...visit,
3670
- ...(visit.metadata && {
3671
- metadata: clampMetadata(visit.metadata)
3672
- }),
3673
- title: clampText(visit.title.trim())
3674
- };
3847
+ return trimTexts(pageEntry(entry, {
3848
+ ...texts(entry),
3849
+ [field]: shortened
3850
+ }));
3851
+ }
3852
+ }
3853
+ // The query string is the first thing to go, since it's not part of the
3854
+ // page's identity; what's left is trimmed to fit under the service's limit.
3855
+ function fitPage(entry) {
3856
+ if (excessBytes(entry) <= 0) {
3857
+ return entry;
3858
+ } else {
3859
+ return trimTexts({
3860
+ ...entry,
3861
+ path: entry.path.split("?")[0]
3862
+ });
3675
3863
  }
3676
3864
  }
3677
3865
  function toEntry(visit, visitedAt) {
3678
- return {
3679
- ...clampVisit(visit),
3680
- version: ENTRY_VERSION,
3866
+ const entry = {
3867
+ ...visit,
3681
3868
  visitedAt: visitedAt.toISOString()
3682
3869
  };
3870
+ if (entry.type === "resource") {
3871
+ return entry;
3872
+ } else {
3873
+ return fitPage(pageEntry(entry, {
3874
+ ...texts(entry),
3875
+ title: entry.title.trim()
3876
+ }));
3877
+ }
3878
+ }
3879
+ // user-store-sync rejects a whole write over one field it doesn't know, so
3880
+ // anything else an entry carries (like the version older entries stored) is
3881
+ // dropped on the way in.
3882
+ function withKnownFields(entry) {
3883
+ if (entry.type === "resource") {
3884
+ return {
3885
+ pcrl: entry.pcrl,
3886
+ type: entry.type,
3887
+ visitedAt: entry.visitedAt
3888
+ };
3889
+ } else {
3890
+ return pageEntry(entry, texts(entry));
3891
+ }
3683
3892
  }
3684
3893
  // Recents are disposable: anything unexpected reads as an empty list (or, for
3685
3894
  // a single bad entry, a list without it) rather than throwing.
3895
+ function entriesFrom(value) {
3896
+ if (Array.isArray(value)) {
3897
+ return value.filter(isEntry).map(withKnownFields);
3898
+ } else {
3899
+ return [];
3900
+ }
3901
+ }
3686
3902
  function parseRecentlyVisited(value) {
3687
- let parsed = null;
3688
3903
  try {
3689
- parsed = JSON.parse(value !== null && value !== void 0 ? value : "null");
3904
+ return entriesFrom(JSON.parse(value !== null && value !== void 0 ? value : "null"));
3690
3905
  } catch {
3691
- parsed = null;
3692
- }
3693
- if (Array.isArray(parsed)) {
3694
- return parsed.filter(isEntry);
3695
- } else {
3696
3906
  return [];
3697
3907
  }
3698
3908
  }
@@ -3700,6 +3910,39 @@ function addVisit(entries, entry) {
3700
3910
  const key = entryKey(entry);
3701
3911
  return [entry, ...entries.filter(existing => entryKey(existing) !== key)].slice(0, MAX_ENTRIES);
3702
3912
  }
3913
+ // The service may write timestamps with fewer fractional digits than
3914
+ // toISOString, so they're compared as times rather than strings.
3915
+ function visitTime(entry) {
3916
+ return isRecord(entry) && typeof entry.visitedAt === "string" ? Date.parse(entry.visitedAt) || 0 : 0;
3917
+ }
3918
+ function newestFirst(entries) {
3919
+ const seen = new Set();
3920
+ return entries.sort((a, b) => visitTime(b) - visitTime(a)).filter(entry => {
3921
+ if (isEntry(entry)) {
3922
+ const key = entryKey(entry);
3923
+ const isFirst = !seen.has(key);
3924
+ seen.add(key);
3925
+ return isFirst;
3926
+ } else {
3927
+ return true;
3928
+ }
3929
+ }).slice(0, MAX_ENTRIES);
3930
+ }
3931
+ // One list from several, newest visit first wherever it was recorded.
3932
+ function mergeEntries(...lists) {
3933
+ return newestFirst(lists.flat());
3934
+ }
3935
+ // Products pin different topbar versions, so the shared list can hold entries
3936
+ // this build doesn't recognize (a newer app or type). They're kept, as stored,
3937
+ // in what's written back, so an older topbar never erases a newer client's
3938
+ // visits. Recognized entries lose unknown fields, as on any read, since one
3939
+ // unknown field would get every write rejected.
3940
+ function mergeStored(stored, local) {
3941
+ return newestFirst([...(Array.isArray(stored) ? stored : []).map(entry => isEntry(entry) ? withKnownFields(entry) : entry), ...local]);
3942
+ }
3943
+ function isSameList(a, b) {
3944
+ return a.length === b.length && a.every((entry, index) => entryKey(entry) === entryKey(b[index]) && visitTime(entry) === visitTime(b[index]));
3945
+ }
3703
3946
 
3704
3947
  // The app whose URL, in this environment, has the current page's host.
3705
3948
  // Reversing pcoUrl handles every environment @planningcenter/url knows about,
@@ -3810,9 +4053,195 @@ function useCurrentPersonId() {
3810
4053
  return userId == null ? undefined : String(userId);
3811
4054
  }
3812
4055
 
3813
- // Per-origin localStorage is a stopgap: each product keeps its own list until
3814
- // PCA-409 moves this to storage shared across product subdomains. Only this
3815
- // file should need to change when it does.
4056
+ // Tokens last 15 minutes. Refreshing a minute early keeps one from expiring
4057
+ // between reading a token and the service checking it.
4058
+ const REFRESH_MARGIN_MS = 60000;
4059
+ // A failed mint (a CSRF 422, a 5xx, a body that isn't a token) isn't retried
4060
+ // on every visit and panel open; the product is left alone for a while.
4061
+ const MINT_BACKOFF_MS = 5 * 60000;
4062
+ const MAX_ATTEMPTS = 3;
4063
+ // A product without the endpoint answers 404 for the rest of the session, so
4064
+ // it's asked once per tab rather than on every page.
4065
+ const UNAVAILABLE_UNTIL_KEY = "topbar.user_store_sync.unavailable_until";
4066
+ const END_OF_SESSION = Number.MAX_SAFE_INTEGER;
4067
+ // Per person, so switching connected people never writes one person's visits
4068
+ // with another's token.
4069
+ function tokenKey(personId) {
4070
+ return `topbar.user_store_sync.token.${personId}`;
4071
+ }
4072
+ function readSession(key) {
4073
+ try {
4074
+ return sessionStorage.getItem(key);
4075
+ } catch {
4076
+ return null;
4077
+ }
4078
+ }
4079
+ function writeSession(key, value) {
4080
+ try {
4081
+ sessionStorage.setItem(key, value);
4082
+ } catch {
4083
+ // Without sessionStorage the next request just mints again.
4084
+ }
4085
+ }
4086
+ function isUserStoreSyncUnavailable() {
4087
+ return Number(readSession(UNAVAILABLE_UNTIL_KEY)) > Date.now();
4088
+ }
4089
+ function markUnavailable(until) {
4090
+ writeSession(UNAVAILABLE_UNTIL_KEY, String(until));
4091
+ }
4092
+ function isToken(value) {
4093
+ return isRecord(value) && typeof value.token === "string" && typeof value.url === "string" && Number.isFinite(value.expiresAt) && typeof value.readOnly === "boolean";
4094
+ }
4095
+ function cachedToken(personId) {
4096
+ var _a;
4097
+ try {
4098
+ const token = JSON.parse((_a = readSession(tokenKey(personId))) !== null && _a !== void 0 ? _a : "null");
4099
+ if (isToken(token) && token.expiresAt - REFRESH_MARGIN_MS > Date.now()) {
4100
+ return token;
4101
+ } else {
4102
+ return null;
4103
+ }
4104
+ } catch {
4105
+ return null;
4106
+ }
4107
+ }
4108
+ function tokenFrom(json) {
4109
+ if (isRecord(json)) {
4110
+ const token = {
4111
+ expiresAt: typeof json.expires_at === "string" ? Date.parse(json.expires_at) : NaN,
4112
+ readOnly: json.read_only === true,
4113
+ token: json.token,
4114
+ url: json.url
4115
+ };
4116
+ return isToken(token) ? token : null;
4117
+ } else {
4118
+ return null;
4119
+ }
4120
+ }
4121
+ // The JWT's subject is the person's account center id, the same id the
4122
+ // product gives the topbar as `userId`.
4123
+ function subject(token) {
4124
+ var _a;
4125
+ try {
4126
+ const payload = ((_a = token.split(".")[1]) !== null && _a !== void 0 ? _a : "").split("-").join("+").split("_").join("/");
4127
+ const claims = JSON.parse(atob(payload));
4128
+ return isRecord(claims) ? claims.sub : undefined;
4129
+ } catch {
4130
+ return undefined;
4131
+ }
4132
+ }
4133
+ async function mintToken(personId) {
4134
+ const {
4135
+ json,
4136
+ ok,
4137
+ response
4138
+ } = await apiRequest(railsCsrfFetch, `${window.location.origin}/user_store_sync/token`, {
4139
+ method: "POST"
4140
+ });
4141
+ const minted = ok ? tokenFrom(json) : null;
4142
+ // The product mints for whoever the session belongs to now. In a tab left
4143
+ // open after switching to another connected person, that isn't the person
4144
+ // this page rendered for, and syncing with their token would write this
4145
+ // person's visits into their list. The endpoint is working, so there's
4146
+ // nothing to back off from; the next page load picks up the new person.
4147
+ const token = minted && subject(minted.token) === personId ? minted : null;
4148
+ if (token) {
4149
+ writeSession(tokenKey(personId), JSON.stringify(token));
4150
+ } else if ((response === null || response === void 0 ? void 0 : response.status) === 404) {
4151
+ markUnavailable(END_OF_SESSION);
4152
+ } else if (!minted) {
4153
+ markUnavailable(Date.now() + MINT_BACKOFF_MS);
4154
+ }
4155
+ return token;
4156
+ }
4157
+ function hasReadOnlyToken(personId) {
4158
+ var _a;
4159
+ return ((_a = cachedToken(personId)) === null || _a === void 0 ? void 0 : _a.readOnly) === true;
4160
+ }
4161
+ async function request(personId, key, init = {}, isRetry = false) {
4162
+ var _a;
4163
+ const token = isRetry ? await mintToken(personId) : (_a = cachedToken(personId)) !== null && _a !== void 0 ? _a : await mintToken(personId);
4164
+ if (token) {
4165
+ const response = await fetch(`${token.url}/v1/data/${key}`, {
4166
+ ...init,
4167
+ headers: {
4168
+ ...init.headers,
4169
+ Authorization: `Bearer ${token.token}`
4170
+ }
4171
+ });
4172
+ if (response.status === 401 && !isRetry) {
4173
+ return request(personId, key, init, true);
4174
+ } else {
4175
+ return {
4176
+ response,
4177
+ token
4178
+ };
4179
+ }
4180
+ } else {
4181
+ return null;
4182
+ }
4183
+ }
4184
+ // The service answers version 0 for a person with nothing stored yet, and
4185
+ // takes `If-Match: "0"` for the first write. Without a version at all, the
4186
+ // write goes unconditioned.
4187
+ function ifMatch(version) {
4188
+ return typeof version === "number" ? {
4189
+ "If-Match": `"${version}"`
4190
+ } : {};
4191
+ }
4192
+ // Applies `change` to the stored value and writes the result, rereading and
4193
+ // retrying when another tab or device wrote in between. `change` returns null
4194
+ // when there's nothing to write. A read-only token (staff impersonating
4195
+ // someone) only reads, so nothing is written into the person's history.
4196
+ // Resolves to the value now stored, with whether the token was read-only, or
4197
+ // null when the service couldn't be reached.
4198
+ async function updateStoredValue(personId, key, change, attemptsLeft = MAX_ATTEMPTS) {
4199
+ const read = await request(personId, key);
4200
+ if (read === null || read === void 0 ? void 0 : read.response.ok) {
4201
+ const {
4202
+ value,
4203
+ version
4204
+ } = await read.response.json();
4205
+ const {
4206
+ readOnly
4207
+ } = read.token;
4208
+ const next = readOnly ? null : change(value);
4209
+ if (next === null) {
4210
+ return {
4211
+ readOnly,
4212
+ value: Array.isArray(value) ? value : []
4213
+ };
4214
+ } else {
4215
+ const write = await request(personId, key, {
4216
+ body: JSON.stringify({
4217
+ value: next
4218
+ }),
4219
+ headers: {
4220
+ "Content-Type": "application/json",
4221
+ ...ifMatch(version)
4222
+ },
4223
+ method: "PUT"
4224
+ });
4225
+ if (write === null || write === void 0 ? void 0 : write.response.ok) {
4226
+ return {
4227
+ readOnly,
4228
+ value: next
4229
+ };
4230
+ } else if ((write === null || write === void 0 ? void 0 : write.response.status) === 409 && attemptsLeft > 1) {
4231
+ return updateStoredValue(personId, key, change, attemptsLeft - 1);
4232
+ } else {
4233
+ return null;
4234
+ }
4235
+ }
4236
+ } else {
4237
+ return null;
4238
+ }
4239
+ }
4240
+
4241
+ // Each product keeps its own copy in localStorage, and user-store-sync joins
4242
+ // the copies up across products and devices wherever the product can mint a
4243
+ // token for it.
4244
+ const SYNC_KEY = "recently_viewed";
3816
4245
  function storageKey({
3817
4246
  env,
3818
4247
  personId
@@ -3831,17 +4260,65 @@ function readRecentlyVisited(scope) {
3831
4260
  return [];
3832
4261
  }
3833
4262
  }
4263
+ function writeRecentlyVisited(scope, entries) {
4264
+ try {
4265
+ localStorage.setItem(storageKey(scope), JSON.stringify(entries));
4266
+ changes.setState({
4267
+ version: changes.getState().version + 1
4268
+ });
4269
+ } catch {
4270
+ // Storage can be full or blocked; recents are disposable.
4271
+ }
4272
+ }
4273
+ async function syncOnce(scope) {
4274
+ try {
4275
+ const synced = await updateStoredValue(scope.personId, SYNC_KEY, stored => {
4276
+ const shared = entriesFrom(stored);
4277
+ const local = readRecentlyVisited(scope);
4278
+ return isSameList(mergeEntries(shared, local), shared) ? null : mergeStored(stored, local);
4279
+ });
4280
+ if (synced) {
4281
+ const shared = entriesFrom(synced.value);
4282
+ writeRecentlyVisited(scope, synced.readOnly ? shared : mergeEntries(shared, readRecentlyVisited(scope)));
4283
+ }
4284
+ } catch {
4285
+ // The service is best-effort; the local copy stands on its own.
4286
+ }
4287
+ }
4288
+ const syncing = new Map();
4289
+ const syncAgain = new Set();
4290
+ // One sync per list at a time. A visit recorded while one runs schedules a
4291
+ // single follow-up, so it still reaches the service; anything else asking
4292
+ // mid-sync just waits for the one running.
4293
+ function sync(scope, followUp) {
4294
+ const key = storageKey(scope);
4295
+ const running = syncing.get(key);
4296
+ if (isUserStoreSyncUnavailable()) {
4297
+ return Promise.resolve();
4298
+ } else if (running) {
4299
+ if (followUp) syncAgain.add(key);
4300
+ return running;
4301
+ } else {
4302
+ const run = syncOnce(scope).then(() => {
4303
+ syncing.delete(key);
4304
+ return syncAgain.delete(key) ? sync(scope, false) : undefined;
4305
+ });
4306
+ syncing.set(key, run);
4307
+ return run;
4308
+ }
4309
+ }
4310
+ function syncRecentlyVisited(scope) {
4311
+ return sync(scope, false);
4312
+ }
4313
+ // Staff impersonating someone get a read-only token, and their visits stay out
4314
+ // of that person's list. Until the token is minted the visit is kept, and the
4315
+ // sync that mints it replaces the local list with the synced one, so recording
4316
+ // never waits on the network.
3834
4317
  function recordVisit(visit, scope) {
3835
4318
  const entry = toEntry(visit, new Date());
3836
- if (isEntry(entry)) {
3837
- try {
3838
- localStorage.setItem(storageKey(scope), JSON.stringify(addVisit(readRecentlyVisited(scope), entry)));
3839
- changes.setState({
3840
- version: changes.getState().version + 1
3841
- });
3842
- } catch {
3843
- // Storage can be full or blocked; recents are disposable.
3844
- }
4319
+ if (isEntry(entry) && !hasReadOnlyToken(scope.personId)) {
4320
+ writeRecentlyVisited(scope, addVisit(readRecentlyVisited(scope), entry));
4321
+ sync(scope, true);
3845
4322
  }
3846
4323
  }
3847
4324
  function useRecentlyVisited({
@@ -3849,6 +4326,14 @@ function useRecentlyVisited({
3849
4326
  personId
3850
4327
  }) {
3851
4328
  const version = shim.useSyncExternalStore(changes.subscribe, () => changes.getState().version);
4329
+ React.useEffect(() => {
4330
+ if (personId) {
4331
+ syncRecentlyVisited({
4332
+ env,
4333
+ personId
4334
+ });
4335
+ }
4336
+ }, [env, personId]);
3852
4337
  // `version` isn't read, but listing it re-reads storage after each visit.
3853
4338
  return React.useMemo(() => personId ? readRecentlyVisited({
3854
4339
  env,
@@ -3996,7 +4481,13 @@ function hasSelectedText(element) {
3996
4481
  return selectedInField || ((_b = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "") !== "";
3997
4482
  }
3998
4483
 
3999
- const COPIED_FEEDBACK_MS = 1500;
4484
+ // eslint-disable-next-line sort-keys-fix/sort-keys-fix
4485
+ const COPIED_TIMING = {
4486
+ enter: 240,
4487
+ active: 1000,
4488
+ exit: 240
4489
+ };
4490
+ const COPIED_FEEDBACK_MS = COPIED_TIMING.enter + COPIED_TIMING.active + COPIED_TIMING.exit;
4000
4491
  // `copiedUrl` stays set briefly after a copy so the UI can confirm it.
4001
4492
  function useCopyLink() {
4002
4493
  const [copiedUrl, setCopiedUrl] = React.useState(null);
@@ -4017,25 +4508,46 @@ function useCopyLink() {
4017
4508
  };
4018
4509
  }
4019
4510
 
4511
+ function indexOf(highlight, items, list) {
4512
+ const pinnedIndex = items.findIndex(({
4513
+ key
4514
+ }) => key === highlight.key);
4515
+ if (highlight.list !== list) {
4516
+ return 0;
4517
+ } else if (pinnedIndex >= 0) {
4518
+ return pinnedIndex;
4519
+ } else {
4520
+ return highlight.index;
4521
+ }
4522
+ }
4020
4523
  // Remembering which list the index belongs to puts the highlight back on the
4021
4524
  // first item whenever a new list replaces it, without an effect to reset it.
4022
- // A list that grows or fills in under the same `list` keeps its highlight.
4023
- function useResultNavigation(items, list) {
4525
+ // A list that grows, fills in, or reorders under the same `list` keeps its
4526
+ // highlight on the same item, found again by key.
4527
+ // Disabled, nothing is highlighted and the keys and pointer leave it alone.
4528
+ function useResultNavigation(items, list, enabled = true) {
4024
4529
  const [highlight, setHighlight] = React.useState({
4025
4530
  index: 0,
4026
4531
  list
4027
4532
  });
4028
- const highlightedIndex = highlight.list === list ? highlight.index : 0;
4029
- const highlighted = items[highlightedIndex];
4533
+ const highlightedIndex = indexOf(highlight, items, list);
4534
+ const highlighted = enabled ? items[highlightedIndex] : undefined;
4030
4535
  const {
4031
4536
  copiedUrl,
4032
4537
  copy
4033
4538
  } = useCopyLink();
4034
- const highlightIndex = React.useCallback(index => setHighlight(current => current.list === list && current.index === index ? current : {
4035
- index,
4036
- list
4037
- }), [list]);
4539
+ const highlightIndex = React.useCallback(index => {
4540
+ var _a;
4541
+ if (!enabled) return;
4542
+ const key = (_a = items[index]) === null || _a === void 0 ? void 0 : _a.key;
4543
+ setHighlight(current => current.list === list && current.index === index && current.key === key ? current : {
4544
+ index,
4545
+ key,
4546
+ list
4547
+ });
4548
+ }, [enabled, items, list]);
4038
4549
  const handleKeyDown = event => {
4550
+ if (!enabled) return;
4039
4551
  const step = verticalStep(event.key);
4040
4552
  if (step && items.length > 0) {
4041
4553
  event.preventDefault();
@@ -4059,41 +4571,89 @@ function useResultNavigation(items, list) {
4059
4571
  };
4060
4572
  }
4061
4573
 
4062
- function groupSections(groups = []) {
4574
+ var styles$k = {"modal":"modal-NR3TO","visuallyHidden":"visuallyHidden-C28ju","panel":"panel-HlF7S"};
4575
+
4576
+ const FALLBACK_SLUGS = ["people", "services"];
4577
+ function defaultProduct(products, appName) {
4578
+ var _a;
4579
+ const current = products.find(product => product.appName === appName);
4580
+ const fallback = FALLBACK_SLUGS.map(slug => products.find(product => product.slug === slug)).find(Boolean);
4581
+ return (_a = current !== null && current !== void 0 ? current : fallback) !== null && _a !== void 0 ? _a : products[0];
4582
+ }
4583
+
4584
+ function groupSections(groups = [], timeZone) {
4063
4585
  return groups.map(({
4064
4586
  results,
4065
4587
  type
4066
4588
  }) => ({
4067
4589
  heading: type,
4068
- items: results.map(resultItem),
4590
+ items: results.map(result => resultItem(result, timeZone)),
4069
4591
  key: type
4070
4592
  }));
4071
4593
  }
4072
4594
  function resultItem({
4073
4595
  attributes,
4074
4596
  id
4075
- }) {
4597
+ }, timeZone) {
4076
4598
  return {
4599
+ category: attributes.category,
4600
+ imageUrl: attributes.image_url,
4077
4601
  key: id,
4078
- subtitle: summarize(attributes.metadata),
4602
+ product: attributes.product,
4603
+ subtitle: summarize(attributes, timeZone),
4079
4604
  title: attributes.title,
4080
4605
  url: attributes.url
4081
4606
  };
4082
4607
  }
4083
- function visitItem(visit) {
4608
+ function visitItem(visit, timeZone) {
4084
4609
  return {
4085
4610
  key: entryKey(visit.entry),
4086
- ...describeVisit(visit)
4611
+ ...describeVisit(visit, timeZone)
4087
4612
  };
4088
4613
  }
4089
- function summarize(metadata) {
4090
- return Object.values(metadata !== null && metadata !== void 0 ? metadata : {}).filter(value => typeof value === "string" && value !== "").join(" · ");
4614
+ const joinParts = (...parts) => parts.filter(Boolean).join(" · ");
4615
+ // Matches home-mobile's search subtitles, so a result reads the same in both.
4616
+ function summarize({
4617
+ category,
4618
+ metadata
4619
+ }, timeZone) {
4620
+ const text = key => {
4621
+ const value = metadata === null || metadata === void 0 ? void 0 : metadata[key];
4622
+ return typeof value === "string" ? value : "";
4623
+ };
4624
+ if (category === "profile") {
4625
+ return joinParts(text("phone"), text("email"));
4626
+ } else if (category === "event") {
4627
+ return eventTime(text("starts_at"), text("ends_at"), {
4628
+ recurring: (metadata === null || metadata === void 0 ? void 0 : metadata.recurring) === true,
4629
+ timeZone
4630
+ });
4631
+ } else {
4632
+ return text("details");
4633
+ }
4634
+ }
4635
+ // "Oct 25, 9–10:30am", in the organization's time zone like the rest
4636
+ // of Planning Center.
4637
+ function eventTime(startsAt, endsAt, {
4638
+ recurring,
4639
+ timeZone
4640
+ }) {
4641
+ if (startsAt === "") {
4642
+ return "";
4643
+ } else {
4644
+ const time = datetimeFmt.datetime(startsAt, endsAt || null, {
4645
+ style: "abbreviated",
4646
+ ...(timeZone && {
4647
+ timeZone
4648
+ })
4649
+ });
4650
+ return recurring ? joinParts(time, "Repeating") : time;
4651
+ }
4091
4652
  }
4092
4653
  // Unlike search results, recents come from every product, so each one names
4093
- // its product and type.
4094
- function describeVisit(visit) {
4654
+ // its type. The row's product icon says which product it came from.
4655
+ function describeVisit(visit, timeZone) {
4095
4656
  var _a, _b;
4096
- const subtitle = (...parts) => parts.filter(Boolean).join(" · ");
4097
4657
  if (visit.status === "page") {
4098
4658
  const {
4099
4659
  app,
@@ -4101,65 +4661,313 @@ function describeVisit(visit) {
4101
4661
  title
4102
4662
  } = visit.entry;
4103
4663
  return {
4104
- subtitle: subtitle(productName(app), (_a = metadata === null || metadata === void 0 ? void 0 : metadata.type) !== null && _a !== void 0 ? _a : "", (_b = metadata === null || metadata === void 0 ? void 0 : metadata.details) !== null && _b !== void 0 ? _b : ""),
4664
+ category: "generic",
4665
+ imageUrl: null,
4666
+ product: app,
4667
+ subtitle: joinParts(capitalize((_a = metadata === null || metadata === void 0 ? void 0 : metadata.type) !== null && _a !== void 0 ? _a : ""), (_b = metadata === null || metadata === void 0 ? void 0 : metadata.details) !== null && _b !== void 0 ? _b : ""),
4105
4668
  title,
4106
4669
  url: visit.url
4107
4670
  };
4108
4671
  } else {
4109
4672
  const {
4110
- metadata,
4673
+ attributes
4674
+ } = visit.result;
4675
+ const {
4676
+ category,
4677
+ image_url,
4111
4678
  product,
4112
4679
  title,
4113
4680
  type
4114
- } = visit.result.attributes;
4681
+ } = attributes;
4682
+ // Profiles and events say what they are with a phone number or a date.
4683
+ const kind = category === "generic" ? capitalize(pluralize.singular(type)) : "";
4115
4684
  return {
4116
- subtitle: subtitle(productName(product), type, summarize(metadata)),
4685
+ category,
4686
+ imageUrl: image_url,
4687
+ product,
4688
+ subtitle: joinParts(kind, summarize(attributes, timeZone)),
4117
4689
  title,
4118
4690
  url: visit.url
4119
4691
  };
4120
4692
  }
4121
4693
  }
4122
- // check-ins → Check-Ins
4123
- function productName(slug) {
4124
- return slug.split("-").map(capitalize).join("-");
4125
- }
4126
4694
  function capitalize(word) {
4127
4695
  return word.charAt(0).toUpperCase() + word.slice(1);
4128
4696
  }
4129
4697
 
4130
- const STORAGE_KEY = "topbar.product_search.last_product";
4131
- function readLastProduct() {
4132
- try {
4133
- return localStorage.getItem(STORAGE_KEY);
4134
- } catch {
4135
- return null;
4136
- }
4137
- }
4138
- function saveLastProduct(slug) {
4139
- try {
4140
- localStorage.setItem(STORAGE_KEY, slug);
4141
- } catch {
4142
- // Storage can be full or blocked; search still works without it.
4698
+ var styles$j = {"container":"container-YDdM1","hint":"hint-017Rd","keycap":"keycap-ENJM2","labels":"labels-GHPqL","copied":"copied-DUFa1"};
4699
+
4700
+ const SYMBOLS = {
4701
+ command: {
4702
+ label: "⌘",
4703
+ paths: ["M7 9a2 2 0 1 1 2 -2v10a2 2 0 1 1 -2 -2h10a2 2 0 1 1 -2 2v-10a2 2 0 1 1 2 2h-10"]
4704
+ },
4705
+ down: {
4706
+ label: "↓",
4707
+ paths: ["M12 6l0 12", "M16 14l-4 4", "M8 14l4 4"]
4708
+ },
4709
+ return: {
4710
+ label: "↵",
4711
+ paths: ["M18 6v6a3 3 0 0 1 -3 3h-10l4 -4m0 8l-4 -4"]
4712
+ },
4713
+ up: {
4714
+ label: "↑",
4715
+ paths: ["M12 6l0 12", "M16 10l-4 -4", "M8 10l4 -4"]
4143
4716
  }
4717
+ };
4718
+ function Keycap(props) {
4719
+ return /*#__PURE__*/React.createElement("kbd", {
4720
+ className: styles$j.keycap
4721
+ }, "symbol" in props ? (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("svg", {
4722
+ "aria-hidden": true,
4723
+ fill: "none",
4724
+ stroke: "currentColor",
4725
+ strokeLinecap: "round",
4726
+ strokeLinejoin: "round",
4727
+ viewBox: "0 0 24 24"
4728
+ }, SYMBOLS[props.symbol].paths.map(d => (/*#__PURE__*/React.createElement("path", {
4729
+ d: d,
4730
+ key: d
4731
+ })))), /*#__PURE__*/React.createElement("span", {
4732
+ className: styles$k.visuallyHidden
4733
+ }, SYMBOLS[props.symbol].label))) : props.label);
4734
+ }
4735
+ function CommandKey() {
4736
+ return isMac() ? /*#__PURE__*/React.createElement(Keycap, {
4737
+ symbol: "command"
4738
+ }) : /*#__PURE__*/React.createElement(Keycap, {
4739
+ label: "Ctrl"
4740
+ });
4144
4741
  }
4145
- function initialProduct(products) {
4146
- var _a, _b, _c;
4147
- const lastProduct = readLastProduct();
4148
- const bySlug = slug => products.find(product => product.slug === slug);
4149
- return (_c = (_b = (_a = bySlug(lastProduct)) !== null && _a !== void 0 ? _a : bySlug("people")) !== null && _b !== void 0 ? _b : bySlug("services")) !== null && _c !== void 0 ? _c : products[0];
4742
+ function EnterKey() {
4743
+ return isMac() ? /*#__PURE__*/React.createElement(Keycap, {
4744
+ symbol: "return"
4745
+ }) : /*#__PURE__*/React.createElement(Keycap, {
4746
+ label: "Enter"
4747
+ });
4150
4748
  }
4151
-
4749
+ const {
4750
+ copyLink,
4751
+ openInNewTab,
4752
+ openSearch,
4753
+ select
4754
+ } = KEYBOARD_SHORTCUTS;
4152
4755
  function KeyboardHints({
4153
4756
  copied
4154
4757
  }) {
4155
- const command = commandKeyLabel();
4156
- return /*#__PURE__*/React.createElement("p", null, "\u2191\u2193 Select \u00B7 \u21B5 Open \u00B7 ", command, "\u21B5 Open in new tab \u00B7 ", command, "C", " ", /*#__PURE__*/React.createElement("span", {
4758
+ return /*#__PURE__*/React.createElement("ul", {
4759
+ "aria-label": "Keyboard shortcuts",
4760
+ className: styles$j.container,
4761
+ "data-platform": isMac() ? "mac" : "pc"
4762
+ }, /*#__PURE__*/React.createElement("li", {
4763
+ className: styles$j.hint
4764
+ }, /*#__PURE__*/React.createElement(tapestry.Flex, {
4765
+ gap: 0.5
4766
+ }, select.modifierKey, /*#__PURE__*/React.createElement(Keycap, {
4767
+ symbol: "up"
4768
+ }), /*#__PURE__*/React.createElement(Keycap, {
4769
+ symbol: "down"
4770
+ })), select.label), /*#__PURE__*/React.createElement("li", {
4771
+ className: styles$j.hint
4772
+ }, /*#__PURE__*/React.createElement(tapestry.Flex, {
4773
+ gap: 0.5
4774
+ }, /*#__PURE__*/React.createElement(CommandKey, null), /*#__PURE__*/React.createElement(EnterKey, null)), openInNewTab.label), /*#__PURE__*/React.createElement("li", {
4775
+ className: classnames(styles$j.hint, copied && styles$j.copied),
4776
+ style: {
4777
+ "--copied-active": `${COPIED_TIMING.active}ms`,
4778
+ "--copied-enter": `${COPIED_TIMING.enter}ms`,
4779
+ "--copied-exit": `${COPIED_TIMING.exit}ms`
4780
+ }
4781
+ }, /*#__PURE__*/React.createElement(tapestry.Flex, {
4782
+ gap: 0.5
4783
+ }, /*#__PURE__*/React.createElement(CommandKey, null), /*#__PURE__*/React.createElement(Keycap, {
4784
+ label: copyLink.key.toUpperCase()
4785
+ })), /*#__PURE__*/React.createElement("span", {
4786
+ className: styles$j.labels
4787
+ }, /*#__PURE__*/React.createElement("span", {
4788
+ "aria-hidden": copied
4789
+ }, copyLink.label), /*#__PURE__*/React.createElement("span", {
4157
4790
  role: "status"
4158
- }, copied ? "Copied!" : "Copy link"), " \u00B7 ", command, "K Open search");
4791
+ }, copied && "Copied!"))), /*#__PURE__*/React.createElement("li", {
4792
+ className: styles$j.hint
4793
+ }, /*#__PURE__*/React.createElement(tapestry.Flex, {
4794
+ gap: 0.5
4795
+ }, /*#__PURE__*/React.createElement(CommandKey, null), /*#__PURE__*/React.createElement(Keycap, {
4796
+ label: openSearch.key.toUpperCase()
4797
+ })), openSearch.label));
4798
+ }
4799
+
4800
+ var styles$i = {"icon":"icon-XKLvN","squircle":"squircle-JCHr6"};
4801
+
4802
+ const PRODUCTS = {
4803
+ accounts: {
4804
+ gradient: "--t-fill-color-product-accounts-gradient-brand",
4805
+ path: logomarks__namespace.accounts
4806
+ },
4807
+ api: {
4808
+ gradient: "--t-fill-color-product-api-gradient-brand",
4809
+ path: logomarks__namespace.api
4810
+ },
4811
+ calendar: {
4812
+ gradient: "--t-fill-color-product-calendar-gradient-brand",
4813
+ path: logomarks__namespace.calendar
4814
+ },
4815
+ "check-ins": {
4816
+ gradient: "--t-fill-color-product-checkins-gradient-brand",
4817
+ path: logomarks__namespace.checkIns
4818
+ },
4819
+ "church-center": {
4820
+ gradient: "--t-fill-color-product-cc-gradient-brand",
4821
+ path: logomarks__namespace.churchCenter
4822
+ },
4823
+ giving: {
4824
+ gradient: "--t-fill-color-product-giving-gradient-brand",
4825
+ path: logomarks__namespace.giving
4826
+ },
4827
+ groups: {
4828
+ gradient: "--t-fill-color-product-groups-gradient-brand",
4829
+ path: logomarks__namespace.groups
4830
+ },
4831
+ home: {
4832
+ gradient: "--t-fill-color-product-home-gradient-brand",
4833
+ path: logomarks__namespace.home
4834
+ },
4835
+ "music-stand": {
4836
+ gradient: "--t-fill-color-product-musicstand-gradient-brand",
4837
+ path: logomarks__namespace.musicStand
4838
+ },
4839
+ people: {
4840
+ gradient: "--t-fill-color-product-people-gradient-brand",
4841
+ path: logomarks__namespace.people
4842
+ },
4843
+ publishing: {
4844
+ gradient: "--t-fill-color-product-publishing-gradient-brand",
4845
+ path: logomarks__namespace.publishing
4846
+ },
4847
+ registrations: {
4848
+ gradient: "--t-fill-color-product-registrations-gradient-brand",
4849
+ path: logomarks__namespace.registrations
4850
+ },
4851
+ services: {
4852
+ gradient: "--t-fill-color-product-services-gradient-brand",
4853
+ path: logomarks__namespace.services
4854
+ }
4855
+ };
4856
+ const isProductIconSlug = slug => Object.prototype.hasOwnProperty.call(PRODUCTS, slug);
4857
+ const maskFor = path => `url("data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="${path}"/></svg>`)}")`;
4858
+ function ProductIcon({
4859
+ size = 16,
4860
+ slug
4861
+ }) {
4862
+ const {
4863
+ gradient,
4864
+ path
4865
+ } = PRODUCTS[slug];
4866
+ const mask = maskFor(path);
4867
+ return /*#__PURE__*/React.createElement("span", {
4868
+ "aria-hidden": true,
4869
+ className: styles$i.icon,
4870
+ style: {
4871
+ height: size,
4872
+ width: size
4873
+ }
4874
+ }, /*#__PURE__*/React.createElement("span", {
4875
+ className: styles$i.squircle,
4876
+ style: {
4877
+ WebkitMaskImage: mask,
4878
+ background: `var(${gradient})`,
4879
+ maskImage: mask
4880
+ }
4881
+ }));
4882
+ }
4883
+
4884
+ var styles$h = {"picker":"picker-iuzzj","option":"option--7LXg"};
4885
+
4886
+ // Phones have no room for a tab per product, so they pick from a dropdown.
4887
+ // Complex mode renders each option's logomark, in the list and the trigger.
4888
+ function ProductSelect({
4889
+ children,
4890
+ onSelect,
4891
+ products,
4892
+ selected
4893
+ }) {
4894
+ const options = products.map(({
4895
+ appName,
4896
+ slug
4897
+ }) => ({
4898
+ label: (/*#__PURE__*/React.createElement("span", {
4899
+ className: styles$h.option
4900
+ }, /*#__PURE__*/React.createElement(ProductIcon, {
4901
+ slug: slug
4902
+ }), appName)),
4903
+ textValue: appName,
4904
+ value: slug
4905
+ }));
4906
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
4907
+ className: styles$h.picker
4908
+ }, /*#__PURE__*/React.createElement(tapestry.Select, {
4909
+ "aria-label": "Product",
4910
+ complex: true,
4911
+ onChange: event => onSelect(event.target.value),
4912
+ options: options,
4913
+ value: selected.slug
4914
+ })), /*#__PURE__*/React.createElement("div", {
4915
+ className: styles$k.panel
4916
+ }, children));
4917
+ }
4918
+
4919
+ // Browsers match :focus-visible on every focused text field, keyboard or not,
4920
+ // since typing follows either way. So this remembers what last moved focus,
4921
+ // shared by every field and listened for once, in the capture phase so it's
4922
+ // known before focus moves.
4923
+ let lastInteraction = "pointer";
4924
+ let listening = false;
4925
+ function listen() {
4926
+ if (listening) return;
4927
+ listening = true;
4928
+ document.addEventListener("keydown", event => {
4929
+ // Shortcuts like ⌘C don't move focus.
4930
+ if (!event.metaKey && !event.ctrlKey && !event.altKey) {
4931
+ lastInteraction = "keyboard";
4932
+ }
4933
+ }, true);
4934
+ document.addEventListener("pointerdown", () => {
4935
+ lastInteraction = "pointer";
4936
+ }, true);
4937
+ }
4938
+ /**
4939
+ * Whether a field was focused from the keyboard, as by Tab, rather than by a
4940
+ * click or tap. Spread `focusProps` onto the field, and style it by
4941
+ * `data-focus-visible`.
4942
+ */
4943
+ function useKeyboardFocus({
4944
+ onBlur,
4945
+ onFocus
4946
+ } = {}) {
4947
+ const [focusVisible, setFocusVisible] = React.useState(false);
4948
+ React.useEffect(listen, []);
4949
+ return {
4950
+ focusProps: {
4951
+ "data-focus-visible": focusVisible || undefined,
4952
+ onBlur: event => {
4953
+ setFocusVisible(false);
4954
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
4955
+ },
4956
+ onFocus: event => {
4957
+ const keyboard = lastInteraction === "keyboard";
4958
+ setFocusVisible(keyboard);
4959
+ onFocus === null || onFocus === void 0 ? void 0 : onFocus(event, keyboard);
4960
+ }
4961
+ },
4962
+ focusVisible
4963
+ };
4159
4964
  }
4160
4965
 
4161
- var styles$d = {"tab":"tab-dz8ki"};
4966
+ var styles$g = {"tablist":"tablist-7ASvc","tab":"tab-dz8ki"};
4162
4967
 
4968
+ // With this many tabs or more, only the selected tab shows its name, so they
4969
+ // all fit. Fewer always fit with their names.
4970
+ const ICON_ONLY_TAB_COUNT = 5;
4163
4971
  function ProductTabs({
4164
4972
  children,
4165
4973
  onKeyDown,
@@ -4170,6 +4978,7 @@ function ProductTabs({
4170
4978
  const id = useInstanceId("product-tabs");
4171
4979
  const tabId = slug => `${id}-tab-${slug}`;
4172
4980
  const tabRefs = React.useRef(new Map());
4981
+ const showAllNames = products.length < ICON_ONLY_TAB_COUNT;
4173
4982
  const handleKeyDown = event => {
4174
4983
  var _a;
4175
4984
  const offset = horizontalStep(event.key);
@@ -4184,13 +4993,13 @@ function ProductTabs({
4184
4993
  }
4185
4994
  };
4186
4995
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
4187
- "aria-label": "Product",
4996
+ "aria-label": "Search in",
4997
+ className: styles$g.tablist,
4188
4998
  onKeyDown: handleKeyDown,
4189
4999
  role: "tablist"
4190
- }, products.map(product => (/*#__PURE__*/React.createElement("button", {
5000
+ }, products.map(product => (/*#__PURE__*/React.createElement(Tab, {
4191
5001
  "aria-controls": `${id}-panel`,
4192
5002
  "aria-selected": product === selected,
4193
- className: styles$d.tab,
4194
5003
  id: tabId(product.slug),
4195
5004
  key: product.slug,
4196
5005
  onClick: () => onSelect(product.slug),
@@ -4201,15 +5010,392 @@ function ProductTabs({
4201
5010
  tabRefs.current.delete(product.slug);
4202
5011
  }
4203
5012
  },
4204
- role: "tab",
4205
- tabIndex: product === selected ? 0 : -1,
4206
- type: "button"
4207
- }, product.appName)))), /*#__PURE__*/React.createElement("div", {
5013
+ tabIndex: product === selected ? 0 : -1
5014
+ }, /*#__PURE__*/React.createElement(ProductIcon, {
5015
+ slug: product.slug
5016
+ }), showAllNames || product === selected ? product.appName : (/*#__PURE__*/React.createElement("span", {
5017
+ className: styles$k.visuallyHidden
5018
+ }, product.appName)))))), /*#__PURE__*/React.createElement("div", {
4208
5019
  "aria-labelledby": tabId(selected.slug),
5020
+ className: styles$k.panel,
4209
5021
  id: `${id}-panel`,
4210
5022
  role: "tabpanel"
4211
5023
  }, children));
4212
5024
  }
5025
+ // The modal's focus scope moves focus here by script when Tab is pressed, and
5026
+ // Safari doesn't match :focus-visible on focus moved by script. So the tab
5027
+ // remembers whether the keyboard brought focus, and the ring keys off that.
5028
+ const Tab = /*#__PURE__*/React.forwardRef(function Tab(props, ref) {
5029
+ const {
5030
+ focusProps
5031
+ } = useKeyboardFocus();
5032
+ return /*#__PURE__*/React.createElement("button", {
5033
+ className: styles$g.tab,
5034
+ ref: ref,
5035
+ role: "tab",
5036
+ type: "button",
5037
+ ...props,
5038
+ ...focusProps
5039
+ });
5040
+ });
5041
+
5042
+ function BlankStateRecentlyVisited(props) {
5043
+ const id = useInstanceId("blank-state-initial");
5044
+ return /*#__PURE__*/React.createElement("svg", {
5045
+ viewBox: "0 0 197 174",
5046
+ fill: "none",
5047
+ "aria-hidden": "true",
5048
+ focusable: "false",
5049
+ ...props
5050
+ }, /*#__PURE__*/React.createElement("path", {
5051
+ d: "M139.863 32.119c10.938 10.028 21.777 20.154 32.912 30.084 8.376 7.373 21.975 15.828 23.157 28.02.592 6.095-2.167 11.993-5.321 17.204-24.635 40.8-81.098 67.148-127.412 48.862-30.646-12.093-76.172-47.387-59.716-85.041 15.865-36.377 64.84-55.056 83.957-57.71 21.876-4.621 34.883 2.457 52.423 18.58Z",
5052
+ fill: "currentColor"
5053
+ }), /*#__PURE__*/React.createElement("g", {
5054
+ clipPath: `url(#${id}-a)`
5055
+ }, /*#__PURE__*/React.createElement("path", {
5056
+ d: "M115.885 109.31c-.478-.686-.01-1.845 1.046-2.589s2.3-.791 2.778-.105c.478.686.009 1.845-1.047 2.589-1.056.744-2.299.791-2.777.105Z",
5057
+ fill: "#333"
5058
+ }), /*#__PURE__*/React.createElement("path", {
5059
+ d: "M123.403 113.599c-3.456 0-6.259-2.817-6.259-6.293 0-3.475 2.803-6.293 6.259-6.293 3.457 0 6.259 2.818 6.259 6.293 0 3.476-2.802 6.293-6.259 6.293Z",
5060
+ fill: "#333"
5061
+ }), /*#__PURE__*/React.createElement("path", {
5062
+ d: "M118.853 100.968a2.85 2.85 0 0 0 2.832-2.484 2.89 2.89 0 0 0-.071-1.115c-2.638-9.955-9.668-9.687-9.964-9.665l.311 5.716h-.104c.119 0 2.853.134 4.254 5.421a2.874 2.874 0 0 0 1.013 1.53 2.846 2.846 0 0 0 1.729.597Z",
5063
+ fill: "#4D4D4D"
5064
+ }), /*#__PURE__*/React.createElement("path", {
5065
+ d: "M114.96 100.503c-.462-5.894 2.796-10.96 7.279-11.315 4.482-.356 8.491 4.134 8.953 10.027.462 5.894-2.796 10.96-7.279 11.315-4.482.356-8.491-4.134-8.953-10.027Z",
5066
+ fill: "#F2F2F2"
5067
+ }), /*#__PURE__*/React.createElement("path", {
5068
+ d: "M125.964 107.738c-4.48.354-8.489-4.135-8.953-10.026a12.893 12.893 0 0 1 1.223-6.707c-2.249 2.046-3.591 5.59-3.283 9.505.463 5.895 4.469 10.384 8.953 10.027 2.594-.205 4.765-1.986 6.055-4.591a6.682 6.682 0 0 1-3.995 1.792Z",
5069
+ fill: "#E6E6E6"
5070
+ }), /*#__PURE__*/React.createElement("path", {
5071
+ d: "M115.885 109.31c-.478-.686-.01-1.845 1.046-2.589s2.3-.791 2.778-.105c.478.686.009 1.845-1.047 2.589-1.056.744-2.299.791-2.777.105Z",
5072
+ fill: "#333"
5073
+ }), /*#__PURE__*/React.createElement("path", {
5074
+ d: "M123.403 113.599c-3.456 0-6.259-2.817-6.259-6.293 0-3.475 2.803-6.293 6.259-6.293 3.457 0 6.259 2.818 6.259 6.293 0 3.476-2.802 6.293-6.259 6.293Z",
5075
+ fill: "#333"
5076
+ }), /*#__PURE__*/React.createElement("path", {
5077
+ d: "M118.853 100.968a2.85 2.85 0 0 0 2.832-2.484 2.89 2.89 0 0 0-.071-1.115c-2.638-9.955-9.668-9.687-9.964-9.665l.311 5.716h-.104c.119 0 2.853.134 4.254 5.421a2.874 2.874 0 0 0 1.013 1.53 2.846 2.846 0 0 0 1.729.597Z",
5078
+ fill: "#4D4D4D"
5079
+ }), /*#__PURE__*/React.createElement("path", {
5080
+ d: "M114.96 100.503c-.462-5.894 2.796-10.96 7.279-11.315 4.482-.356 8.491 4.134 8.953 10.027.462 5.894-2.796 10.96-7.279 11.315-4.482.356-8.491-4.134-8.953-10.027Z",
5081
+ fill: "#F2F2F2"
5082
+ }), /*#__PURE__*/React.createElement("path", {
5083
+ d: "M125.964 107.738c-4.48.354-8.489-4.135-8.953-10.026a12.893 12.893 0 0 1 1.223-6.707c-2.249 2.046-3.591 5.59-3.283 9.505.463 5.895 4.469 10.384 8.953 10.027 2.594-.205 4.765-1.986 6.055-4.591a6.682 6.682 0 0 1-3.995 1.792Z",
5084
+ fill: "#E6E6E6"
5085
+ }), /*#__PURE__*/React.createElement("path", {
5086
+ d: "M89.317 121.331a2.836 2.836 0 0 1-1.92-.752 2.869 2.869 0 0 1-.911-1.857c-.534-5.726 3.527-13.808 3.99-14.713a2.849 2.849 0 0 1 1.666-1.413 2.835 2.835 0 0 1 2.172.185 2.86 2.86 0 0 1 1.405 1.675 2.876 2.876 0 0 1-.184 2.183c-1.46 2.843-3.669 8.492-3.383 11.551a2.868 2.868 0 0 1-1.504 2.797 2.84 2.84 0 0 1-1.064.318 1.378 1.378 0 0 1-.267.026Z",
5087
+ fill: "#4D4D4D"
5088
+ }), /*#__PURE__*/React.createElement("path", {
5089
+ d: "M92.155 112.314c3.308 0 5.989-2.696 5.989-6.021 0-3.326-2.681-6.021-5.989-6.021-3.307 0-5.988 2.695-5.988 6.021 0 3.325 2.681 6.021 5.988 6.021Z",
5090
+ fill: "gray"
5091
+ }), /*#__PURE__*/React.createElement("path", {
5092
+ d: "M80.597 128.771h11.769v3.726a1.118 1.118 0 0 1-1.112 1.118H78.57a1.118 1.118 0 0 1-1.112-1.118v-.566c0-.841.332-1.648.924-2.242a3.144 3.144 0 0 1 2.23-.929l-.015.011Z",
5093
+ fill: "#333"
5094
+ }), /*#__PURE__*/React.createElement("path", {
5095
+ d: "M89.572 132.084s8.075.119 6.3-8.268c-1.775-8.387-12.188-15.351-15.234-6.066-3.046 9.285-1.386 15.232 8.934 14.334Z",
5096
+ fill: "#F2F2F2"
5097
+ }), /*#__PURE__*/React.createElement("path", {
5098
+ d: "M106.67 121.334h-.27a2.84 2.84 0 0 1-1.925-1.025 2.872 2.872 0 0 1-.639-2.093c.285-3.059-1.92-8.708-3.38-11.551a2.873 2.873 0 0 1 1.296-3.721 2.832 2.832 0 0 1 2.102-.199 2.848 2.848 0 0 1 1.66 1.312c.463.906 4.521 8.991 3.988 14.714a2.874 2.874 0 0 1-.926 1.828 2.832 2.832 0 0 1-1.906.735Z",
5099
+ fill: "#4D4D4D"
5100
+ }), /*#__PURE__*/React.createElement("path", {
5101
+ d: "M103.835 112.314c3.307 0 5.988-2.696 5.988-6.021 0-3.326-2.681-6.021-5.988-6.021-3.307 0-5.988 2.695-5.988 6.021 0 3.325 2.681 6.021 5.988 6.021Z",
5102
+ fill: "gray"
5103
+ }), /*#__PURE__*/React.createElement("path", {
5104
+ d: "m117.408 133.652-12.674-.002c-.295 0-.577-.118-.786-.328a1.121 1.121 0 0 1-.325-.79v-3.726l11.773.002c.837 0 1.639.334 2.23.929s.923 1.401.923 2.242v.567a1.116 1.116 0 0 1-1.141 1.106Z",
5105
+ fill: "#333"
5106
+ }), /*#__PURE__*/React.createElement("path", {
5107
+ d: "M106.414 132.084s-8.075.119-6.318-8.268c1.756-8.387 12.195-15.343 15.237-6.062 3.043 9.281 1.405 15.235-8.919 14.33Z",
5108
+ fill: "#F2F2F2"
5109
+ }), /*#__PURE__*/React.createElement("path", {
5110
+ d: "M109.107 94.58a2.305 2.305 0 0 0 2.191 2.412 2.302 2.302 0 0 0 2.399-2.202l.333-7.33a2.306 2.306 0 0 0-2.191-2.412 2.303 2.303 0 0 0-2.4 2.203l-.332 7.328Z",
5111
+ fill: "gray"
5112
+ }), /*#__PURE__*/React.createElement("path", {
5113
+ d: "M80.968 109.31c.478-.686.01-1.845-1.047-2.589-1.056-.744-2.3-.791-2.777-.105-.478.686-.01 1.845 1.046 2.589s2.3.791 2.778.105Z",
5114
+ fill: "#333"
5115
+ }), /*#__PURE__*/React.createElement("path", {
5116
+ d: "M73.448 113.599c3.457 0 6.26-2.817 6.26-6.293 0-3.475-2.803-6.293-6.26-6.293-3.456 0-6.258 2.818-6.258 6.293 0 3.476 2.802 6.293 6.258 6.293Z",
5117
+ fill: "#333"
5118
+ }), /*#__PURE__*/React.createElement("path", {
5119
+ d: "M78 100.968a2.853 2.853 0 0 1-2.832-2.484 2.876 2.876 0 0 1 .07-1.115c2.639-9.955 9.669-9.687 9.965-9.665l-.311 5.716h.104c-.12 0-2.854.134-4.255 5.421a2.87 2.87 0 0 1-1.013 1.53 2.845 2.845 0 0 1-1.729.597Z",
5120
+ fill: "#4D4D4D"
5121
+ }), /*#__PURE__*/React.createElement("path", {
5122
+ d: "M87.37 88.17a2.305 2.305 0 0 0-2.19-2.413 2.302 2.302 0 0 0-2.4 2.202l-.332 7.329a2.305 2.305 0 0 0 2.19 2.413 2.302 2.302 0 0 0 2.4-2.203l.332-7.328Z",
5123
+ fill: "gray"
5124
+ }), /*#__PURE__*/React.createElement("path", {
5125
+ d: "M81.893 100.503c.462-5.894-2.797-10.96-7.28-11.315-4.482-.356-8.49 4.134-8.953 10.027-.462 5.894 2.797 10.96 7.28 11.315 4.482.356 8.49-4.134 8.953-10.027Z",
5126
+ fill: "#F2F2F2"
5127
+ }), /*#__PURE__*/React.createElement("path", {
5128
+ d: "M70.888 107.738c4.48.354 8.49-4.135 8.953-10.026a12.89 12.89 0 0 0-1.223-6.707c2.25 2.046 3.591 5.59 3.284 9.505-.464 5.895-4.47 10.384-8.953 10.027-2.594-.205-4.766-1.986-6.055-4.591a6.682 6.682 0 0 0 3.994 1.792Z",
5129
+ fill: "#E6E6E6"
5130
+ }), /*#__PURE__*/React.createElement("path", {
5131
+ d: "M112.717 94.105c-.511-9.095-7.459-11.703-15.82-11.226-8.36.477-14.97 3.856-14.451 12.951.518 9.095 7.707 16.081 16.067 15.605 8.36-.477 14.719-8.231 14.204-17.33Z",
5132
+ fill: "#F2F2F2"
5133
+ }), /*#__PURE__*/React.createElement("path", {
5134
+ d: "M112.565 92.656c-1.056 7.496-6.799 13.413-14.059 13.812-7.852.451-14.67-5.686-15.897-13.965a14.571 14.571 0 0 0-.17 3.327c.51 9.095 7.704 16.081 16.067 15.605 8.364-.477 14.723-8.235 14.211-17.33a16.83 16.83 0 0 0-.152-1.45Z",
5135
+ fill: "#E6E6E6"
5136
+ }), /*#__PURE__*/React.createElement("path", {
5137
+ d: "M103.546 90.353H91.61a.62.62 0 0 0-.619.623v1.762a.62.62 0 0 0 .62.622h11.935a.62.62 0 0 0 .619-.622v-1.762a.62.62 0 0 0-.619-.623Zm0 5.187H91.61a.62.62 0 0 0-.619.622v1.762a.62.62 0 0 0 .62.623h11.935a.62.62 0 0 0 .619-.623v-1.762a.62.62 0 0 0-.619-.622Zm-.004 5.19H91.606a.62.62 0 0 0-.619.622v1.763a.62.62 0 0 0 .62.622h11.935a.62.62 0 0 0 .619-.622v-1.763a.62.62 0 0 0-.619-.622Z",
5138
+ fill: "#3690EA"
5139
+ }), /*#__PURE__*/React.createElement("path", {
5140
+ d: "M89.317 121.331a2.836 2.836 0 0 1-1.92-.752 2.869 2.869 0 0 1-.911-1.857c-.534-5.726 3.527-13.808 3.99-14.713a2.849 2.849 0 0 1 1.666-1.413 2.835 2.835 0 0 1 2.172.185 2.86 2.86 0 0 1 1.405 1.675 2.876 2.876 0 0 1-.184 2.183c-1.46 2.843-3.669 8.492-3.383 11.551a2.868 2.868 0 0 1-1.504 2.797 2.84 2.84 0 0 1-1.064.318 1.378 1.378 0 0 1-.267.026Z",
5141
+ fill: "#4D4D4D"
5142
+ }), /*#__PURE__*/React.createElement("path", {
5143
+ d: "M92.155 112.314c3.308 0 5.989-2.696 5.989-6.021 0-3.326-2.681-6.021-5.989-6.021-3.307 0-5.988 2.695-5.988 6.021 0 3.325 2.681 6.021 5.988 6.021Z",
5144
+ fill: "gray"
5145
+ }), /*#__PURE__*/React.createElement("path", {
5146
+ d: "M80.597 128.771h11.769v3.726a1.118 1.118 0 0 1-1.112 1.118H78.57a1.118 1.118 0 0 1-1.112-1.118v-.566c0-.841.332-1.648.924-2.242a3.144 3.144 0 0 1 2.23-.929l-.015.011Z",
5147
+ fill: "#333"
5148
+ }), /*#__PURE__*/React.createElement("path", {
5149
+ d: "M89.572 132.084s8.075.119 6.3-8.268c-1.775-8.387-12.188-15.351-15.234-6.066-3.046 9.285-1.386 15.232 8.934 14.334Z",
5150
+ fill: "#F2F2F2"
5151
+ }), /*#__PURE__*/React.createElement("path", {
5152
+ d: "M106.67 121.334h-.27a2.84 2.84 0 0 1-1.925-1.025 2.872 2.872 0 0 1-.639-2.093c.285-3.059-1.92-8.708-3.38-11.551a2.873 2.873 0 0 1 1.296-3.721 2.832 2.832 0 0 1 2.102-.199 2.848 2.848 0 0 1 1.66 1.312c.463.906 4.521 8.991 3.988 14.714a2.874 2.874 0 0 1-.926 1.828 2.832 2.832 0 0 1-1.906.735Z",
5153
+ fill: "#4D4D4D"
5154
+ }), /*#__PURE__*/React.createElement("path", {
5155
+ d: "M103.835 112.314c3.307 0 5.988-2.696 5.988-6.021 0-3.326-2.681-6.021-5.988-6.021-3.307 0-5.988 2.695-5.988 6.021 0 3.325 2.681 6.021 5.988 6.021Z",
5156
+ fill: "gray"
5157
+ }), /*#__PURE__*/React.createElement("path", {
5158
+ d: "m117.408 133.652-12.674-.002c-.295 0-.577-.118-.786-.328a1.121 1.121 0 0 1-.325-.79v-3.726l11.773.002c.837 0 1.639.334 2.23.929s.923 1.401.923 2.242v.567a1.116 1.116 0 0 1-1.141 1.106Z",
5159
+ fill: "#333"
5160
+ }), /*#__PURE__*/React.createElement("path", {
5161
+ d: "M106.414 132.084s-8.075.119-6.318-8.268c1.756-8.387 12.195-15.343 15.237-6.062 3.043 9.281 1.405 15.235-8.919 14.33Z",
5162
+ fill: "#F2F2F2"
5163
+ }), /*#__PURE__*/React.createElement("path", {
5164
+ d: "M109.107 94.58a2.305 2.305 0 0 0 2.191 2.412 2.302 2.302 0 0 0 2.399-2.202l.333-7.33a2.306 2.306 0 0 0-2.191-2.412 2.303 2.303 0 0 0-2.4 2.203l-.332 7.328Z",
5165
+ fill: "gray"
5166
+ }), /*#__PURE__*/React.createElement("path", {
5167
+ d: "M80.968 109.31c.478-.686.01-1.845-1.047-2.589-1.056-.744-2.3-.791-2.777-.105-.478.686-.01 1.845 1.046 2.589s2.3.791 2.778.105Z",
5168
+ fill: "#333"
5169
+ }), /*#__PURE__*/React.createElement("path", {
5170
+ d: "M73.448 113.599c3.457 0 6.26-2.817 6.26-6.293 0-3.475-2.803-6.293-6.26-6.293-3.456 0-6.258 2.818-6.258 6.293 0 3.476 2.802 6.293 6.258 6.293Z",
5171
+ fill: "#333"
5172
+ }), /*#__PURE__*/React.createElement("path", {
5173
+ d: "M78 100.968a2.853 2.853 0 0 1-2.832-2.484 2.876 2.876 0 0 1 .07-1.115c2.639-9.955 9.669-9.687 9.965-9.665l-.311 5.716h.104c-.12 0-2.854.134-4.255 5.421a2.87 2.87 0 0 1-1.013 1.53 2.845 2.845 0 0 1-1.729.597Z",
5174
+ fill: "#4D4D4D"
5175
+ }), /*#__PURE__*/React.createElement("path", {
5176
+ d: "M87.37 88.17a2.305 2.305 0 0 0-2.19-2.413 2.302 2.302 0 0 0-2.4 2.202l-.332 7.329a2.305 2.305 0 0 0 2.19 2.413 2.302 2.302 0 0 0 2.4-2.203l.332-7.328Z",
5177
+ fill: "gray"
5178
+ }), /*#__PURE__*/React.createElement("path", {
5179
+ d: "M81.893 100.503c.462-5.894-2.797-10.96-7.28-11.315-4.482-.356-8.49 4.134-8.953 10.027-.462 5.894 2.797 10.96 7.28 11.315 4.482.356 8.49-4.134 8.953-10.027Z",
5180
+ fill: "#F2F2F2"
5181
+ }), /*#__PURE__*/React.createElement("path", {
5182
+ d: "M70.888 107.738c4.48.354 8.49-4.135 8.953-10.026a12.89 12.89 0 0 0-1.223-6.707c2.25 2.046 3.591 5.59 3.284 9.505-.464 5.895-4.47 10.384-8.953 10.027-2.594-.205-4.766-1.986-6.055-4.591a6.682 6.682 0 0 0 3.994 1.792Z",
5183
+ fill: "#E6E6E6"
5184
+ }), /*#__PURE__*/React.createElement("path", {
5185
+ d: "M112.717 94.105c-.511-9.095-7.459-11.703-15.82-11.226-8.36.477-14.97 3.856-14.451 12.951.518 9.095 7.707 16.081 16.067 15.605 8.36-.477 14.719-8.231 14.204-17.33Z",
5186
+ fill: "#F2F2F2"
5187
+ }), /*#__PURE__*/React.createElement("path", {
5188
+ d: "M112.565 92.656c-1.056 7.496-6.799 13.413-14.059 13.812-7.852.451-14.67-5.686-15.897-13.965a14.571 14.571 0 0 0-.17 3.327c.51 9.095 7.704 16.081 16.067 15.605 8.364-.477 14.723-8.235 14.211-17.33a16.83 16.83 0 0 0-.152-1.45Z",
5189
+ fill: "#E6E6E6"
5190
+ }), /*#__PURE__*/React.createElement("path", {
5191
+ d: "M94.626 78.445c-.114-.488 6.548-.927 5.815.246v.775c0 .746.033 1.49.033 2.258s.037 1.595.044 2.392c.278.593-6.473.935-5.817-.115v-.67c-.015-1.63-.06-3.257-.075-4.886Z",
5192
+ fill: "#999"
5193
+ }), /*#__PURE__*/React.createElement("path", {
5194
+ d: "M103.546 90.353H91.61a.62.62 0 0 0-.619.623v1.762a.62.62 0 0 0 .62.622h11.935a.62.62 0 0 0 .619-.622v-1.762a.62.62 0 0 0-.619-.623Zm0 5.187H91.61a.62.62 0 0 0-.619.622v1.762a.62.62 0 0 0 .62.623h11.935a.62.62 0 0 0 .619-.623v-1.762a.62.62 0 0 0-.619-.622Zm-.004 5.19H91.606a.62.62 0 0 0-.619.622v1.763a.62.62 0 0 0 .62.622h11.935a.62.62 0 0 0 .619-.622v-1.763a.62.62 0 0 0-.619-.622ZM55.773 64.004c4.349 0 7.874-5.285 7.874-11.804s-3.525-11.804-7.874-11.804-7.875 5.285-7.875 11.804c0 6.52 3.526 11.804 7.875 11.804Zm84.17.015c4.349 0 7.874-5.285 7.874-11.804 0-6.52-3.525-11.804-7.874-11.804s-7.875 5.285-7.875 11.804 3.526 11.804 7.875 11.804Z",
5195
+ fill: "#3690EA"
5196
+ }), /*#__PURE__*/React.createElement("path", {
5197
+ d: "M97.962 29.036c7.273 0 13.17-2.224 13.17-4.967 0-2.743-5.897-4.966-13.17-4.966-7.274 0-13.17 2.223-13.17 4.966 0 2.743 5.896 4.967 13.17 4.967Z",
5198
+ fill: "#B3B3B3"
5199
+ }), /*#__PURE__*/React.createElement("path", {
5200
+ d: "M97.962 16.55c4.545 0 8.23-3.705 8.23-8.275S102.507 0 97.962 0c-4.546 0-8.23 3.705-8.23 8.275s3.684 8.275 8.23 8.275Z",
5201
+ fill: "#3690EA"
5202
+ }), /*#__PURE__*/React.createElement("path", {
5203
+ d: "M141.607 59.283V45.147a19.038 19.038 0 0 0-3.687-11.301 18.872 18.872 0 0 0-9.653-6.874c-8.838-2.69-19.203-4.24-30.29-4.244-11.088-.004-21.452 1.546-30.29 4.233a18.871 18.871 0 0 0-9.668 6.866 19.041 19.041 0 0 0-3.699 11.305v14.132a19.03 19.03 0 0 0 3.685 11.303 18.86 18.86 0 0 0 9.656 6.872c8.841 2.694 19.206 4.244 30.29 4.244 11.083 0 21.452-1.542 30.294-4.233a18.858 18.858 0 0 0 9.666-6.863 19.028 19.028 0 0 0 3.696-11.304Z",
5204
+ fill: "#F2F2F2"
5205
+ }), /*#__PURE__*/React.createElement("path", {
5206
+ d: "M97.954 75.051c-10.068 0-19.88-1.371-28.381-3.957a12.353 12.353 0 0 1-6.262-4.485 12.463 12.463 0 0 1-2.41-7.34V45.131c.006-2.642.85-5.214 2.411-7.34a12.345 12.345 0 0 1 6.264-4.482c8.501-2.586 18.317-3.95 28.382-3.95 10.065 0 19.877 1.371 28.382 3.96a12.35 12.35 0 0 1 6.262 4.486 12.46 12.46 0 0 1 2.409 7.34V59.28a12.453 12.453 0 0 1-2.41 7.341 12.343 12.343 0 0 1-6.265 4.482c-8.486 2.585-18.317 3.949-28.382 3.949Z",
5207
+ fill: "#E6E6E6"
5208
+ }), /*#__PURE__*/React.createElement("path", {
5209
+ d: "M100.863 15.992h-5.81v1.293h5.81v-1.293Z",
5210
+ fill: "#F2F2F2"
5211
+ }), /*#__PURE__*/React.createElement("path", {
5212
+ d: "M76.472 66.05c4.327 0 7.834-6.2 7.834-13.846 0-7.647-3.507-13.846-7.834-13.846-4.326 0-7.833 6.2-7.833 13.846s3.507 13.845 7.833 13.845Z",
5213
+ fill: "#1A1A1A"
5214
+ }), /*#__PURE__*/React.createElement("path", {
5215
+ d: "M77.844 52.766c1.743 0 3.157-2.088 3.157-4.664 0-2.577-1.414-4.665-3.157-4.665-1.744 0-3.157 2.088-3.157 4.665 0 2.576 1.413 4.664 3.157 4.664Z",
5216
+ fill: "#fff"
5217
+ }), /*#__PURE__*/React.createElement("path", {
5218
+ d: "M118.662 66.057c4.326 0 7.834-6.2 7.834-13.846s-3.508-13.845-7.834-13.845c-4.327 0-7.834 6.199-7.834 13.845 0 7.647 3.507 13.846 7.834 13.846Z",
5219
+ fill: "#1A1A1A"
5220
+ }), /*#__PURE__*/React.createElement("path", {
5221
+ d: "M120.032 52.774c1.744 0 3.157-2.089 3.157-4.665s-1.413-4.665-3.157-4.665c-1.743 0-3.157 2.089-3.157 4.665s1.414 4.665 3.157 4.665Z",
5222
+ fill: "#fff"
5223
+ }), /*#__PURE__*/React.createElement("path", {
5224
+ d: "M92.674 63.11a10.286 10.286 0 0 0 7.949 1.095 13.2 13.2 0 0 0 2.623-1.118.738.738 0 0 1 1.035.639.748.748 0 0 1-.119.453c-2.224 2.82-6.474 3.625-9.672 2.12a7.284 7.284 0 0 1-2.75-2.12.748.748 0 0 1 .465-1.139.738.738 0 0 1 .469.054v.015Z",
5225
+ fill: "#999"
5226
+ }), /*#__PURE__*/React.createElement("path", {
5227
+ d: "M55.773 64.004c4.349 0 7.874-5.285 7.874-11.804s-3.525-11.804-7.874-11.804-7.875 5.285-7.875 11.804c0 6.52 3.526 11.804 7.875 11.804Zm84.17.015c4.349 0 7.874-5.285 7.874-11.804 0-6.52-3.525-11.804-7.874-11.804s-7.875 5.285-7.875 11.804 3.526 11.804 7.875 11.804Z",
5228
+ fill: "#3690EA"
5229
+ }), /*#__PURE__*/React.createElement("path", {
5230
+ d: "M95.008 14.315c-.115-.488 6.548-.932 5.815.246v.771c0 .745.033 1.51.037 2.262.003.752.033 1.594.04 2.392.282.592-6.474.935-5.818-.116v-.67c-.014-1.629-.055-3.257-.074-4.885Z",
5231
+ fill: "#F2F2F2"
5232
+ }), /*#__PURE__*/React.createElement("path", {
5233
+ d: "M97.962 29.036c7.273 0 13.17-2.224 13.17-4.967 0-2.743-5.897-4.966-13.17-4.966-7.274 0-13.17 2.223-13.17 4.966 0 2.743 5.896 4.967 13.17 4.967Z",
5234
+ fill: "#B3B3B3"
5235
+ }), /*#__PURE__*/React.createElement("path", {
5236
+ d: "M97.962 16.55c4.545 0 8.23-3.705 8.23-8.275S102.507 0 97.962 0c-4.546 0-8.23 3.705-8.23 8.275s3.684 8.275 8.23 8.275Z",
5237
+ fill: "#3690EA"
5238
+ }), /*#__PURE__*/React.createElement("path", {
5239
+ d: "M141.607 59.283V45.147a19.038 19.038 0 0 0-3.687-11.301 18.872 18.872 0 0 0-9.653-6.874c-8.838-2.69-19.203-4.24-30.29-4.244-11.088-.004-21.452 1.546-30.29 4.233a18.871 18.871 0 0 0-9.668 6.866 19.041 19.041 0 0 0-3.699 11.305v14.132a19.03 19.03 0 0 0 3.685 11.303 18.86 18.86 0 0 0 9.656 6.872c8.841 2.694 19.206 4.244 30.29 4.244 11.083 0 21.452-1.542 30.294-4.233a18.858 18.858 0 0 0 9.666-6.863 19.028 19.028 0 0 0 3.696-11.304Z",
5240
+ fill: "#F2F2F2"
5241
+ }), /*#__PURE__*/React.createElement("path", {
5242
+ d: "M97.954 75.051c-10.068 0-19.88-1.371-28.381-3.957a12.353 12.353 0 0 1-6.262-4.485 12.463 12.463 0 0 1-2.41-7.34V45.131c.006-2.642.85-5.214 2.411-7.34a12.345 12.345 0 0 1 6.264-4.482c8.501-2.586 18.317-3.95 28.382-3.95 10.065 0 19.877 1.371 28.382 3.96a12.35 12.35 0 0 1 6.262 4.486 12.46 12.46 0 0 1 2.409 7.34V59.28a12.453 12.453 0 0 1-2.41 7.341 12.343 12.343 0 0 1-6.265 4.482c-8.486 2.585-18.317 3.949-28.382 3.949Zm2.909-59.059h-5.81v1.293h5.81v-1.293Z",
5243
+ fill: "#E6E6E6"
5244
+ }), /*#__PURE__*/React.createElement("path", {
5245
+ d: "M76.472 66.05c4.327 0 7.834-6.2 7.834-13.846 0-7.647-3.507-13.846-7.834-13.846-4.326 0-7.833 6.2-7.833 13.846s3.507 13.845 7.833 13.845Z",
5246
+ fill: "#1A1A1A"
5247
+ }), /*#__PURE__*/React.createElement("path", {
5248
+ d: "M77.844 52.766c1.743 0 3.157-2.088 3.157-4.664 0-2.577-1.414-4.665-3.157-4.665-1.744 0-3.157 2.088-3.157 4.665 0 2.576 1.413 4.664 3.157 4.664Z",
5249
+ fill: "#fff"
5250
+ }), /*#__PURE__*/React.createElement("path", {
5251
+ d: "M118.662 66.057c4.326 0 7.834-6.2 7.834-13.846s-3.508-13.845-7.834-13.845c-4.327 0-7.834 6.199-7.834 13.845 0 7.647 3.507 13.846 7.834 13.846Z",
5252
+ fill: "#1A1A1A"
5253
+ }), /*#__PURE__*/React.createElement("path", {
5254
+ d: "M120.032 52.774c1.744 0 3.157-2.089 3.157-4.665s-1.413-4.665-3.157-4.665c-1.743 0-3.157 2.089-3.157 4.665s1.414 4.665 3.157 4.665Z",
5255
+ fill: "#fff"
5256
+ }), /*#__PURE__*/React.createElement("path", {
5257
+ d: "M92.674 63.11a10.286 10.286 0 0 0 7.949 1.095 13.2 13.2 0 0 0 2.623-1.118.738.738 0 0 1 1.035.639.748.748 0 0 1-.119.453c-2.224 2.82-6.474 3.625-9.672 2.12a7.284 7.284 0 0 1-2.75-2.12.748.748 0 0 1 .465-1.139.738.738 0 0 1 .469.054v.015Z",
5258
+ fill: "#999"
5259
+ }), /*#__PURE__*/React.createElement("path", {
5260
+ d: "M101.117 9.562a3.035 3.035 0 0 0 3.027-3.043 3.035 3.035 0 0 0-3.027-3.043A3.035 3.035 0 0 0 98.09 6.52a3.035 3.035 0 0 0 3.027 3.043ZM51.578 54.84c.801 0 1.45-1.64 1.45-3.66 0-2.023-.649-3.662-1.45-3.662-.802 0-1.451 1.64-1.451 3.661 0 2.022.65 3.66 1.45 3.66Zm93.429 0c.802 0 1.451-1.64 1.451-3.66 0-2.023-.649-3.662-1.451-3.662-.801 0-1.45 1.64-1.45 3.661 0 2.022.649 3.66 1.45 3.66Z",
5261
+ fill: "#4BAAF7"
5262
+ }), /*#__PURE__*/React.createElement("g", {
5263
+ clipPath: `url(#${id}-b)`
5264
+ }, /*#__PURE__*/React.createElement("path", {
5265
+ d: "M52.39 160.841h-2.919a1.774 1.774 0 0 1-1.766-1.782v-7.334h9.035l-2.677 7.911a1.766 1.766 0 0 1-1.671 1.206l-.001-.001Zm91.774 0h2.919c.977 0 1.767-.799 1.767-1.782v-7.334h-9.036l2.677 7.911a1.767 1.767 0 0 0 1.672 1.206l.001-.001Z",
5266
+ fill: "#6D4932"
5267
+ }), /*#__PURE__*/React.createElement("path", {
5268
+ d: "M163.181 108.015H33.375c-2.37 0-4.291 1.479-4.291 3.305v2.216c0 1.825 1.921 3.305 4.29 3.305h129.807c2.369 0 4.29-1.48 4.29-3.305v-2.216c0-1.826-1.921-3.305-4.29-3.305Z",
5269
+ fill: "#A87B5D"
5270
+ }), /*#__PURE__*/React.createElement("path", {
5271
+ d: "M38.282 116.841h119.992v33.16c0 1.648-1.554 2.985-3.469 2.985H41.752c-1.915 0-3.468-1.337-3.468-2.985v-33.16h-.002Z",
5272
+ fill: "#916A50"
5273
+ }), /*#__PURE__*/React.createElement("path", {
5274
+ opacity: ".3",
5275
+ d: "M131.002 109.794h-97.18a.996.996 0 0 0-.992 1.001c0 .552.444 1 .992 1h97.18a.996.996 0 0 0 .991-1 .996.996 0 0 0-.991-1.001Zm30.849 0h-24.24a.996.996 0 0 0-.992 1.001c0 .552.444 1 .992 1h24.24a.996.996 0 0 0 .992-1 .996.996 0 0 0-.992-1.001Z",
5276
+ fill: "#D4B097"
5277
+ })), /*#__PURE__*/React.createElement("g", {
5278
+ clipPath: `url(#${id}-c)`
5279
+ }, /*#__PURE__*/React.createElement("path", {
5280
+ d: "M151.367 97.536h2.894c1.6 0 2.895 1.307 2.895 2.913a2.906 2.906 0 0 1-2.895 2.914h-2.894v-5.827Z",
5281
+ strokeWidth: "6",
5282
+ strokeMiterlimit: "10",
5283
+ stroke: `url(#${id}-d)`
5284
+ }), /*#__PURE__*/React.createElement("path", {
5285
+ d: "M135.876 93.304h17.017a.6.6 0 0 1 .597.602v10.166c0 1.942-1.566 3.522-3.499 3.522h-11.214c-1.933 0-3.499-1.58-3.499-3.522V93.906a.6.6 0 0 1 .598-.602Z",
5286
+ fill: `url(#${id}-e)`
5287
+ })), /*#__PURE__*/React.createElement("path", {
5288
+ d: "m37.492 78.174 38.863-6.725a3.453 3.453 0 0 1 3.455 3.45v30.087H34.04V81.623a3.452 3.452 0 0 1 3.452-3.45Z",
5289
+ fill: `url(#${id}-f)`
5290
+ }), /*#__PURE__*/React.createElement("path", {
5291
+ d: "M34.1 108.015v-3.363h57.697v3.363H34.1Z",
5292
+ fill: `url(#${id}-g)`
5293
+ }), /*#__PURE__*/React.createElement("path", {
5294
+ d: "M79.673 108.015v-3.363h12.124v3.363H79.673Z",
5295
+ fill: `url(#${id}-h)`
5296
+ })), /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("linearGradient", {
5297
+ id: `${id}-d`,
5298
+ x1: "150.254",
5299
+ y1: "100.449",
5300
+ x2: "158.273",
5301
+ y2: "100.449",
5302
+ gradientUnits: "userSpaceOnUse"
5303
+ }, /*#__PURE__*/React.createElement("stop", {
5304
+ stopColor: "#FEFEFE"
5305
+ }), /*#__PURE__*/React.createElement("stop", {
5306
+ offset: "1",
5307
+ stopColor: "#fff"
5308
+ })), /*#__PURE__*/React.createElement("linearGradient", {
5309
+ id: `${id}-e`,
5310
+ x1: "132.629",
5311
+ y1: "100.449",
5312
+ x2: "155.32",
5313
+ y2: "100.449",
5314
+ gradientUnits: "userSpaceOnUse"
5315
+ }, /*#__PURE__*/React.createElement("stop", {
5316
+ stopColor: "#FEFEFE"
5317
+ }), /*#__PURE__*/React.createElement("stop", {
5318
+ offset: "1",
5319
+ stopColor: "#F3F3F3"
5320
+ })), /*#__PURE__*/React.createElement("linearGradient", {
5321
+ id: `${id}-f`,
5322
+ x1: "56.925",
5323
+ y1: "45.291",
5324
+ x2: "56.925",
5325
+ y2: "93.076",
5326
+ gradientUnits: "userSpaceOnUse"
5327
+ }, /*#__PURE__*/React.createElement("stop", {
5328
+ stopColor: "#FEFEFE"
5329
+ }), /*#__PURE__*/React.createElement("stop", {
5330
+ offset: "1",
5331
+ stopColor: "#D1D6E7"
5332
+ })), /*#__PURE__*/React.createElement("linearGradient", {
5333
+ id: `${id}-g`,
5334
+ x1: "62.684",
5335
+ y1: "108.015",
5336
+ x2: "62.684",
5337
+ y2: "104.85",
5338
+ gradientUnits: "userSpaceOnUse"
5339
+ }, /*#__PURE__*/React.createElement("stop", {
5340
+ stopColor: "#D2D6E8"
5341
+ }), /*#__PURE__*/React.createElement("stop", {
5342
+ offset: ".726",
5343
+ stopColor: "#D1D6E7"
5344
+ })), /*#__PURE__*/React.createElement("linearGradient", {
5345
+ id: `${id}-h`,
5346
+ x1: "85.68",
5347
+ y1: "108.015",
5348
+ x2: "85.68",
5349
+ y2: "104.85",
5350
+ gradientUnits: "userSpaceOnUse"
5351
+ }, /*#__PURE__*/React.createElement("stop", {
5352
+ stopColor: "#D8DDF1"
5353
+ }), /*#__PURE__*/React.createElement("stop", {
5354
+ offset: ".726",
5355
+ stopColor: "#E2E6F6"
5356
+ })), /*#__PURE__*/React.createElement("clipPath", {
5357
+ id: `${id}-a`
5358
+ }, /*#__PURE__*/React.createElement("path", {
5359
+ fill: "#fff",
5360
+ transform: "translate(12.006)",
5361
+ d: "M0 0h172v174H0z"
5362
+ })), /*#__PURE__*/React.createElement("clipPath", {
5363
+ id: `${id}-b`
5364
+ }, /*#__PURE__*/React.createElement("path", {
5365
+ fill: "#fff",
5366
+ transform: "translate(29.084 105.073)",
5367
+ d: "M0 0h138.387v68.927H0z"
5368
+ })), /*#__PURE__*/React.createElement("clipPath", {
5369
+ id: `${id}-c`
5370
+ }, /*#__PURE__*/React.createElement("path", {
5371
+ fill: "#fff",
5372
+ transform: "translate(135.278 93.304)",
5373
+ d: "M0 0h22.995v14.29H0z"
5374
+ }))));
5375
+ }
5376
+
5377
+ var styles$f = {"blank_state":"blank_state-wMOWN","image":"image-uy0Fd"};
5378
+
5379
+ function BlankState$1({
5380
+ image,
5381
+ role,
5382
+ subtitle,
5383
+ title
5384
+ }) {
5385
+ return /*#__PURE__*/React.createElement(tapestry.Flex, {
5386
+ role: role,
5387
+ className: styles$f.blank_state,
5388
+ direction: "column",
5389
+ align: "center",
5390
+ gap: 3
5391
+ }, /*#__PURE__*/React.createElement(tapestry.Flex, {
5392
+ className: styles$f.image
5393
+ }, image), /*#__PURE__*/React.createElement(tapestry.Flex, {
5394
+ direction: "column",
5395
+ align: "center",
5396
+ gap: 1
5397
+ }, /*#__PURE__*/React.createElement("h2", null, title), /*#__PURE__*/React.createElement("p", null, subtitle)));
5398
+ }
4213
5399
 
4214
5400
  function EndOfResultsObserver({
4215
5401
  onVisible
@@ -4229,39 +5415,119 @@ function EndOfResultsObserver({
4229
5415
 
4230
5416
  const resultId = (listboxId, index) => `${listboxId}-result-${index}`;
4231
5417
 
4232
- var styles$c = {"result":"result-Thq2C"};
5418
+ var styles$e = {"result":"result-Thq2C","title":"title-KYUEn","subtitle":"subtitle-R2haq","image":"image-KVDor","avatar":"avatar-6Gh62","photo":"photo-FZR3Q","badge":"badge-trUKt"};
4233
5419
 
4234
5420
  function SearchResult({
5421
+ category,
5422
+ describedBy,
5423
+ headingAbove,
4235
5424
  highlighted,
4236
5425
  id,
5426
+ imageUrl,
4237
5427
  onHighlight,
5428
+ onOpen,
5429
+ product,
4238
5430
  subtitle,
4239
5431
  title,
4240
5432
  url
4241
5433
  }) {
4242
5434
  const ref = React.useRef(null);
5435
+ // A hovered result is already under the pointer, and scrolling it clear of
5436
+ // the panel's scroll padding would slide the list out from under the mouse.
5437
+ const highlightedByPointer = React.useRef(false);
4243
5438
  React.useEffect(() => {
4244
- var _a;
4245
- if (highlighted) (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({
4246
- block: "nearest"
4247
- });
4248
- }, [highlighted]);
5439
+ var _a, _b;
5440
+ if (!highlighted) return;
5441
+ if (highlightedByPointer.current) {
5442
+ highlightedByPointer.current = false;
5443
+ } else {
5444
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({
5445
+ block: "nearest"
5446
+ });
5447
+ // Scrolling up to a section's first result leaves its heading cut off
5448
+ // above it, so bring that in too. Scrolling down, it's already in view.
5449
+ if (headingAbove) {
5450
+ (_b = document.getElementById(headingAbove)) === null || _b === void 0 ? void 0 : _b.scrollIntoView({
5451
+ block: "nearest"
5452
+ });
5453
+ }
5454
+ }
5455
+ }, [headingAbove, highlighted]);
5456
+ const highlightFromPointer = () => {
5457
+ if (highlighted) return;
5458
+ highlightedByPointer.current = true;
5459
+ onHighlight();
5460
+ };
5461
+ // Closes search before the page goes, so coming back to it doesn't find
5462
+ // search still open. Clicks that open a new tab or window leave it open.
5463
+ const openFromClick = event => {
5464
+ if (event.button !== 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;
5465
+ onOpen();
5466
+ };
4249
5467
  // Focus stays in the search input, which points at the highlighted result
4250
5468
  // with aria-activedescendant, so results are kept out of the tab order.
4251
5469
  // Mouse move rather than enter: arrowing scrolls results under a resting
4252
5470
  // pointer, and that shouldn't steal the highlight.
4253
- return /*#__PURE__*/React.createElement("a", {
4254
- "aria-selected": highlighted,
4255
- className: styles$c.result,
4256
- href: url,
4257
- id: id,
4258
- onMouseMove: onHighlight,
4259
- ref: ref,
4260
- role: "option",
4261
- tabIndex: -1
4262
- }, /*#__PURE__*/React.createElement("div", null, title), /*#__PURE__*/React.createElement("div", null, subtitle));
5471
+ // Results open with a full page load, like Enter does, rather than through
5472
+ // the product's router. Their URLs can go through server redirects, like
5473
+ // People's staff URLs, that Turbo would follow with fetch or prefetch on
5474
+ // hover, and they should open the same way in every product.
5475
+ return (
5476
+ /*#__PURE__*/
5477
+ // Named by the title alone, so screen readers say "Ada Lovelace" rather
5478
+ // than the whole row. The section and subtitle are read after a pause.
5479
+ React.createElement("a", {
5480
+ "aria-describedby": [describedBy, subtitle && `${id}-subtitle`].filter(Boolean).join(" ") || undefined,
5481
+ "aria-labelledby": title ? `${id}-title` : undefined,
5482
+ "aria-selected": highlighted,
5483
+ className: styles$e.result,
5484
+ "data-turbo": "false",
5485
+ href: url,
5486
+ id: id,
5487
+ onClick: openFromClick,
5488
+ onMouseMove: highlightFromPointer,
5489
+ ref: ref,
5490
+ role: "option",
5491
+ tabIndex: -1
5492
+ }, /*#__PURE__*/React.createElement(ResultImage, {
5493
+ category: category,
5494
+ imageUrl: imageUrl,
5495
+ product: product
5496
+ }), /*#__PURE__*/React.createElement("span", {
5497
+ className: styles$e.title,
5498
+ id: `${id}-title`
5499
+ }, title), /*#__PURE__*/React.createElement("span", {
5500
+ className: styles$e.subtitle,
5501
+ id: `${id}-subtitle`
5502
+ }, subtitle))
5503
+ );
5504
+ }
5505
+ // A person's photo or the result's own image, badged with its product, or
5506
+ // just the product's logomark when there's no image.
5507
+ function ResultImage({
5508
+ category,
5509
+ imageUrl,
5510
+ product
5511
+ }) {
5512
+ const icon = size => isProductIconSlug(product) ? (/*#__PURE__*/React.createElement(ProductIcon, {
5513
+ size: size,
5514
+ slug: product
5515
+ })) : null;
5516
+ return /*#__PURE__*/React.createElement("span", {
5517
+ "aria-hidden": true,
5518
+ className: styles$e.image
5519
+ }, imageUrl ? (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("img", {
5520
+ alt: "",
5521
+ className: category === "profile" ? styles$e.avatar : styles$e.photo,
5522
+ loading: "lazy",
5523
+ src: imageUrl
5524
+ }), /*#__PURE__*/React.createElement("span", {
5525
+ className: styles$e.badge
5526
+ }, icon(16)))) : icon("100%"));
4263
5527
  }
4264
5528
 
5529
+ var styles$d = {"heading":"heading-LioUF","group":"group-cKChg"};
5530
+
4265
5531
  // Sections with a heading render as labelled groups; ones without render
4266
5532
  // their items straight into the listbox. Indexes run across every section.
4267
5533
  function ResultListbox({
@@ -4271,16 +5537,27 @@ function ResultListbox({
4271
5537
  label,
4272
5538
  labelledBy,
4273
5539
  onHighlight,
5540
+ onOpen,
4274
5541
  sections
4275
5542
  }) {
4276
5543
  let index = 0;
4277
- const renderItem = item => {
5544
+ // With aria-activedescendant, screen readers don't reliably announce the
5545
+ // group a highlighted option is in, so each option names its heading too.
5546
+ const renderItem = (item, indexInSection, headingId) => {
4278
5547
  const itemIndex = index++;
5548
+ // Sections without a heading of their own sit under the listbox's label.
5549
+ const headingAbove = indexInSection > 0 ? undefined : headingId !== null && headingId !== void 0 ? headingId : itemIndex === 0 ? labelledBy : undefined;
4279
5550
  return /*#__PURE__*/React.createElement(SearchResult, {
5551
+ category: item.category,
5552
+ describedBy: headingId,
5553
+ headingAbove: headingAbove,
4280
5554
  highlighted: itemIndex === highlightedIndex,
4281
5555
  id: resultId(id, itemIndex),
5556
+ imageUrl: item.imageUrl,
4282
5557
  key: item.key,
4283
5558
  onHighlight: () => onHighlight(itemIndex),
5559
+ onOpen: onOpen,
5560
+ product: item.product,
4284
5561
  subtitle: item.subtitle,
4285
5562
  title: item.title,
4286
5563
  url: item.url
@@ -4296,16 +5573,18 @@ function ResultListbox({
4296
5573
  if (section.heading === undefined) {
4297
5574
  return /*#__PURE__*/React.createElement(React.Fragment, {
4298
5575
  key: section.key
4299
- }, section.items.map(renderItem));
5576
+ }, section.items.map((item, itemIndex) => renderItem(item, itemIndex)));
4300
5577
  }
4301
5578
  const headingId = `${id}-group-${sectionIndex}`;
4302
5579
  return /*#__PURE__*/React.createElement("div", {
4303
5580
  "aria-labelledby": headingId,
5581
+ className: styles$d.group,
4304
5582
  key: section.key,
4305
5583
  role: "group"
4306
5584
  }, /*#__PURE__*/React.createElement("div", {
5585
+ className: styles$d.heading,
4307
5586
  id: headingId
4308
- }, section.heading), section.items.map(renderItem));
5587
+ }, section.heading), section.items.map((item, itemIndex) => renderItem(item, itemIndex, headingId)));
4309
5588
  }));
4310
5589
  }
4311
5590
 
@@ -4319,9 +5598,14 @@ function RecentlyVisited({
4319
5598
  }) {
4320
5599
  const headingId = `${navigation.id}-heading`;
4321
5600
  if (items.length === 0 && !hasMore && !loading) {
4322
- return /*#__PURE__*/React.createElement("p", null, "Pages you visit will show up here.");
5601
+ return /*#__PURE__*/React.createElement(BlankState$1, {
5602
+ image: /*#__PURE__*/React.createElement(BlankStateRecentlyVisited, null),
5603
+ subtitle: "Pages you visit will show up here.",
5604
+ title: "Recently visited"
5605
+ });
4323
5606
  } else {
4324
5607
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
5608
+ className: styles$d.heading,
4325
5609
  id: headingId
4326
5610
  }, "Recently visited"), /*#__PURE__*/React.createElement(ResultListbox, {
4327
5611
  labelledBy: headingId,
@@ -4337,6 +5621,8 @@ function RecentlyVisited({
4337
5621
  }
4338
5622
  }
4339
5623
 
5624
+ var styles$c = {"row":"row-5P7UQ","header":"header-sXEyG","closeButton":"closeButton-rPJJV","input":"input-YQkTC","clearButton":"clearButton-9Yh9w"};
5625
+
4340
5626
  // A combobox: focus stays here while aria-activedescendant points screen
4341
5627
  // readers at the highlighted result in the listbox it controls.
4342
5628
  function SearchInput({
@@ -4345,29 +5631,441 @@ function SearchInput({
4345
5631
  inputRef,
4346
5632
  listboxId,
4347
5633
  onChange,
5634
+ onClose,
4348
5635
  onFocus,
4349
5636
  onKeyDown,
4350
5637
  value
4351
5638
  }) {
4352
- return /*#__PURE__*/React.createElement("input", {
5639
+ const {
5640
+ focusProps
5641
+ } = useKeyboardFocus({
5642
+ onFocus: (event, keyboard) => {
5643
+ // Tabbing in selects the whole term, which the next keystroke would
5644
+ // replace. Put the cursor after it instead, to keep typing. The
5645
+ // browser selects after the focus event, so this waits a frame and
5646
+ // only undoes that select-all: typing on the tabs moves focus here by
5647
+ // script, which keeps the cursor, and the keystroke may already be in.
5648
+ if (keyboard) {
5649
+ const input = event.currentTarget;
5650
+ requestAnimationFrame(() => {
5651
+ const length = input.value.length;
5652
+ const selectedAll = length > 0 && input.selectionStart === 0 && input.selectionEnd === length;
5653
+ if (document.activeElement !== input || !selectedAll) return;
5654
+ input.setSelectionRange(length, length);
5655
+ });
5656
+ }
5657
+ onFocus();
5658
+ }
5659
+ });
5660
+ return /*#__PURE__*/React.createElement("div", {
5661
+ className: styles$c.row
5662
+ }, /*#__PURE__*/React.createElement("label", {
5663
+ className: styles$c.header,
5664
+ id: "topbar_product_search_label"
5665
+ }, /*#__PURE__*/React.createElement(Icon, {
5666
+ name: "general.search",
5667
+ size: 20,
5668
+ theme: "--t-icon-color-dim"
5669
+ }), /*#__PURE__*/React.createElement("input", {
4353
5670
  "aria-activedescendant": highlightedIndex === null ? undefined : resultId(listboxId, highlightedIndex),
4354
5671
  "aria-autocomplete": "list",
4355
5672
  "aria-controls": expanded ? listboxId : undefined,
4356
5673
  "aria-expanded": expanded,
4357
5674
  "aria-label": "Search",
4358
5675
  autoFocus: true,
5676
+ className: styles$c.input,
5677
+ id: "product_search",
4359
5678
  onChange: event => onChange(event.target.value),
4360
- onFocus: onFocus,
4361
5679
  onKeyDown: onKeyDown,
4362
5680
  placeholder: "Search",
4363
5681
  ref: inputRef,
4364
5682
  role: "combobox",
4365
5683
  type: "search",
4366
- value: value
4367
- });
5684
+ value: value,
5685
+ ...focusProps
5686
+ }), !onClose && value !== "" && (/*#__PURE__*/React.createElement("button", {
5687
+ "aria-label": "Clear search",
5688
+ className: styles$c.clearButton,
5689
+ onClick: () => {
5690
+ var _a;
5691
+ onChange("");
5692
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
5693
+ },
5694
+ tabIndex: -1,
5695
+ type: "button"
5696
+ }, /*#__PURE__*/React.createElement("svg", {
5697
+ "aria-hidden": true,
5698
+ viewBox: "0 0 20 20"
5699
+ }, /*#__PURE__*/React.createElement("circle", {
5700
+ cx: "10",
5701
+ cy: "10",
5702
+ r: "10"
5703
+ }), /*#__PURE__*/React.createElement("path", {
5704
+ d: "M6.5 6.5l7 7m0 -7l-7 7"
5705
+ }))))), onClose && (/*#__PURE__*/React.createElement(tapestry.IconButton, {
5706
+ "aria-label": "Close search",
5707
+ className: styles$c.closeButton,
5708
+ icon: /*#__PURE__*/React.createElement(Icon, {
5709
+ name: "general.x",
5710
+ theme: "--t-icon-color-dim"
5711
+ }),
5712
+ kind: "ghost",
5713
+ onClick: onClose,
5714
+ size: "md"
5715
+ })));
4368
5716
  }
4369
5717
 
4370
- var styles$b = {"visuallyHidden":"visuallyHidden-S9VG5"};
5718
+ function BlankStateError(props) {
5719
+ const id = useInstanceId("blank-state-error");
5720
+ return /*#__PURE__*/React.createElement("svg", {
5721
+ viewBox: "0 0 197 158",
5722
+ fill: "none",
5723
+ "aria-hidden": "true",
5724
+ focusable: "false",
5725
+ ...props
5726
+ }, /*#__PURE__*/React.createElement("path", {
5727
+ d: "M139.863 26.119c10.938 10.028 21.777 20.154 32.912 30.084 8.376 7.373 21.975 15.828 23.157 28.02.592 6.095-2.167 11.993-5.321 17.204-24.635 40.8-81.098 67.148-127.412 48.862-30.646-12.093-76.172-47.387-59.716-85.041C19.348 28.87 68.323 10.192 87.44 7.538c21.876-4.621 34.883 2.457 52.423 18.58Z",
5728
+ fill: "currentColor"
5729
+ }), /*#__PURE__*/React.createElement("g", {
5730
+ clipPath: `url(#${id}-a)`
5731
+ }, /*#__PURE__*/React.createElement("path", {
5732
+ d: "M76.296 111.268c-2.63 0-5.95-.883-9.822-3.622a3.39 3.39 0 0 1-1.375-2.212 3.375 3.375 0 0 1 .603-2.529 3.44 3.44 0 0 1 4.777-.767c5.305 3.786 7.949 1.838 8.056 1.767a1.23 1.23 0 0 0-.094.08l4.62 5.004a10.434 10.434 0 0 1-6.765 2.279Z",
5733
+ fill: "#4D4D4D"
5734
+ }), /*#__PURE__*/React.createElement("path", {
5735
+ d: "M83.313 102.999a2.751 2.751 0 0 0-2.882-2.611 2.747 2.747 0 0 0-2.63 2.86l.399 8.688a2.751 2.751 0 0 0 2.882 2.611 2.746 2.746 0 0 0 2.63-2.86l-.399-8.688Z",
5736
+ fill: "gray"
5737
+ }), /*#__PURE__*/React.createElement("path", {
5738
+ d: "M119.428 111.268a10.438 10.438 0 0 1-6.751-2.292l4.619-5.005a1.387 1.387 0 0 0-.093-.079c.106.084 2.75 2.032 8.055-1.767a3.439 3.439 0 0 1 4.777.766 3.378 3.378 0 0 1-.772 4.742c-3.885 2.774-7.205 3.635-9.835 3.635Z",
5739
+ fill: "#4D4D4D"
5740
+ }), /*#__PURE__*/React.createElement("path", {
5741
+ d: "M101.658 18.962H94.68v1.533h6.978v-1.533Z",
5742
+ fill: "#F2F2F2"
5743
+ }), /*#__PURE__*/React.createElement("path", {
5744
+ d: "M91.823 74.82a12.502 12.502 0 0 0 9.546 1.299 16.005 16.005 0 0 0 3.151-1.326.894.894 0 0 1 1.035.24.882.882 0 0 1 .064 1.053c-2.67 3.345-7.775 4.294-11.62 2.514a8.803 8.803 0 0 1-3.302-2.513.879.879 0 0 1 .561-1.353.887.887 0 0 1 .565.068v.017Z",
5745
+ fill: "#999"
5746
+ }), /*#__PURE__*/React.createElement("path", {
5747
+ d: "M88.236 143.397a3.433 3.433 0 0 1-2.304-.891 3.383 3.383 0 0 1-1.096-2.201c-.636-6.788 4.237-16.369 4.798-17.442a3.41 3.41 0 0 1 2-1.643 3.442 3.442 0 0 1 2.586.227 3.398 3.398 0 0 1 1.68 1.965 3.368 3.368 0 0 1-.196 2.569c-1.75 3.37-4.402 10.066-4.059 13.693a3.38 3.38 0 0 1-.773 2.479 3.43 3.43 0 0 1-2.31 1.213l-.326.031Z",
5748
+ fill: "#4D4D4D"
5749
+ }), /*#__PURE__*/React.createElement("path", {
5750
+ d: "M91.645 132.708c3.972 0 7.192-3.195 7.192-7.138 0-3.942-3.22-7.137-7.192-7.137s-7.191 3.195-7.191 7.137c0 3.943 3.22 7.138 7.191 7.138Z",
5751
+ fill: "gray"
5752
+ }), /*#__PURE__*/React.createElement("path", {
5753
+ d: "M77.765 152.218h14.134v4.417c0 .351-.141.689-.391.937-.25.249-.59.388-.944.388H75.33a1.34 1.34 0 0 1-.945-.388 1.32 1.32 0 0 1-.39-.937v-.671c0-.997.398-1.953 1.109-2.658a3.801 3.801 0 0 1 2.678-1.101l-.018.013Z",
5754
+ fill: "#333"
5755
+ }), /*#__PURE__*/React.createElement("path", {
5756
+ d: "M88.548 156.141s9.697.141 7.592-9.797c-2.105-9.939-14.641-18.198-18.295-7.191-3.654 11.007-1.695 18.056 10.703 16.988Z",
5757
+ fill: "#F2F2F2"
5758
+ }), /*#__PURE__*/React.createElement("path", {
5759
+ d: "M109.077 143.402h-.325a3.427 3.427 0 0 1-2.313-1.216 3.38 3.38 0 0 1-.771-2.481c.342-3.627-2.305-10.323-4.054-13.693a3.371 3.371 0 0 1-.11-2.514c.29-.821.887-1.5 1.666-1.897a3.44 3.44 0 0 1 2.525-.236 3.413 3.413 0 0 1 1.993 1.555c.556 1.069 5.429 10.654 4.789 17.443a3.383 3.383 0 0 1-1.113 2.167 3.426 3.426 0 0 1-2.287.872Z",
5760
+ fill: "#4D4D4D"
5761
+ }), /*#__PURE__*/React.createElement("path", {
5762
+ d: "M105.672 132.708c3.972 0 7.192-3.195 7.192-7.138 0-3.942-3.22-7.137-7.192-7.137s-7.191 3.195-7.191 7.137c0 3.943 3.219 7.138 7.191 7.138Z",
5763
+ fill: "gray"
5764
+ }), /*#__PURE__*/React.createElement("path", {
5765
+ d: "m121.972 158.007-15.22-.003c-.354 0-.693-.139-.943-.388a1.317 1.317 0 0 1-.391-.937v-4.417l14.139.003c1.004 0 1.967.396 2.678 1.101a3.745 3.745 0 0 1 1.108 2.658v.671c0 .352-.141.689-.391.937-.25.249-.59.388-.944.388l-.036-.013Z",
5766
+ fill: "#333"
5767
+ }), /*#__PURE__*/React.createElement("path", {
5768
+ d: "M108.769 156.145s-9.701.137-7.587-9.801c2.114-9.939 14.645-18.19 18.295-7.187 3.649 11.003 1.682 18.061-10.708 16.988Z",
5769
+ fill: "#F2F2F2"
5770
+ }), /*#__PURE__*/React.createElement("path", {
5771
+ d: "M112.002 111.683c-.07 1.51 1.108 2.791 2.63 2.86a2.75 2.75 0 0 0 2.882-2.611l.399-8.688a2.746 2.746 0 0 0-2.63-2.86 2.75 2.75 0 0 0-2.882 2.611l-.399 8.688Z",
5772
+ fill: "gray"
5773
+ }), /*#__PURE__*/React.createElement("path", {
5774
+ d: "M47.508 75.88c5.223 0 9.457-6.265 9.457-13.994 0-7.728-4.234-13.993-9.457-13.993-5.223 0-9.457 6.265-9.457 13.993 0 7.729 4.234 13.993 9.457 13.993Zm101.082.017c5.223 0 9.457-6.265 9.457-13.993 0-7.728-4.234-13.993-9.457-13.993-5.223 0-9.457 6.265-9.457 13.993 0 7.728 4.234 13.993 9.457 13.993Z",
5775
+ fill: "#3690EA"
5776
+ }), /*#__PURE__*/React.createElement("path", {
5777
+ d: "M94.622 16.97c-.133-.574 7.868-1.1 6.987.296 0 .305 0 .61.022.914 0 .884.04 1.767.04 2.681 0 .915.041 1.886.054 2.832.334.706-7.78 1.113-6.991-.133v-.795c-.036-1.935-.09-3.86-.112-5.795Z",
5778
+ fill: "#F2F2F2"
5779
+ }), /*#__PURE__*/React.createElement("path", {
5780
+ d: "M98.174 34.426c8.734 0 15.816-2.636 15.816-5.888s-7.082-5.888-15.816-5.888c-8.736 0-15.817 2.637-15.817 5.888 0 3.252 7.082 5.888 15.817 5.888Z",
5781
+ fill: "#B3B3B3"
5782
+ }), /*#__PURE__*/React.createElement("path", {
5783
+ d: "M98.174 19.625c5.458 0 9.883-4.393 9.883-9.81 0-5.418-4.425-9.81-9.883-9.81-5.46 0-9.884 4.392-9.884 9.81s4.425 9.81 9.883 9.81Z",
5784
+ fill: "#3690EA"
5785
+ }), /*#__PURE__*/React.createElement("path", {
5786
+ d: "M116.339 111.123c-.614-10.782-8.958-13.874-19.002-13.309-10.044.566-17.979 4.567-17.356 15.354.623 10.786 9.252 19.063 19.296 18.498 10.044-.565 17.676-9.761 17.062-20.543Z",
5787
+ fill: "#F2F2F2"
5788
+ }), /*#__PURE__*/React.createElement("path", {
5789
+ d: "M116.139 109.4c-1.268 8.891-8.171 15.901-16.884 16.378-9.43.53-17.623-6.74-19.096-16.559a17.615 17.615 0 0 0-.205 3.949c.619 10.781 9.257 19.063 19.297 18.498 10.039-.566 17.685-9.762 17.07-20.544a11.69 11.69 0 0 0-.182-1.722Z",
5790
+ fill: "#E6E6E6"
5791
+ }), /*#__PURE__*/React.createElement("path", {
5792
+ d: "M94.609 92.558c-.134-.579 7.868-1.1 6.987.291v.915c0 .883.035 1.789.04 2.68.004.893.04 1.891.053 2.837.334.702-7.779 1.108-6.991-.137v-.796c-.013-1.93-.067-3.86-.089-5.79Z",
5793
+ fill: "#999"
5794
+ }), /*#__PURE__*/React.createElement("path", {
5795
+ d: "M150.588 70.279V53.525a22.366 22.366 0 0 0-4.425-13.4 22.645 22.645 0 0 0-11.596-8.146c-10.613-3.19-23.061-5.027-36.376-5.031-13.315-.004-25.762 1.833-36.38 5.018a22.654 22.654 0 0 0-11.609 8.14 22.374 22.374 0 0 0-4.438 13.401v16.754a22.375 22.375 0 0 0 4.435 13.403 22.654 22.654 0 0 0 11.607 8.143c10.614 3.19 23.061 5.026 36.376 5.031 13.315.004 25.763-1.833 36.376-5.018a22.658 22.658 0 0 0 11.598-8.144 22.377 22.377 0 0 0 4.432-13.397Z",
5796
+ fill: "#F2F2F2"
5797
+ }), /*#__PURE__*/React.createElement("path", {
5798
+ d: "M98.16 88.976c-12.087 0-23.87-1.626-34.08-4.695a14.817 14.817 0 0 1-7.522-5.316 14.635 14.635 0 0 1-2.891-8.704V53.507a14.64 14.64 0 0 1 2.89-8.698 14.82 14.82 0 0 1 7.514-5.317c10.21-3.065 21.993-4.682 34.085-4.682 12.091 0 23.871 1.626 34.079 4.696a14.817 14.817 0 0 1 7.523 5.315 14.635 14.635 0 0 1 2.891 8.704V70.28a14.635 14.635 0 0 1-2.897 8.703 14.824 14.824 0 0 1-7.525 5.312c-10.191 3.047-21.976 4.682-34.067 4.682Zm3.498-70.014H94.68v1.533h6.978v-1.533Z",
5799
+ fill: "#E6E6E6"
5800
+ }), /*#__PURE__*/React.createElement("path", {
5801
+ d: "M72.367 78.304c5.195 0 9.407-7.348 9.407-16.413 0-9.065-4.212-16.414-9.407-16.414-5.196 0-9.408 7.349-9.408 16.414 0 9.065 4.212 16.413 9.408 16.413Z",
5802
+ fill: "#1A1A1A"
5803
+ }), /*#__PURE__*/React.createElement("path", {
5804
+ d: "M74.013 62.558c2.094 0 3.792-2.476 3.792-5.53 0-3.054-1.698-5.53-3.792-5.53s-3.791 2.476-3.791 5.53c0 3.054 1.697 5.53 3.791 5.53Z",
5805
+ fill: "#fff"
5806
+ }), /*#__PURE__*/React.createElement("path", {
5807
+ d: "M123.032 78.313c5.196 0 9.408-7.349 9.408-16.413 0-9.065-4.212-16.414-9.408-16.414-5.195 0-9.407 7.349-9.407 16.414 0 9.065 4.212 16.413 9.407 16.413Z",
5808
+ fill: "#1A1A1A"
5809
+ }), /*#__PURE__*/React.createElement("path", {
5810
+ d: "M124.679 62.567c2.094 0 3.792-2.476 3.792-5.53 0-3.054-1.698-5.53-3.792-5.53s-3.792 2.476-3.792 5.53c0 3.054 1.698 5.53 3.792 5.53Z",
5811
+ fill: "#fff"
5812
+ }), /*#__PURE__*/React.createElement("path", {
5813
+ d: "M105.325 106.675H90.991a.74.74 0 0 0-.743.737v2.089a.74.74 0 0 0 .743.738h14.334a.74.74 0 0 0 .743-.738v-2.089a.74.74 0 0 0-.743-.737Zm0 6.148H90.991a.74.74 0 0 0-.743.738v2.089a.74.74 0 0 0 .743.738h14.334c.41 0 .743-.331.743-.738v-2.089a.74.74 0 0 0-.743-.738Zm-.004 6.153H90.987a.74.74 0 0 0-.744.737v2.09a.74.74 0 0 0 .744.737h14.334a.74.74 0 0 0 .743-.737v-2.09a.74.74 0 0 0-.743-.737Z",
5814
+ fill: "#3690EA"
5815
+ }), /*#__PURE__*/React.createElement("path", {
5816
+ d: "M140.653 109.023c5.67-4.178 7.656-11.053 4.438-15.356-3.219-4.303-10.424-4.405-16.094-.227-5.67 4.177-7.656 11.052-4.438 15.356 3.219 4.303 10.424 4.405 16.094.227Z",
5817
+ fill: "#F2F2F2"
5818
+ }), /*#__PURE__*/React.createElement("path", {
5819
+ d: "M144.211 97.717c-3.217-4.302-10.422-4.417-16.092-.23a15.277 15.277 0 0 0-5.087 6.339c.067-3.613 2.194-7.58 5.964-10.358 5.669-4.174 12.874-4.073 16.092.23 1.86 2.486 1.976 5.83.649 9.019a7.943 7.943 0 0 0-1.526-5Z",
5820
+ fill: "#E6E6E6"
5821
+ }), /*#__PURE__*/React.createElement("path", {
5822
+ d: "M141.051 91.524c.966-1.66.874-3.508-.205-4.126-1.08-.618-2.737.226-3.703 1.887-.966 1.66-.874 3.508.205 4.126 1.079.619 2.737-.226 3.703-1.887Z",
5823
+ fill: "#333"
5824
+ }), /*#__PURE__*/React.createElement("path", {
5825
+ d: "M142.711 103.49c4.151 0 7.517-3.34 7.517-7.46s-3.366-7.46-7.517-7.46-7.516 3.34-7.516 7.46 3.365 7.46 7.516 7.46Z",
5826
+ fill: "#333"
5827
+ }), /*#__PURE__*/React.createElement("path", {
5828
+ d: "M70.234 108.894c3.219-4.303 1.232-11.178-4.437-15.356-5.67-4.178-12.875-4.076-16.094.227-3.219 4.303-1.232 11.179 4.438 15.356 5.67 4.178 12.875 4.076 16.093-.227Z",
5829
+ fill: "#F2F2F2"
5830
+ }), /*#__PURE__*/React.createElement("path", {
5831
+ d: "M50.574 97.717c3.218-4.302 10.422-4.417 16.092-.23a15.273 15.273 0 0 1 5.087 6.339c-.067-3.613-2.194-7.58-5.964-10.358-5.67-4.174-12.874-4.073-16.092.23-1.86 2.486-1.971 5.83-.65 9.019a7.945 7.945 0 0 1 1.527-5Z",
5832
+ fill: "#E6E6E6"
5833
+ }), /*#__PURE__*/React.createElement("path", {
5834
+ d: "M57.434 93.41c1.08-.618 1.171-2.466.206-4.126-.966-1.66-2.624-2.506-3.703-1.887-1.08.618-1.171 2.466-.205 4.126.965 1.66 2.623 2.506 3.702 1.887Z",
5835
+ fill: "#333"
5836
+ }), /*#__PURE__*/React.createElement("path", {
5837
+ d: "M52.074 103.49c4.151 0 7.516-3.34 7.516-7.46s-3.365-7.46-7.516-7.46-7.517 3.34-7.517 7.46 3.366 7.46 7.517 7.46Z",
5838
+ fill: "#333"
5839
+ }), /*#__PURE__*/React.createElement("path", {
5840
+ d: "M98.485 83.08c1.523-.183 2.609-1.544 2.426-3.041-.183-1.497-1.565-2.561-3.088-2.378-1.522.183-2.608 1.544-2.425 3.041.182 1.497 1.565 2.561 3.087 2.378Z",
5841
+ fill: "#1A1A1A"
5842
+ }), /*#__PURE__*/React.createElement("path", {
5843
+ d: "M101.729 11.17c1.733 0 3.138-1.394 3.138-3.113 0-1.72-1.405-3.114-3.138-3.114-1.733 0-3.137 1.394-3.137 3.114s1.404 3.114 3.137 3.114Zm52.37 52.753c.829 0 1.5-1.677 1.5-3.746s-.671-3.746-1.5-3.746c-.828 0-1.499 1.677-1.499 3.746s.671 3.746 1.499 3.746Zm-111.549 0c.829 0 1.5-1.677 1.5-3.746s-.671-3.746-1.5-3.746c-.828 0-1.5 1.677-1.5 3.746s.672 3.746 1.5 3.746Z",
5844
+ fill: "#4BAAF7"
5845
+ })), /*#__PURE__*/React.createElement("mask", {
5846
+ id: `${id}-b`,
5847
+ style: {
5848
+ maskType: "alpha"
5849
+ },
5850
+ maskUnits: "userSpaceOnUse",
5851
+ x: "0",
5852
+ y: "6",
5853
+ width: "197",
5854
+ height: "151"
5855
+ }, /*#__PURE__*/React.createElement("path", {
5856
+ d: "M139.863 26.12c10.938 10.028 21.777 20.154 32.912 30.084 8.376 7.373 21.975 15.828 23.157 28.02.592 6.095-2.167 11.993-5.321 17.204-24.635 40.8-81.098 67.148-127.412 48.862-30.646-12.093-76.172-47.387-59.716-85.041 15.865-36.377 64.84-55.056 83.957-57.71 21.876-4.621 34.883 2.457 52.423 18.58Z",
5857
+ fill: "#CEE1FF",
5858
+ fillOpacity: ".8"
5859
+ })), /*#__PURE__*/React.createElement("g", {
5860
+ mask: `url(#${id}-b)`
5861
+ }, /*#__PURE__*/React.createElement("path", {
5862
+ d: "m59.006 101 8 4m-4 1-4-5h6",
5863
+ stroke: "#FFD463"
5864
+ }), /*#__PURE__*/React.createElement("path", {
5865
+ d: "M60.006 100.999c-14.02-9.35-30.69-13.01-50-11S-26.916 103.01-38.276 115",
5866
+ strokeWidth: "2",
5867
+ stroke: "#fff"
5868
+ }), /*#__PURE__*/React.createElement("path", {
5869
+ d: "m125.304 89-8.08 3.84m1.68-3.77 6.4-.07-3.7 4.72",
5870
+ stroke: "#FFD463"
5871
+ }), /*#__PURE__*/React.createElement("path", {
5872
+ d: "M123.724 89.5c26.45-8.66 23 40.5 47 42.5 22.399 1.867 36.5-31.001 63 12",
5873
+ strokeWidth: "2",
5874
+ stroke: "#fff"
5875
+ })), /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("clipPath", {
5876
+ id: `${id}-a`
5877
+ }, /*#__PURE__*/React.createElement("path", {
5878
+ fill: "#fff",
5879
+ transform: "translate(38.051)",
5880
+ d: "M0 0h120v158H0z"
5881
+ }))));
5882
+ }
5883
+
5884
+ function BlankStateNoResults(props) {
5885
+ const id = useInstanceId("blank-state-no-results");
5886
+ return /*#__PURE__*/React.createElement("svg", {
5887
+ viewBox: "0 0 197 152",
5888
+ fill: "none",
5889
+ "aria-hidden": "true",
5890
+ focusable: "false",
5891
+ ...props
5892
+ }, /*#__PURE__*/React.createElement("path", {
5893
+ d: "M139.863 19.971C150.801 30 161.64 40.126 172.775 50.055c8.376 7.374 21.975 15.829 23.157 28.02.592 6.095-2.167 11.994-5.321 17.205-24.635 40.8-81.098 67.148-127.412 48.862C32.553 132.049-12.973 96.754 3.483 59.1 19.348 22.724 68.323 4.044 87.44 1.39c21.876-4.62 34.883 2.458 52.423 18.581Z",
5894
+ fill: "currentColor"
5895
+ }), /*#__PURE__*/React.createElement("path", {
5896
+ d: "M94.382 27.326c4.859 0 8.797-3.932 8.797-8.783 0-4.85-3.938-8.783-8.797-8.783-4.858 0-8.796 3.933-8.796 8.783 0 4.851 3.938 8.783 8.796 8.783Z",
5897
+ fill: "#3690EA"
5898
+ }), /*#__PURE__*/React.createElement("path", {
5899
+ d: "M97.481 19.861a3.22 3.22 0 0 0 3.222-3.217 3.22 3.22 0 0 0-3.222-3.217 3.22 3.22 0 0 0-3.222 3.217 3.22 3.22 0 0 0 3.222 3.217Z",
5900
+ fill: "#4BAAF7"
5901
+ }), /*#__PURE__*/React.createElement("path", {
5902
+ d: "M97.564 26.688h-6.248v3.565h6.248v-3.565Z",
5903
+ fill: "#F2F2F2"
5904
+ }), /*#__PURE__*/React.createElement("path", {
5905
+ d: "M49.297 77.706c4.649 0 8.417-5.61 8.417-12.53 0-6.921-3.768-12.531-8.417-12.531s-8.417 5.61-8.417 12.53c0 6.92 3.768 12.531 8.417 12.531Zm89.958 0c4.649 0 8.417-5.61 8.417-12.53 0-6.921-3.768-12.531-8.417-12.531s-8.417 5.61-8.417 12.53c0 6.92 3.768 12.531 8.417 12.531Z",
5906
+ fill: "#3690EA"
5907
+ }), /*#__PURE__*/React.createElement("path", {
5908
+ d: "M94.379 40.574c7.774 0 14.076-2.36 14.076-5.271 0-2.912-6.302-5.272-14.076-5.272-7.774 0-14.076 2.36-14.076 5.272 0 2.911 6.302 5.271 14.076 5.271Z",
5909
+ fill: "#B3B3B3"
5910
+ }), /*#__PURE__*/React.createElement("path", {
5911
+ d: "M141.036 72.671V57.672a20.118 20.118 0 0 0-3.949-12 20.166 20.166 0 0 0-10.333-7.29c-9.448-2.852-20.529-4.497-32.379-4.497-11.849 0-22.926 1.645-32.374 4.497a20.167 20.167 0 0 0-10.331 7.29 20.117 20.117 0 0 0-3.95 12v15a20.112 20.112 0 0 0 3.949 12A20.163 20.163 0 0 0 62 91.962c9.448 2.856 20.53 4.496 32.375 4.496 11.844 0 22.93-1.64 32.378-4.496a20.153 20.153 0 0 0 10.333-7.289 20.107 20.107 0 0 0 3.949-12.002Z",
5912
+ fill: "#F2F2F2"
5913
+ }), /*#__PURE__*/React.createElement("path", {
5914
+ d: "M94.387 89.422c-10.76 0-21.248-1.448-30.348-4.193a13.19 13.19 0 0 1-6.698-4.759 13.159 13.159 0 0 1-2.576-7.794v-15a13.163 13.163 0 0 1 2.577-7.793 13.196 13.196 0 0 1 6.697-4.76c9.082-2.744 19.574-4.193 30.348-4.193 10.773 0 21.248 1.449 30.348 4.194a13.2 13.2 0 0 1 6.701 4.757 13.17 13.17 0 0 1 2.582 7.795v15a13.164 13.164 0 0 1-2.577 7.794 13.195 13.195 0 0 1-6.697 4.759c-9.109 2.727-19.597 4.193-30.357 4.193Z",
5915
+ fill: "#E6E6E6"
5916
+ }), /*#__PURE__*/React.createElement("path", {
5917
+ d: "M71.426 79.868c4.624 0 8.373-6.58 8.373-14.696s-3.749-14.696-8.373-14.696c-4.624 0-8.372 6.58-8.372 14.696 0 8.117 3.748 14.697 8.372 14.697Z",
5918
+ fill: "#1A1A1A"
5919
+ }), /*#__PURE__*/React.createElement("path", {
5920
+ d: "M72.894 65.765c1.863 0 3.373-2.217 3.373-4.95 0-2.735-1.51-4.952-3.373-4.952-1.864 0-3.375 2.217-3.375 4.951 0 2.734 1.511 4.95 3.374 4.95Z",
5921
+ fill: "#fff"
5922
+ }), /*#__PURE__*/React.createElement("path", {
5923
+ d: "M116.517 79.868c4.624 0 8.373-6.58 8.373-14.696s-3.749-14.696-8.373-14.696c-4.624 0-8.372 6.58-8.372 14.696 0 8.117 3.748 14.697 8.372 14.697Z",
5924
+ fill: "#1A1A1A"
5925
+ }), /*#__PURE__*/React.createElement("path", {
5926
+ d: "M117.981 65.765c1.864 0 3.374-2.217 3.374-4.95 0-2.735-1.51-4.952-3.374-4.952-1.863 0-3.374 2.217-3.374 4.951 0 2.734 1.511 4.95 3.374 4.95Z",
5927
+ fill: "#fff"
5928
+ }), /*#__PURE__*/React.createElement("path", {
5929
+ d: "M100.012 80.196a14.156 14.156 0 0 0-2.785-1.159 10.598 10.598 0 0 0-5.713 0 14.09 14.09 0 0 0-2.78 1.159h-.027a.773.773 0 0 1-.973-1.159 8.74 8.74 0 0 1 6.639-3.049 8.754 8.754 0 0 1 6.638 3.05.773.773 0 0 1-.977 1.158h-.022Z",
5930
+ fill: "#999"
5931
+ }), /*#__PURE__*/React.createElement("path", {
5932
+ d: "M44.788 67.69c.853 0 1.545-1.731 1.545-3.867 0-2.137-.692-3.868-1.545-3.868-.852 0-1.544 1.731-1.544 3.867 0 2.137.691 3.868 1.544 3.868Zm99.38 0c.853 0 1.544-1.731 1.544-3.867 0-2.137-.691-3.868-1.544-3.868-.853 0-1.544 1.731-1.544 3.867 0 2.137.691 3.868 1.544 3.868Z",
5933
+ fill: "#4BAAF7"
5934
+ }), /*#__PURE__*/React.createElement("path", {
5935
+ d: "M79.596 106.857s-13.835 0-13.835-18.752",
5936
+ strokeWidth: "13.63",
5937
+ strokeMiterlimit: "10",
5938
+ strokeLinecap: "round",
5939
+ stroke: "#4D4D4D"
5940
+ }), /*#__PURE__*/React.createElement("path", {
5941
+ d: "M79.295 99.708h-.004a2.453 2.453 0 0 0-2.34 2.56l.353 7.781a2.453 2.453 0 0 0 2.564 2.337h.004a2.452 2.452 0 0 0 2.34-2.559l-.353-7.782a2.453 2.453 0 0 0-2.564-2.337Z",
5942
+ fill: "gray"
5943
+ }), /*#__PURE__*/React.createElement("path", {
5944
+ d: "M109.137 104.385s3.851 3.681 10.947-1.181",
5945
+ strokeWidth: "13.63",
5946
+ strokeMiterlimit: "10",
5947
+ strokeLinecap: "round",
5948
+ stroke: "#4D4D4D"
5949
+ }), /*#__PURE__*/React.createElement("path", {
5950
+ d: "m107.907 112.125.004.001a2.455 2.455 0 0 0 2.859-1.966l1.414-7.661a2.451 2.451 0 0 0-1.97-2.854h-.004a2.455 2.455 0 0 0-2.859 1.965l-1.413 7.661a2.45 2.45 0 0 0 1.969 2.854Z",
5951
+ fill: "gray"
5952
+ }), /*#__PURE__*/React.createElement("path", {
5953
+ d: "M89.494 121.176s-4.44 8.569-3.936 13.934",
5954
+ strokeWidth: "13.63",
5955
+ strokeMiterlimit: "10",
5956
+ strokeLinecap: "round",
5957
+ stroke: "#4D4D4D"
5958
+ }), /*#__PURE__*/React.createElement("path", {
5959
+ d: "M88.59 128.571c3.535 0 6.4-2.861 6.4-6.39a6.395 6.395 0 0 0-6.4-6.39 6.395 6.395 0 0 0-6.4 6.39 6.395 6.395 0 0 0 6.4 6.39Z",
5960
+ fill: "gray"
5961
+ }), /*#__PURE__*/React.createElement("path", {
5962
+ d: "M76.233 146.043h12.585v3.966a1.205 1.205 0 0 1-1.205 1.204H74.068a1.205 1.205 0 0 1-1.205-1.204v-.601a3.367 3.367 0 0 1 .989-2.378 3.38 3.38 0 0 1 2.38-.987Z",
5963
+ fill: "#333"
5964
+ }), /*#__PURE__*/React.createElement("path", {
5965
+ d: "M85.808 149.557s8.631.125 6.752-8.774c-1.878-8.899-13-16.291-16.263-6.434-3.262 9.857-1.499 16.166 9.511 15.208Z",
5966
+ fill: "#F2F2F2"
5967
+ }), /*#__PURE__*/React.createElement("path", {
5968
+ d: "M100.159 121.176s4.463 8.569 3.937 13.934",
5969
+ strokeWidth: "13.63",
5970
+ strokeMiterlimit: "10",
5971
+ strokeLinecap: "round",
5972
+ stroke: "#4D4D4D"
5973
+ }), /*#__PURE__*/React.createElement("path", {
5974
+ d: "M101.064 128.571c3.534 0 6.4-2.861 6.4-6.39 0-3.529-2.866-6.39-6.4-6.39a6.395 6.395 0 0 0-6.4 6.39 6.395 6.395 0 0 0 6.4 6.39Z",
5975
+ fill: "gray"
5976
+ }), /*#__PURE__*/React.createElement("path", {
5977
+ d: "M115.584 151.216h-13.545a1.206 1.206 0 0 1-1.205-1.203v-3.98h12.586a3.37 3.37 0 0 1 3.374 3.369v.602a1.21 1.21 0 0 1-.745 1.121 1.23 1.23 0 0 1-.465.091Z",
5978
+ fill: "#333"
5979
+ }), /*#__PURE__*/React.createElement("path", {
5980
+ d: "M103.838 149.557s-8.632.125-6.757-8.774c1.874-8.899 13.036-16.291 16.285-6.434 3.249 9.857 1.5 16.166-9.528 15.208Zm6.725-40.315c-.549-9.652-7.975-12.415-16.91-11.907-8.935.508-16.004 4.091-15.455 13.748.549 9.656 8.243 17.067 17.178 16.559 8.935-.508 15.736-8.743 15.187-18.4Z",
5981
+ fill: "#F2F2F2"
5982
+ }), /*#__PURE__*/React.createElement("path", {
5983
+ d: "M110.402 107.707c-1.129 7.958-7.271 14.228-15.027 14.665-8.39.477-15.683-6.034-16.995-14.821a15.77 15.77 0 0 0-.183 3.533c.549 9.652 8.239 17.067 17.178 16.559 8.939-.508 15.736-8.742 15.174-18.399a14.03 14.03 0 0 0-.147-1.537Z",
5984
+ fill: "#E6E6E6"
5985
+ }), /*#__PURE__*/React.createElement("path", {
5986
+ d: "M100.76 105.262H88a.66.66 0 0 0-.66.66v1.871c0 .365.296.66.66.66h12.76a.66.66 0 0 0 .66-.66v-1.871a.66.66 0 0 0-.66-.66Zm0 5.512H88a.66.66 0 0 0-.66.66v1.871c0 .364.296.66.66.66h12.76a.66.66 0 0 0 .66-.66v-1.871a.66.66 0 0 0-.66-.66Zm0 5.505H88a.66.66 0 0 0-.66.66v1.871c0 .364.296.66.66.66h12.76a.66.66 0 0 0 .66-.66v-1.871a.66.66 0 0 0-.66-.66Z",
5987
+ fill: "#3690EA"
5988
+ }), /*#__PURE__*/React.createElement("path", {
5989
+ d: "M133.43 107.146c5.688-4.463 7.529-11.6 4.111-15.943-3.417-4.343-10.799-4.245-16.487.218-5.688 4.463-7.529 11.601-4.111 15.943 3.417 4.343 10.799 4.245 16.487-.218Z",
5990
+ fill: "#F2F2F2"
5991
+ }), /*#__PURE__*/React.createElement("path", {
5992
+ d: "M136.74 95.34c-3.418-4.344-10.8-4.246-16.486.22a15.744 15.744 0 0 0-5.034 6.683c-.031-3.725 2.035-7.87 5.802-10.837 5.69-4.456 13.072-4.559 16.491-.218 1.972 2.508 2.182 5.953.919 9.273a8.246 8.246 0 0 0-1.692-5.12Z",
5993
+ fill: "#E6E6E6"
5994
+ }), /*#__PURE__*/React.createElement("path", {
5995
+ d: "M127.405 89.78c1.87.546 3.824.751 5.766.605v0a16.153 16.153 0 0 0 9.056-3.631",
5996
+ strokeWidth: "13.63",
5997
+ strokeMiterlimit: "10",
5998
+ strokeLinecap: "round",
5999
+ stroke: "#333"
6000
+ }), /*#__PURE__*/React.createElement("path", {
6001
+ d: "M79.875 85.766c2.25-7.476-.567-14.93-6.293-16.649-5.727-1.718-12.194 2.949-14.444 10.425-2.251 7.476.567 14.93 6.293 16.648 5.727 1.719 12.194-2.948 14.444-10.424Z",
6002
+ fill: "#F2F2F2"
6003
+ }), /*#__PURE__*/React.createElement("path", {
6004
+ d: "M69.713 71.558c5.726 1.72 8.542 9.175 6.293 16.652a16.978 16.978 0 0 1-4.74 7.687c3.767-1.435 7.141-5.151 8.627-10.12 2.232-7.477-.567-14.932-6.293-16.648-3.311-.993-6.863.152-9.706 2.736 1.85-.75 3.9-.858 5.82-.307Z",
6005
+ fill: "#E6E6E6"
6006
+ }), /*#__PURE__*/React.createElement("path", {
6007
+ d: "M77.006 68.04a6.195 6.195 0 0 1-4.269-1.866 6.176 6.176 0 0 1 0-8.623 6.195 6.195 0 0 1 4.27-1.867",
6008
+ strokeWidth: "13.63",
6009
+ strokeMiterlimit: "10",
6010
+ strokeLinecap: "round",
6011
+ stroke: "#333"
6012
+ }), /*#__PURE__*/React.createElement("path", {
6013
+ d: "M81.567 54.262c-.103.03-.205.07-.303.106l-.304.112-.303.111-.3.112-.303.111c-.103.031-.2.071-.303.111-.103.04-.201.072-.304.108l-.299.11-.303.112-.304.112c-.102.03-.2.071-.303.111l-.3.107-.303.111-.303.112-.304.111c-.098.031-.2.072-.299.112-.098.04-.205.07-.303.111-.099.04-.201.071-.304.107l-.299.111-.303.112a5.63 5.63 0 0 0-3.824 4.578 5.62 5.62 0 0 0 1.101 4.178 5.578 5.578 0 0 0 2.754 1.956l.303.112.304.111.308.112.303.11.304.112.303.112.304.111.303.112.308.111.304.111.303.112.304.111c.102.036.2.076.303.107l.308.116c.098.036.2.076.303.107.103.031.201.08.304.111.103.031.2.08.303.112.103.03.201.08.304.111.103.031.2.08.303.111.103.032.206.08.308.112a8.12 8.12 0 0 0 10.027-3.863 8.087 8.087 0 0 0-2.619-10.407 8.117 8.117 0 0 0-7.479-.88v.004Z",
6014
+ fill: "#2278D6"
6015
+ }), /*#__PURE__*/React.createElement("path", {
6016
+ d: "M97.105 47.237c-.192.062-.389.138-.58.21-.193.07-.393.142-.585.213-.192.072-.389.138-.585.214-.196.076-.388.138-.58.214-.192.076-.393.138-.585.214-.192.076-.388.138-.584.214-.197.076-.389.138-.585.214-.197.075-.388.138-.58.214-.192.075-.389.138-.585.213-.196.076-.388.139-.585.21-.196.071-.388.143-.58.214-.192.071-.392.138-.584.214-.192.075-.389.138-.585.214-.196.075-.388.138-.585.213-.196.076-.388.139-.58.214-.192.076-.393.139-.585.214-.191.076-.388.138-.584.214-.197.076-.389.138-.585.214-.196.076-.388.134-.58.21-.192.075-.388.138-.585.213a10.762 10.762 0 0 0-3.146 1.65 10.844 10.844 0 0 0-1.674 15.763 10.879 10.879 0 0 0 4.883 3.233c.196.075.388.151.589.213.2.063.388.152.585.214.196.063.392.152.589.219.196.067.388.147.584.214l.59.213c.196.076.388.152.589.214.2.063.388.152.584.214.197.063.388.152.59.214.2.063.388.152.584.219.196.066.388.147.59.213.2.067.387.148.584.214.196.067.388.147.589.214.2.067.388.152.584.214.197.063.393.152.59.214.196.062.388.151.584.218l.59.214c.196.072.388.147.584.214.196.067.393.147.59.214.196.067.387.151.588.214.201.062.388.151.585.214a15.669 15.669 0 0 0 14.439-1.806 15.624 15.624 0 0 0 6.706-12.895 15.597 15.597 0 0 0-1.829-7.256 15.659 15.659 0 0 0-19.454-7.244Z",
6017
+ fill: "#3690EA"
6018
+ }), /*#__PURE__*/React.createElement("path", {
6019
+ d: "M119.065 37.388a25.93 25.93 0 0 0-.978.356c-.326.125-.651.232-.977.357-.326.125-.652.232-.978.356-.325.125-.651.232-.977.361-.326.13-.652.232-.977.357-.326.125-.652.232-.978.356-.326.125-.656.232-.977.357-.322.125-.656.232-.978.36-.321.13-.651.228-.977.357-.326.13-.656.232-.977.357-.322.124-.656.231-.978.356-.321.125-.656.232-.977.357-.321.125-.656.231-.977.36-.322.13-.657.228-.978.357-.321.13-.656.232-.977.357-.322.124-.656.231-.978.356-.321.125-.656.232-.982.361-.325.13-.651.227-.977.357-.326.129-.651.227-.973.356-.321.13-.656.232-.982.357a18.217 18.217 0 0 0-7.281 4.523A18.158 18.158 0 0 0 90.716 72.8a18.097 18.097 0 0 0 8.926 6.314c.326.13.651.254.986.361.335.107.652.254.982.361.33.107.652.25.986.36.335.112.647.25.982.357.335.107.652.254.982.361.33.107.652.25.986.361.335.112.652.25.982.357.33.107.652.254.986.36.335.108.648.25.982.362.335.111.652.25.982.356.33.107.652.254.986.361.335.107.652.25.982.361.331.111.652.25.982.357.33.106.656.253.986.36.331.107.652.254.982.361.331.107.652.25.987.361.334.112.651.25.981.357.331.107.652.254.987.36.334.108.647.25.982.362.334.111.651.25.981.356a26.26 26.26 0 0 0 24.2-3.02 26.2 26.2 0 0 0 8.29-9.42 26.147 26.147 0 0 0-.114-24.35 26.194 26.194 0 0 0-8.377-9.343 26.244 26.244 0 0 0-24.226-2.795l-.022.009Z",
6020
+ fill: "#50B0FF"
6021
+ }), /*#__PURE__*/React.createElement("path", {
6022
+ d: "M128.994 80.692a18.926 18.926 0 0 1-11.736-4.091 18.853 18.853 0 0 1-5.352-22.825 18.889 18.889 0 0 1 8.696-8.867 18.93 18.93 0 0 1 22.967 4.864 18.856 18.856 0 0 1 .514 23.437 18.738 18.738 0 0 1-6.655 5.529 18.772 18.772 0 0 1-8.434 1.953Z",
6023
+ fill: "#D6DEE5"
6024
+ }), /*#__PURE__*/React.createElement("path", {
6025
+ d: "M129.021 45.14a16.719 16.719 0 0 1 10.373 3.604 16.67 16.67 0 0 1 5.887 9.258 16.65 16.65 0 0 1-1.144 10.906 16.687 16.687 0 0 1-7.681 7.838 16.724 16.724 0 0 1-10.896 1.38 16.704 16.704 0 0 1-9.398-5.675 16.657 16.657 0 0 1-.449-20.708 16.64 16.64 0 0 1 13.322-6.604h-.014Zm.014-4.417a21.143 21.143 0 0 0-13.684 5.01 21.066 21.066 0 0 0-4.43 26.958 21.12 21.12 0 0 0 11.363 9.113 21.153 21.153 0 0 0 14.569-.404 21.113 21.113 0 0 0 10.84-9.728 21.063 21.063 0 0 0 1.948-14.422 21.086 21.086 0 0 0-7.869-12.249 20.973 20.973 0 0 0-12.737-4.278Z",
6026
+ fill: "#1B64CE"
6027
+ }), /*#__PURE__*/React.createElement("path", {
6028
+ d: "M131.495 67.397c4.287 0 7.762-3.47 7.762-7.749 0-4.28-3.475-7.75-7.762-7.75-4.286 0-7.761 3.47-7.761 7.75 0 4.28 3.475 7.75 7.761 7.75Z",
6029
+ fill: "#fff"
6030
+ }), /*#__PURE__*/React.createElement("path", {
6031
+ d: "M137.039 56.638a3.996 3.996 0 0 0 3.999-3.993 3.996 3.996 0 0 0-3.999-3.992 3.996 3.996 0 0 0-3.999 3.992 3.996 3.996 0 0 0 3.999 3.993Z",
6032
+ fill: "#fff"
6033
+ }), /*#__PURE__*/React.createElement("mask", {
6034
+ id: `${id}-a`,
6035
+ style: {
6036
+ maskType: "alpha"
6037
+ },
6038
+ maskUnits: "userSpaceOnUse",
6039
+ x: "90",
6040
+ y: "96",
6041
+ width: "9",
6042
+ height: "4"
6043
+ }, /*#__PURE__*/React.createElement("path", {
6044
+ d: "M94.651 96.461c-1.785 0-3.26-.038-3.78-.038v2.897h7.14v-2.897c-.371 0-1.574.038-3.36.038Z",
6045
+ fill: "#000"
6046
+ })), /*#__PURE__*/React.createElement("g", {
6047
+ mask: `url(#${id}-a)`
6048
+ }, /*#__PURE__*/React.createElement("path", {
6049
+ d: "M94.51 95.545c-1.732.049-3.124.25-3.124.494v2.617c0 .245 1.392.446 3.124.495 1.731.049 3.124-.138 3.124-.384v-2.839c0-.245-1.393-.432-3.124-.383Z",
6050
+ fill: "#999"
6051
+ })));
6052
+ }
6053
+
6054
+ var styles$b = {"spinner":"spinner-b5tlz"};
6055
+
6056
+ function LoadingSpinner({
6057
+ size = 48,
6058
+ trackWidth = 6
6059
+ }) {
6060
+ return /*#__PURE__*/React.createElement("span", {
6061
+ "aria-hidden": "true",
6062
+ className: styles$b.spinner,
6063
+ style: {
6064
+ "--spinner-size": `${size}px`,
6065
+ "--spinner-track-width": `${trackWidth}px`
6066
+ }
6067
+ });
6068
+ }
4371
6069
 
4372
6070
  function SearchResults({
4373
6071
  label,
@@ -4388,18 +6086,36 @@ function SearchResults({
4388
6086
  ...navigation
4389
6087
  });
4390
6088
  }
4391
- return /*#__PURE__*/React.createElement("p", {
4392
- role: "status"
4393
- }, "Searching\u2026");
6089
+ return /*#__PURE__*/React.createElement(tapestry.Flex, {
6090
+ role: "status",
6091
+ justify: "center",
6092
+ align: "center",
6093
+ gap: 2,
6094
+ direction: "column",
6095
+ style: {
6096
+ color: "var(--t-text-color-placeholder)",
6097
+ fontSize: "var(--t-font-size-md)",
6098
+ marginTop: 48
6099
+ }
6100
+ }, /*#__PURE__*/React.createElement(LoadingSpinner, {
6101
+ size: 40,
6102
+ trackWidth: 5
6103
+ }), "Searching\u2026");
4394
6104
  case "error":
4395
- return /*#__PURE__*/React.createElement("p", {
4396
- role: "alert"
4397
- }, "Search isn\u2019t working right now. Try again.");
6105
+ return /*#__PURE__*/React.createElement(BlankState$1, {
6106
+ image: /*#__PURE__*/React.createElement(BlankStateError, null),
6107
+ role: "alert",
6108
+ subtitle: "Try again in a moment.",
6109
+ title: "Search isn\u2019t working right now"
6110
+ });
4398
6111
  case "done":
4399
6112
  if (sections.length === 0) {
4400
- return /*#__PURE__*/React.createElement("p", {
4401
- role: "status"
4402
- }, "No results for \u201C", term.trim(), "\u201D");
6113
+ // The panel's result count announces this, so it isn't read twice.
6114
+ return /*#__PURE__*/React.createElement(BlankState$1, {
6115
+ image: /*#__PURE__*/React.createElement(BlankStateNoResults, null),
6116
+ subtitle: "Clear search and try again.",
6117
+ title: `No results for “${term.trim()}”`
6118
+ });
4403
6119
  }
4404
6120
  return /*#__PURE__*/React.createElement(ResultListbox, {
4405
6121
  busy: false,
@@ -4414,31 +6130,43 @@ function SearchResults({
4414
6130
  // stays put as more recents load and as their lookups answer.
4415
6131
  const RECENTS = "recents";
4416
6132
  function SearchPanel({
6133
+ appName,
6134
+ mobile = false,
4417
6135
  env,
6136
+ onClose,
6137
+ onOpenResult,
4418
6138
  products
4419
6139
  }) {
4420
6140
  var _a, _b;
4421
6141
  const listboxId = useInstanceId("product-search-results");
4422
6142
  const [term, setTerm] = React.useState("");
4423
- const [selectedSlug, setSelectedSlug] = React.useState(() => initialProduct(products).slug);
6143
+ const [selectedSlug, setSelectedSlug] = React.useState(() => defaultProduct(products, appName).slug);
4424
6144
  const product = (_a = products.find(({
4425
6145
  slug
4426
6146
  }) => slug === selectedSlug)) !== null && _a !== void 0 ? _a : products[0];
4427
6147
  const hasTerm = term.trim() !== "";
4428
6148
  const search = useProductSearch(product.slug, term);
4429
6149
  const groups = "groups" in search ? search.groups : undefined;
4430
- const sections = React.useMemo(() => groupSections(groups), [groups]);
6150
+ const {
6151
+ organizationTimeZone
6152
+ } = useStore();
6153
+ const sections = React.useMemo(() => groupSections(groups, organizationTimeZone), [groups, organizationTimeZone]);
4431
6154
  const {
4432
6155
  visits,
4433
6156
  ...recents
4434
6157
  } = useRecentVisits(env);
4435
- const recentItems = visits.map(visitItem);
6158
+ const recentItems = visits.map(visit => visitItem(visit, organizationTimeZone));
4436
6159
  const items = hasTerm ? sections.flatMap(section => section.items) : recentItems;
4437
- const navigation = useResultNavigation(items, hasTerm ? sections : RECENTS);
6160
+ // Phones open results by tapping them, with no highlight to arrow through.
6161
+ // A narrow window with a keyboard and mouse keeps both, as does the desktop
6162
+ // layout on a touch device, whose keyboard hints still advertise them.
6163
+ const touchOnly = useMediaQuery("(hover: none) and (pointer: coarse)");
6164
+ const navigation = useResultNavigation(items, hasTerm ? sections : RECENTS, !(mobile && touchOnly));
4438
6165
  const {
4439
6166
  highlightedIndex
4440
6167
  } = navigation;
4441
6168
  const inputRef = React.useRef(null);
6169
+ const resultCount = useAnnouncement(hasTerm && search.status === "done" ? `${items.length === 0 ? "No results" : `${items.length} ${items.length === 1 ? "result" : "results"}`} for “${term.trim()}” in ${product.appName}` : null);
4442
6170
  const [announceHighlight, setAnnounceHighlight] = React.useState(false);
4443
6171
  // The tabs keep focus while arrowing through results, but only the focused
4444
6172
  // input can point screen readers at the highlight, so from the tabs it's
@@ -4454,41 +6182,50 @@ function SearchPanel({
4454
6182
  navigation.handleKeyDown(event);
4455
6183
  }
4456
6184
  };
4457
- React.useEffect(() => {
4458
- if (hasTerm) saveLastProduct(product.slug);
4459
- }, [hasTerm, product.slug]);
6185
+ const results = hasTerm ? (/*#__PURE__*/React.createElement(SearchResults, {
6186
+ highlightedIndex: highlightedIndex,
6187
+ id: listboxId,
6188
+ label: `Results from Planning Center ${product.appName}`,
6189
+ onHighlight: navigation.highlightIndex,
6190
+ onOpen: onOpenResult,
6191
+ sections: sections,
6192
+ status: search.status,
6193
+ term: term
6194
+ })) : (/*#__PURE__*/React.createElement(RecentlyVisited, {
6195
+ highlightedIndex: highlightedIndex,
6196
+ id: listboxId,
6197
+ items: recentItems,
6198
+ onHighlight: navigation.highlightIndex,
6199
+ onOpen: onOpenResult,
6200
+ ...recents
6201
+ }));
4460
6202
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SearchInput, {
4461
6203
  expanded: items.length > 0,
4462
6204
  highlightedIndex: highlightedIndex,
4463
6205
  inputRef: inputRef,
4464
6206
  listboxId: listboxId,
4465
6207
  onChange: setTerm,
6208
+ onClose: onClose,
4466
6209
  onFocus: () => setAnnounceHighlight(false),
4467
6210
  onKeyDown: navigation.handleKeyDown,
4468
6211
  value: term
4469
- }), /*#__PURE__*/React.createElement(ProductTabs, {
6212
+ }), mobile ? (/*#__PURE__*/React.createElement(ProductSelect, {
6213
+ onSelect: setSelectedSlug,
6214
+ products: products,
6215
+ selected: product
6216
+ }, results)) : (/*#__PURE__*/React.createElement(ProductTabs, {
4470
6217
  onKeyDown: handleTabsKeyDown,
4471
6218
  onSelect: setSelectedSlug,
4472
6219
  products: products,
4473
6220
  selected: product
4474
- }, hasTerm ? (/*#__PURE__*/React.createElement(SearchResults, {
4475
- highlightedIndex: highlightedIndex,
4476
- id: listboxId,
4477
- label: `${product.appName} results`,
4478
- onHighlight: navigation.highlightIndex,
4479
- sections: sections,
4480
- status: search.status,
4481
- term: term
4482
- })) : (/*#__PURE__*/React.createElement(RecentlyVisited, {
4483
- highlightedIndex: highlightedIndex,
4484
- id: listboxId,
4485
- items: recentItems,
4486
- onHighlight: navigation.highlightIndex,
4487
- ...recents
4488
- }))), /*#__PURE__*/React.createElement("div", {
6221
+ }, results)), /*#__PURE__*/React.createElement("div", {
6222
+ "aria-live": "polite",
6223
+ className: styles$k.visuallyHidden
6224
+ }, announceHighlight ? (_b = navigation.highlighted) === null || _b === void 0 ? void 0 : _b.title : null), /*#__PURE__*/React.createElement("div", {
4489
6225
  "aria-live": "polite",
4490
- className: styles$b.visuallyHidden
4491
- }, announceHighlight ? (_b = navigation.highlighted) === null || _b === void 0 ? void 0 : _b.title : null), /*#__PURE__*/React.createElement(KeyboardHints, {
6226
+ className: styles$k.visuallyHidden,
6227
+ "data-testid": "result-count"
6228
+ }, resultCount), mobile ? null : /*#__PURE__*/React.createElement(KeyboardHints, {
4492
6229
  copied: navigation.copied
4493
6230
  }));
4494
6231
  }
@@ -4559,32 +6296,6 @@ function useSearchShortcut(enabled, open, setOpen) {
4559
6296
  }, [enabled, open, setOpen]);
4560
6297
  }
4561
6298
 
4562
- const SEARCHABLE_PRODUCTS = [{
4563
- appName: "Calendar",
4564
- slug: "calendar"
4565
- }, {
4566
- appName: "Check-Ins",
4567
- slug: "check-ins"
4568
- }, {
4569
- appName: "Giving",
4570
- slug: "giving"
4571
- }, {
4572
- appName: "Groups",
4573
- slug: "groups"
4574
- }, {
4575
- appName: "People",
4576
- slug: "people"
4577
- }, {
4578
- appName: "Publishing",
4579
- slug: "publishing"
4580
- }, {
4581
- appName: "Registrations",
4582
- slug: "registrations"
4583
- }, {
4584
- appName: "Services",
4585
- slug: "services"
4586
- }];
4587
-
4588
6299
  const PERMISSION_CHECKS = {
4589
6300
  "check-ins": () => fetchMe("check-ins", "permission").then(({
4590
6301
  permission
@@ -4689,24 +6400,60 @@ function inSwitcherOrder(apps) {
4689
6400
  return groupApps(apps).restProducts.flatMap(app => SEARCHABLE_PRODUCTS.filter(product => product.appName === app.name));
4690
6401
  }
4691
6402
 
6403
+ /**
6404
+ * Writes the height of the visible part of the page to the parent of `ref`'s
6405
+ * element as `--visual-viewport-height`. It shrinks when an on-screen keyboard
6406
+ * opens; `100dvh` doesn't, since mobile Safari draws the keyboard over it.
6407
+ */
6408
+ function useVisualViewportHeight(ref, enabled) {
6409
+ React.useEffect(() => {
6410
+ var _a;
6411
+ const viewport = window.visualViewport;
6412
+ const parent = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.parentElement;
6413
+ if (!enabled || !viewport || !parent) return undefined;
6414
+ const update = () => parent.style.setProperty("--visual-viewport-height", `${viewport.height}px`);
6415
+ update();
6416
+ viewport.addEventListener("resize", update);
6417
+ return () => {
6418
+ viewport.removeEventListener("resize", update);
6419
+ parent.style.removeProperty("--visual-viewport-height");
6420
+ };
6421
+ }, [enabled, ref]);
6422
+ }
6423
+
4692
6424
  function ProductSearch({
6425
+ appName,
4693
6426
  apps,
6427
+ mobile = false,
4694
6428
  env
4695
6429
  }) {
4696
6430
  const searchable = useSearchableProducts(apps);
4697
6431
  const [open, setOpen] = React.useState(false);
6432
+ const modalRef = React.useRef(null);
6433
+ // Sizes Tapestry's modal frame, the dialog's parent, to fit above the keyboard.
6434
+ useVisualViewportHeight(modalRef, mobile && open);
4698
6435
  const available = searchable.status === "done" && searchable.products.length > 0;
4699
6436
  useSearchShortcut(available, open, setOpen);
4700
6437
  if (!available) return null;
4701
6438
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SearchButton, {
6439
+ mobile: mobile,
4702
6440
  onClick: () => setOpen(true)
4703
6441
  }), /*#__PURE__*/React.createElement(tapestry.Modal, {
4704
6442
  "aria-label": "Search",
6443
+ className: styles$k.modal,
4705
6444
  dismissible: true,
6445
+ id: "product_search_modal",
4706
6446
  onClose: () => setOpen(false),
4707
- open: open
6447
+ open: open,
6448
+ ref: modalRef,
6449
+ size: "lg"
4708
6450
  }, /*#__PURE__*/React.createElement(SearchPanel, {
6451
+ appName: appName,
6452
+ mobile: mobile,
4709
6453
  env: env,
6454
+ // Phones have no Esc, so mobile search gets a close button.
6455
+ onClose: mobile ? () => setOpen(false) : undefined,
6456
+ onOpenResult: () => setOpen(false),
4710
6457
  products: searchable.products
4711
6458
  })));
4712
6459
  }
@@ -5000,6 +6747,7 @@ const NotSmallTopbar = ({
5000
6747
  margin: "auto"
5001
6748
  }
5002
6749
  }), !notificationsEnabled && notifications(), productSearchEnabled ? (/*#__PURE__*/React.createElement(ProductSearch, {
6750
+ appName: props.appName,
5003
6751
  apps: props.apps,
5004
6752
  env: props.env
5005
6753
  })) : search({
@@ -32914,7 +34662,7 @@ ClientStorage.defaultProps = {
32914
34662
  method: "localStorage"
32915
34663
  };
32916
34664
 
32917
- var styles$6 = {"appmenu-button":"appmenu-button-b0UvT","appmenu-layer":"appmenu-layer-0IQpN","appmenu-container":"appmenu-container-gackd","appmenu-scroll":"appmenu-scroll-mPSx0","appmenu-list":"appmenu-list-h7clX","appmenu-list-a":"appmenu-list-a-rGIQN","appmenu-list-a--top":"appmenu-list-a--top-RT-2F","appmenu-list-a--bottom":"appmenu-list-a--bottom-YDeBC","appmenu-close-button":"appmenu-close-button-vv9bV","current-route":"current-route-wpJgz","is-active":"is-active-wy8Bg","routes":"routes-Nmt1S","route":"route-kkknQ","profile-button":"profile-button-a2WO2"};
34665
+ var styles$6 = {"appmenu-button":"appmenu-button-b0UvT","appmenu-layer":"appmenu-layer-0IQpN","appmenu-container":"appmenu-container-gackd","appmenu-scroll":"appmenu-scroll-mPSx0","appmenu-list":"appmenu-list-h7clX","appmenu-list-a":"appmenu-list-a-rGIQN","appmenu-list-a--top":"appmenu-list-a--top-RT-2F","appmenu-list-a--bottom":"appmenu-list-a--bottom-YDeBC","appmenu-close-button":"appmenu-close-button-vv9bV","current-route":"current-route-wpJgz","actions":"actions-INQ7-","is-active":"is-active-wy8Bg","routes":"routes-Nmt1S","route":"route-kkknQ","profile-button":"profile-button-a2WO2"};
32918
34666
 
32919
34667
  function AccountSettingsLink({
32920
34668
  env
@@ -33134,7 +34882,14 @@ const SmallTopbar = ({
33134
34882
  setProductSwitcherVisible(false);
33135
34883
  setRoutesMenuVisible(visible => !visible);
33136
34884
  } : null
33137
- }, /*#__PURE__*/React.createElement(CurrentRouteComponent, null, capitalize$1(currentRouteText)), props.routes.length > 0 && /*#__PURE__*/React.createElement(DisclosureChevronIcon, null)), /*#__PURE__*/React.createElement("button", {
34885
+ }, /*#__PURE__*/React.createElement(CurrentRouteComponent, null, capitalize$1(currentRouteText)), props.routes.length > 0 && /*#__PURE__*/React.createElement(DisclosureChevronIcon, null)), /*#__PURE__*/React.createElement("div", {
34886
+ className: styles$6["actions"]
34887
+ }, productSearchEnabled && (/*#__PURE__*/React.createElement(ProductSearch, {
34888
+ appName: props.appName,
34889
+ apps: props.apps,
34890
+ mobile: true,
34891
+ env: props.env
34892
+ })), /*#__PURE__*/React.createElement("button", {
33138
34893
  type: "button",
33139
34894
  className: styles$6["profile-button"],
33140
34895
  onClick: () => {
@@ -33145,7 +34900,7 @@ const SmallTopbar = ({
33145
34900
  }, /*#__PURE__*/React.createElement(Avatar, {
33146
34901
  env: props.env,
33147
34902
  url: props.userAvatarPath
33148
- })));
34903
+ }))));
33149
34904
  };
33150
34905
  const SmallRoute = ({
33151
34906
  active,
@@ -33635,38 +35390,6 @@ const SwitchView = ({
33635
35390
  }));
33636
35391
  };
33637
35392
 
33638
- const collections = {
33639
- general: general__namespace,
33640
- toolbar: toolbar__namespace
33641
- };
33642
- const paths = collections;
33643
- function Icon({
33644
- name,
33645
- size = 16,
33646
- style,
33647
- theme,
33648
- title,
33649
- ...props
33650
- }) {
33651
- const [collection, symbol] = name.split(".");
33652
- return /*#__PURE__*/React.createElement("svg", {
33653
- "aria-hidden": title ? undefined : true,
33654
- fill: "currentColor",
33655
- height: size,
33656
- role: title ? "img" : undefined,
33657
- style: {
33658
- color: theme && `var(${theme})`,
33659
- flexShrink: 0,
33660
- ...style
33661
- },
33662
- viewBox: "0 0 16 16",
33663
- width: size,
33664
- ...props
33665
- }, title && /*#__PURE__*/React.createElement("title", null, title), /*#__PURE__*/React.createElement("path", {
33666
- d: paths[collection][symbol]
33667
- }));
33668
- }
33669
-
33670
35393
  var styles$3 = {"color-mode-switcher":"color-mode-switcher-JpczO","color-mode-switcher-label":"color-mode-switcher-label-3jPM2","color-mode-switcher-modes":"color-mode-switcher-modes-u-bic"};
33671
35394
 
33672
35395
  const COLOR_MODES = [{
@@ -35154,13 +36877,15 @@ const useNotifications = ({
35154
36877
  return notification.data;
35155
36878
  }
35156
36879
  };
35157
- const updateStateFromJoltMessage = React.useCallback(message => {
36880
+ const updateStateFromJoltMessage = React.useCallback(async message => {
35158
36881
  try {
35159
36882
  const joltMessageNotificationDataPayload = extractPayloadFromJoltMessage(message);
35160
- fetchNotification(joltMessageNotificationDataPayload.data.id).then(resp => {
35161
- const notification = buildNotificationFromApiResponse(resp.data, resp);
35162
- setNotifications(notifications => [...notifications.filter(candidate => candidate.id !== notification.id), notification]);
35163
- });
36883
+ const resp = await fetchNotification(joltMessageNotificationDataPayload.data.id);
36884
+ if (!(resp === null || resp === void 0 ? void 0 : resp.data)) {
36885
+ return;
36886
+ }
36887
+ const notification = buildNotificationFromApiResponse(resp.data, resp);
36888
+ setNotifications(notifications => [...notifications.filter(candidate => candidate.id !== notification.id), notification]);
35164
36889
  } catch (exception) {
35165
36890
  console.error("topbar encountered error when updating state from jolt message", exception);
35166
36891
  }