@planningcenter/topbar 12.4.0-rc.0 → 12.4.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.css +78 -12
- package/dist/topbar.css.map +1 -1
- package/dist/topbar.js +1082 -853
- package/dist/topbar.js.map +1 -1
- package/dist/topbar.modern.js +1082 -853
- package/dist/topbar.modern.js.map +1 -1
- package/dist/topbar.module.js +1082 -853
- package/dist/topbar.module.js.map +1 -1
- package/dist/topbar.umd.js +1082 -853
- package/dist/topbar.umd.js.map +1 -1
- package/package.json +2 -3
package/dist/topbar.umd.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
var people__namespace = /*#__PURE__*/_interopNamespaceDefault(people);
|
|
28
28
|
var toolbar__namespace = /*#__PURE__*/_interopNamespaceDefault(toolbar);
|
|
29
29
|
|
|
30
|
-
var styles$
|
|
30
|
+
var styles$m = {"accessibility-toolbar":"accessibility-toolbar-jgjUG"};
|
|
31
31
|
|
|
32
32
|
const AccessibilityToolbar = ({
|
|
33
33
|
children
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
(_a = document.getElementById("main-content")) === null || _a === void 0 ? void 0 : _a.focus();
|
|
40
40
|
};
|
|
41
41
|
return /*#__PURE__*/React.createElement("div", {
|
|
42
|
-
className: styles$
|
|
42
|
+
className: styles$m["accessibility-toolbar"]
|
|
43
43
|
}, /*#__PURE__*/React.createElement(tapestry.Link, {
|
|
44
44
|
href: "#main-content",
|
|
45
45
|
kind: "primary",
|
|
@@ -358,11 +358,11 @@
|
|
|
358
358
|
fill: fill
|
|
359
359
|
})));
|
|
360
360
|
|
|
361
|
-
var styles$
|
|
361
|
+
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"};
|
|
362
362
|
|
|
363
363
|
function AnnouncementIcon() {
|
|
364
364
|
return /*#__PURE__*/React.createElement("svg", {
|
|
365
|
-
className: styles$
|
|
365
|
+
className: styles$l["announcement-icon"],
|
|
366
366
|
width: "16",
|
|
367
367
|
height: "16",
|
|
368
368
|
viewBox: "0 0 16 16",
|
|
@@ -487,7 +487,7 @@
|
|
|
487
487
|
} = this.props;
|
|
488
488
|
const isPromo = variant === "promo";
|
|
489
489
|
return /*#__PURE__*/React.createElement("div", {
|
|
490
|
-
className: classnames(styles$
|
|
490
|
+
className: classnames(styles$l["announcement"], styles$l[`announcement--${variant !== null && variant !== void 0 ? variant : "platform"}`]),
|
|
491
491
|
"data-announcement-variant": variant !== null && variant !== void 0 ? variant : "platform",
|
|
492
492
|
style: isPromo ? {
|
|
493
493
|
backgroundImage: promoBackgroundUrl,
|
|
@@ -496,7 +496,7 @@
|
|
|
496
496
|
backgroundSize: "cover"
|
|
497
497
|
} : undefined
|
|
498
498
|
}, !isPromo && /*#__PURE__*/React.createElement(AnnouncementIcon, null), /*#__PURE__*/React.createElement("div", {
|
|
499
|
-
className: styles$
|
|
499
|
+
className: styles$l["announcement-content"],
|
|
500
500
|
style: style,
|
|
501
501
|
...platformProps
|
|
502
502
|
}));
|
|
@@ -545,7 +545,7 @@
|
|
|
545
545
|
const isPromo = variant === "promo";
|
|
546
546
|
return /*#__PURE__*/React.createElement("button", {
|
|
547
547
|
type: "button",
|
|
548
|
-
className: classnames(styles$
|
|
548
|
+
className: classnames(styles$l.dismiss, isPromo && styles$l["dismiss--promo"]),
|
|
549
549
|
...props
|
|
550
550
|
}, /*#__PURE__*/React.createElement(X, {
|
|
551
551
|
fill: isPromo ? "currentColor" : "white",
|
|
@@ -625,9 +625,9 @@
|
|
|
625
625
|
...platformProps
|
|
626
626
|
} = this.props;
|
|
627
627
|
return /*#__PURE__*/React.createElement("div", {
|
|
628
|
-
className: styles$
|
|
628
|
+
className: styles$l["announcement"]
|
|
629
629
|
}, /*#__PURE__*/React.createElement(AnnouncementIcon, null), /*#__PURE__*/React.createElement("div", {
|
|
630
|
-
className: styles$
|
|
630
|
+
className: styles$l["announcement-content"],
|
|
631
631
|
style: style,
|
|
632
632
|
...platformProps
|
|
633
633
|
}));
|
|
@@ -638,7 +638,7 @@
|
|
|
638
638
|
}) {
|
|
639
639
|
return /*#__PURE__*/React.createElement("button", {
|
|
640
640
|
type: "button",
|
|
641
|
-
className: styles$
|
|
641
|
+
className: styles$l.dismiss,
|
|
642
642
|
...props
|
|
643
643
|
}, /*#__PURE__*/React.createElement(X, {
|
|
644
644
|
fill: "white",
|
|
@@ -1760,7 +1760,7 @@
|
|
|
1760
1760
|
})) : (/*#__PURE__*/React.createElement("div", null, "appName not supported")));
|
|
1761
1761
|
}
|
|
1762
1762
|
|
|
1763
|
-
var styles$
|
|
1763
|
+
var styles$k = {"icon-slot":"icon-slot-m3ZIk","name":"name-UNqbW"};
|
|
1764
1764
|
|
|
1765
1765
|
const AppRow = ({
|
|
1766
1766
|
appName,
|
|
@@ -1769,24 +1769,24 @@
|
|
|
1769
1769
|
}) => {
|
|
1770
1770
|
if (appName === "Accounts") {
|
|
1771
1771
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
|
|
1772
|
-
className: styles$
|
|
1772
|
+
className: styles$k["icon-slot"]
|
|
1773
1773
|
}, /*#__PURE__*/React.createElement(MonoAppIcon, {
|
|
1774
1774
|
appName: "Accounts",
|
|
1775
1775
|
colors: colors,
|
|
1776
1776
|
size: iconSize
|
|
1777
1777
|
})), /*#__PURE__*/React.createElement("span", {
|
|
1778
|
-
className: styles$
|
|
1778
|
+
className: styles$k.name
|
|
1779
1779
|
}, "Account settings"));
|
|
1780
1780
|
}
|
|
1781
1781
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorAppIcon, {
|
|
1782
1782
|
appName: appName.replace(/[\s-]/, ""),
|
|
1783
1783
|
size: iconSize
|
|
1784
1784
|
}), /*#__PURE__*/React.createElement("span", {
|
|
1785
|
-
className: styles$
|
|
1785
|
+
className: styles$k.name
|
|
1786
1786
|
}, appName));
|
|
1787
1787
|
};
|
|
1788
1788
|
|
|
1789
|
-
var styles$
|
|
1789
|
+
var styles$j = {"button":"button-XMbeQ","label":"label-884of","chevron":"chevron-RRg9k"};
|
|
1790
1790
|
|
|
1791
1791
|
const AppsButton = /*#__PURE__*/React.forwardRef(({
|
|
1792
1792
|
appName,
|
|
@@ -1798,10 +1798,10 @@
|
|
|
1798
1798
|
...restProps,
|
|
1799
1799
|
ref: ref,
|
|
1800
1800
|
"aria-label": `App switcher: ${appName}`,
|
|
1801
|
-
className: styles$
|
|
1801
|
+
className: styles$j.button,
|
|
1802
1802
|
kind: "neutral-inline",
|
|
1803
1803
|
label: /*#__PURE__*/React.createElement("span", {
|
|
1804
|
-
className: styles$
|
|
1804
|
+
className: styles$j.label
|
|
1805
1805
|
}, isAccounts ? "Account settings" : appName),
|
|
1806
1806
|
prefix: isAccounts ? (/*#__PURE__*/React.createElement(MonoAppIcon, {
|
|
1807
1807
|
appName: "Accounts",
|
|
@@ -1812,13 +1812,13 @@
|
|
|
1812
1812
|
size: 22
|
|
1813
1813
|
})),
|
|
1814
1814
|
suffix: /*#__PURE__*/React.createElement(DisclosureChevronIcon, {
|
|
1815
|
-
className: `${styles$
|
|
1815
|
+
className: `${styles$j.chevron} symbol`
|
|
1816
1816
|
})
|
|
1817
1817
|
});
|
|
1818
1818
|
});
|
|
1819
1819
|
AppsButton.displayName = "AppsButton";
|
|
1820
1820
|
|
|
1821
|
-
var styles$
|
|
1821
|
+
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"};
|
|
1822
1822
|
|
|
1823
1823
|
const AppsMenu = ({
|
|
1824
1824
|
appName,
|
|
@@ -1839,8 +1839,8 @@
|
|
|
1839
1839
|
}, /*#__PURE__*/React.createElement("a", {
|
|
1840
1840
|
"aria-current": isCurrent ? "page" : undefined,
|
|
1841
1841
|
"aria-label": name,
|
|
1842
|
-
className: classnames(styles$
|
|
1843
|
-
[styles$
|
|
1842
|
+
className: classnames(styles$i.link, {
|
|
1843
|
+
[styles$i.current]: isCurrent
|
|
1844
1844
|
}),
|
|
1845
1845
|
"data-pendo": `app-switcher--change-app--${name}`,
|
|
1846
1846
|
"data-turbolinks": false,
|
|
@@ -1856,22 +1856,22 @@
|
|
|
1856
1856
|
colors: colors
|
|
1857
1857
|
})), /*#__PURE__*/React.createElement(tapestry.PopoverContent, {
|
|
1858
1858
|
"aria-label": "Switch app",
|
|
1859
|
-
className: styles$
|
|
1859
|
+
className: styles$i["popover-content"],
|
|
1860
1860
|
placement: "bottom start"
|
|
1861
1861
|
}, /*#__PURE__*/React.createElement("nav", {
|
|
1862
|
-
className: styles$
|
|
1862
|
+
className: styles$i.nav,
|
|
1863
1863
|
"data-pendo": "app-switcher"
|
|
1864
1864
|
}, /*#__PURE__*/React.createElement("ul", {
|
|
1865
|
-
className: styles$
|
|
1865
|
+
className: styles$i.list,
|
|
1866
1866
|
role: "list"
|
|
1867
1867
|
}, homeProduct && renderProductLink(homeProduct.name), restProducts.map(({
|
|
1868
1868
|
name
|
|
1869
1869
|
}) => renderProductLink(name)), accountsProduct && (/*#__PURE__*/React.createElement("li", {
|
|
1870
|
-
className: styles$
|
|
1870
|
+
className: styles$i["accounts-item"]
|
|
1871
1871
|
}, /*#__PURE__*/React.createElement("a", {
|
|
1872
1872
|
"aria-current": appName === accountsProduct.name ? "page" : undefined,
|
|
1873
1873
|
"aria-label": "Account settings",
|
|
1874
|
-
className: classnames(styles$
|
|
1874
|
+
className: classnames(styles$i.link, styles$i["accounts-link"]),
|
|
1875
1875
|
"data-pendo": "app-switcher--change-app--Accounts",
|
|
1876
1876
|
"data-turbolinks": false,
|
|
1877
1877
|
href: pcoUrl$1(env)("accounts") + getAppsSwitchProductPath(accountsProduct.name)
|
|
@@ -2079,7 +2079,7 @@
|
|
|
2079
2079
|
})) : (/*#__PURE__*/React.createElement("div", null, "appName not supported"));
|
|
2080
2080
|
}
|
|
2081
2081
|
|
|
2082
|
-
var styles$
|
|
2082
|
+
var styles$h = {"unbutton":"unbutton-lEbTR"};
|
|
2083
2083
|
|
|
2084
2084
|
function Unbutton({
|
|
2085
2085
|
className,
|
|
@@ -2088,7 +2088,7 @@
|
|
|
2088
2088
|
...nativeProps
|
|
2089
2089
|
}) {
|
|
2090
2090
|
return /*#__PURE__*/React.createElement("button", {
|
|
2091
|
-
className: classnames(styles$
|
|
2091
|
+
className: classnames(styles$h.unbutton, className),
|
|
2092
2092
|
style: {
|
|
2093
2093
|
...style
|
|
2094
2094
|
},
|
|
@@ -2097,7 +2097,7 @@
|
|
|
2097
2097
|
});
|
|
2098
2098
|
}
|
|
2099
2099
|
|
|
2100
|
-
var styles$
|
|
2100
|
+
var styles$g = {"button":"button-wsipc","button-accounts":"button-accounts-zQmBM","chevron":"chevron-obyBF","is-expanded":"is-expanded-PoCQ9"};
|
|
2101
2101
|
|
|
2102
2102
|
const LegacyAppsButton = ({
|
|
2103
2103
|
appName,
|
|
@@ -2112,8 +2112,8 @@
|
|
|
2112
2112
|
"aria-haspopup": "true",
|
|
2113
2113
|
"aria-label": `App switcher: ${appName}`,
|
|
2114
2114
|
onClick: onClick,
|
|
2115
|
-
className: classnames(styles$
|
|
2116
|
-
[styles$
|
|
2115
|
+
className: classnames(styles$g.button, {
|
|
2116
|
+
[styles$g["is-expanded"]]: expanded
|
|
2117
2117
|
}),
|
|
2118
2118
|
type: "button",
|
|
2119
2119
|
style: style,
|
|
@@ -2122,7 +2122,7 @@
|
|
|
2122
2122
|
appName: "Accounts",
|
|
2123
2123
|
colors: colors
|
|
2124
2124
|
}), /*#__PURE__*/React.createElement("div", {
|
|
2125
|
-
className: styles$
|
|
2125
|
+
className: styles$g["button-accounts"]
|
|
2126
2126
|
}, "Account settings"))) : (/*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ColorAppIcon, {
|
|
2127
2127
|
appName: appName.replace(/[\s-]/, "")
|
|
2128
2128
|
}), /*#__PURE__*/React.createElement(MonoAppName, {
|
|
@@ -2130,7 +2130,7 @@
|
|
|
2130
2130
|
key: "mono-app-name",
|
|
2131
2131
|
size: 24
|
|
2132
2132
|
}))), /*#__PURE__*/React.createElement(DisclosureChevronIcon, {
|
|
2133
|
-
className: styles$
|
|
2133
|
+
className: styles$g.chevron,
|
|
2134
2134
|
key: "disclosure-chevron-icon"
|
|
2135
2135
|
}));
|
|
2136
2136
|
};
|
|
@@ -2263,7 +2263,7 @@
|
|
|
2263
2263
|
}
|
|
2264
2264
|
}
|
|
2265
2265
|
|
|
2266
|
-
var styles$
|
|
2266
|
+
var styles$f = {"popup-root":"popup-root-SeL5u","popup":"popup-nQXYW","is-visible":"is-visible-3DAUP"};
|
|
2267
2267
|
|
|
2268
2268
|
const Popup = ({
|
|
2269
2269
|
className,
|
|
@@ -2271,8 +2271,8 @@
|
|
|
2271
2271
|
isVisible,
|
|
2272
2272
|
...nativeProps
|
|
2273
2273
|
}) => (/*#__PURE__*/React.createElement(C, {
|
|
2274
|
-
className: classnames(styles$
|
|
2275
|
-
[styles$
|
|
2274
|
+
className: classnames(styles$f.popup, {
|
|
2275
|
+
[styles$f["is-visible"]]: isVisible
|
|
2276
2276
|
}, className),
|
|
2277
2277
|
...nativeProps
|
|
2278
2278
|
}));
|
|
@@ -2280,11 +2280,11 @@
|
|
|
2280
2280
|
const PopupRoot = ({
|
|
2281
2281
|
...nativeProps
|
|
2282
2282
|
}) => (/*#__PURE__*/React.createElement("div", {
|
|
2283
|
-
className: styles$
|
|
2283
|
+
className: styles$f["popup-root"],
|
|
2284
2284
|
...nativeProps
|
|
2285
2285
|
}));
|
|
2286
2286
|
|
|
2287
|
-
var styles$
|
|
2287
|
+
var styles$e = {"popup":"popup-bVhSa"};
|
|
2288
2288
|
|
|
2289
2289
|
const LegacyAppsMenu = ({
|
|
2290
2290
|
appName,
|
|
@@ -2322,7 +2322,7 @@
|
|
|
2322
2322
|
cleanup: !visible,
|
|
2323
2323
|
component: Outsider,
|
|
2324
2324
|
onOutsideClick: toggle,
|
|
2325
|
-
className: styles$
|
|
2325
|
+
className: styles$e.popup,
|
|
2326
2326
|
isVisible: visible
|
|
2327
2327
|
}, /*#__PURE__*/React.createElement("menu", {
|
|
2328
2328
|
ref: menuRef,
|
|
@@ -3235,27 +3235,34 @@ true;
|
|
|
3235
3235
|
const isMac = () => /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
|
3236
3236
|
const hasCommandKey = event => isMac() ? event.metaKey : event.ctrlKey;
|
|
3237
3237
|
const commandKeyLabel = () => isMac() ? "⌘" : "Ctrl+";
|
|
3238
|
+
const isSearchShortcut = event => event.key.toLowerCase() === "k" && !event.altKey && !event.shiftKey && hasCommandKey(event);
|
|
3239
|
+
// Products opened their own search with `/` before this one replaced it.
|
|
3240
|
+
const isLegacySearchShortcut = event => event.key === "/" && !event.altKey && !event.ctrlKey && !event.metaKey && !isTypingIn(event.target);
|
|
3241
|
+
const isCopyShortcut = event => event.key.toLowerCase() === "c" && !event.altKey && !event.shiftKey && hasCommandKey(event);
|
|
3242
|
+
const isTypingIn = target => target instanceof Element && target.closest('input, select, textarea, [contenteditable]:not([contenteditable="false"])') !== null;
|
|
3243
|
+
const isTypingKey = event => event.key.length === 1 && event.key !== " " && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
3244
|
+
const verticalStep = key => ({
|
|
3245
|
+
ArrowDown: 1,
|
|
3246
|
+
ArrowUp: -1
|
|
3247
|
+
})[key];
|
|
3248
|
+
const horizontalStep = key => ({
|
|
3249
|
+
ArrowLeft: -1,
|
|
3250
|
+
ArrowRight: 1
|
|
3251
|
+
})[key];
|
|
3238
3252
|
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
} catch {
|
|
3251
|
-
// Storage can be full or blocked; search still works without it.
|
|
3252
|
-
}
|
|
3253
|
+
function SearchButton({
|
|
3254
|
+
onClick
|
|
3255
|
+
}) {
|
|
3256
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
3257
|
+
"aria-keyshortcuts": `${isMac() ? "Meta+K" : "Control+K"} /`,
|
|
3258
|
+
"aria-label": "Search",
|
|
3259
|
+
onClick: onClick,
|
|
3260
|
+
type: "button"
|
|
3261
|
+
}, /*#__PURE__*/React.createElement(Spyglass, {
|
|
3262
|
+
fill: "currentColor"
|
|
3263
|
+
}));
|
|
3253
3264
|
}
|
|
3254
3265
|
|
|
3255
|
-
var styles$c = {"visuallyHidden":"visuallyHidden-C28ju"};
|
|
3256
|
-
|
|
3257
|
-
var styles$b = {"tab":"tab-lQLDx"};
|
|
3258
|
-
|
|
3259
3266
|
// useId isn't available on React 17, which our peer range still supports.
|
|
3260
3267
|
let instanceCount$1 = 0;
|
|
3261
3268
|
function useInstanceId(prefix) {
|
|
@@ -3263,58 +3270,237 @@ true;
|
|
|
3263
3270
|
return id;
|
|
3264
3271
|
}
|
|
3265
3272
|
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3273
|
+
// The versions home-mobile pins, so web and mobile read the same response
|
|
3274
|
+
// shapes. Some endpoints only exist from a version on: Registrations' me,
|
|
3275
|
+
// product_search_results, and pcrl_lookups need 2025-05-01.
|
|
3276
|
+
const API_VERSIONS = {
|
|
3277
|
+
calendar: "2022-07-07",
|
|
3278
|
+
"check-ins": "2025-05-28",
|
|
3279
|
+
giving: "2019-10-18",
|
|
3280
|
+
groups: "2023-07-10",
|
|
3281
|
+
home: "2018-08-01",
|
|
3282
|
+
people: "2023-03-21",
|
|
3283
|
+
publishing: "2024-03-25",
|
|
3284
|
+
registrations: "2025-05-01",
|
|
3285
|
+
services: "2018-11-01"
|
|
3286
|
+
};
|
|
3287
|
+
// For a `/~api/{product}/v2/...` URL, the header that pins its product's
|
|
3288
|
+
// version.
|
|
3289
|
+
function apiVersionHeaders(url) {
|
|
3290
|
+
const [,, product] = new URL(url).pathname.split("/");
|
|
3291
|
+
const version = API_VERSIONS[product];
|
|
3292
|
+
if (version) {
|
|
3293
|
+
return {
|
|
3294
|
+
"X-PCO-API-Version": version
|
|
3295
|
+
};
|
|
3296
|
+
} else {
|
|
3297
|
+
return {};
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
|
|
3301
|
+
const CACHE_TTL_MS = 60000;
|
|
3302
|
+
const MAX_ENTRIES$1 = 50;
|
|
3303
|
+
const cache = new Map();
|
|
3304
|
+
function cachedRequest(url) {
|
|
3305
|
+
const cached = cache.get(url);
|
|
3306
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
3307
|
+
// Re-inserting keeps the Map in recently-used order for eviction.
|
|
3308
|
+
cache.delete(url);
|
|
3309
|
+
cache.set(url, cached);
|
|
3310
|
+
return cached.promise;
|
|
3311
|
+
} else {
|
|
3312
|
+
return fetchIntoCache(url);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
function fetchIntoCache(url) {
|
|
3316
|
+
const promise = apiRequest(defaultFetch, url, {
|
|
3317
|
+
headers: apiVersionHeaders(url)
|
|
3318
|
+
}).then(({
|
|
3319
|
+
json,
|
|
3320
|
+
ok
|
|
3321
|
+
}) => {
|
|
3322
|
+
if (!ok || json === null) throw new Error(`Request failed: ${url}`);
|
|
3323
|
+
return json;
|
|
3324
|
+
});
|
|
3325
|
+
// In-flight entries never expire, so every caller shares the one fetch.
|
|
3326
|
+
const entry = {
|
|
3327
|
+
expiresAt: Infinity,
|
|
3328
|
+
promise
|
|
3329
|
+
};
|
|
3330
|
+
cache.set(url, entry);
|
|
3331
|
+
promise.then(() => entry.expiresAt = Date.now() + CACHE_TTL_MS, () => cache.get(url) === entry && cache.delete(url));
|
|
3332
|
+
if (cache.size > MAX_ENTRIES$1) cache.delete(cache.keys().next().value);
|
|
3333
|
+
return promise;
|
|
3334
|
+
}
|
|
3335
|
+
function useCachedRequest(url) {
|
|
3336
|
+
const [settled, setSettled] = React.useState();
|
|
3337
|
+
React.useEffect(() => {
|
|
3338
|
+
if (url) {
|
|
3339
|
+
let current = true;
|
|
3340
|
+
cachedRequest(url).then(data => current && setSettled({
|
|
3341
|
+
data,
|
|
3342
|
+
url
|
|
3343
|
+
}), () => current && setSettled({
|
|
3344
|
+
failed: true,
|
|
3345
|
+
url
|
|
3346
|
+
}));
|
|
3347
|
+
return () => {
|
|
3348
|
+
current = false;
|
|
3349
|
+
};
|
|
3288
3350
|
} else {
|
|
3289
|
-
|
|
3351
|
+
return undefined;
|
|
3352
|
+
}
|
|
3353
|
+
}, [url]);
|
|
3354
|
+
if (!url) {
|
|
3355
|
+
return {
|
|
3356
|
+
status: "idle"
|
|
3357
|
+
};
|
|
3358
|
+
} else if ((settled === null || settled === void 0 ? void 0 : settled.url) !== url) {
|
|
3359
|
+
return {
|
|
3360
|
+
data: settled && "data" in settled ? settled.data : undefined,
|
|
3361
|
+
status: "loading"
|
|
3362
|
+
};
|
|
3363
|
+
} else if ("data" in settled) {
|
|
3364
|
+
return {
|
|
3365
|
+
data: settled.data,
|
|
3366
|
+
status: "done"
|
|
3367
|
+
};
|
|
3368
|
+
} else {
|
|
3369
|
+
return {
|
|
3370
|
+
status: "error"
|
|
3371
|
+
};
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
// One request per URL, for callers that fan out to a varying number of
|
|
3375
|
+
// endpoints. Unlike `useCachedRequest`, a URL that hasn't settled yet has no
|
|
3376
|
+
// earlier data to fall back on.
|
|
3377
|
+
function useCachedRequests(urls) {
|
|
3378
|
+
const [settled, setSettled] = React.useState({});
|
|
3379
|
+
// Keyed by value because each settle re-renders the caller, and a caller
|
|
3380
|
+
// that builds a fresh `urls` array on render would otherwise loop forever.
|
|
3381
|
+
const key = urls.join("\n");
|
|
3382
|
+
React.useEffect(() => {
|
|
3383
|
+
let current = true;
|
|
3384
|
+
const settle = result => current && setSettled(prev => ({
|
|
3385
|
+
...prev,
|
|
3386
|
+
[result.url]: result
|
|
3387
|
+
}));
|
|
3388
|
+
for (const url of key.split("\n").filter(Boolean)) {
|
|
3389
|
+
cachedRequest(url).then(data => settle({
|
|
3390
|
+
data,
|
|
3391
|
+
url
|
|
3392
|
+
}), () => settle({
|
|
3393
|
+
failed: true,
|
|
3394
|
+
url
|
|
3395
|
+
}));
|
|
3290
3396
|
}
|
|
3397
|
+
return () => {
|
|
3398
|
+
current = false;
|
|
3399
|
+
};
|
|
3400
|
+
}, [key]);
|
|
3401
|
+
return urls.map(url => {
|
|
3402
|
+
const result = settled[url];
|
|
3403
|
+
if (!result) {
|
|
3404
|
+
return {
|
|
3405
|
+
status: "loading"
|
|
3406
|
+
};
|
|
3407
|
+
} else if ("data" in result) {
|
|
3408
|
+
return {
|
|
3409
|
+
data: result.data,
|
|
3410
|
+
status: "done"
|
|
3411
|
+
};
|
|
3412
|
+
} else {
|
|
3413
|
+
return {
|
|
3414
|
+
status: "error"
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
});
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
function productSearchUrl(product, query) {
|
|
3421
|
+
const params = new URLSearchParams({
|
|
3422
|
+
per_page: "100",
|
|
3423
|
+
"where[term]": query
|
|
3424
|
+
});
|
|
3425
|
+
return `${window.location.origin}/~api/${product}/v2/product_search_results?${params}`;
|
|
3426
|
+
}
|
|
3427
|
+
function groupByType({
|
|
3428
|
+
data,
|
|
3429
|
+
meta
|
|
3430
|
+
}) {
|
|
3431
|
+
var _a, _b;
|
|
3432
|
+
const typeOrder = (_a = meta === null || meta === void 0 ? void 0 : meta.type_order) !== null && _a !== void 0 ? _a : [];
|
|
3433
|
+
const groups = new Map();
|
|
3434
|
+
for (const result of data) {
|
|
3435
|
+
const {
|
|
3436
|
+
type
|
|
3437
|
+
} = result.attributes;
|
|
3438
|
+
if (!groups.has(type)) groups.set(type, {
|
|
3439
|
+
results: [],
|
|
3440
|
+
type
|
|
3441
|
+
});
|
|
3442
|
+
(_b = groups.get(type)) === null || _b === void 0 ? void 0 : _b.results.push(result);
|
|
3443
|
+
}
|
|
3444
|
+
const rank = type => {
|
|
3445
|
+
const index = typeOrder.indexOf(type);
|
|
3446
|
+
return index === -1 ? typeOrder.length : index;
|
|
3291
3447
|
};
|
|
3292
|
-
return
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3448
|
+
return [...groups.values()].sort((a, b) => rank(a.type) - rank(b.type));
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
function useDebouncedValue(value, delay) {
|
|
3452
|
+
const [debounced, setDebounced] = React.useState(value);
|
|
3453
|
+
React.useEffect(() => {
|
|
3454
|
+
const timeout = setTimeout(() => setDebounced(value), delay);
|
|
3455
|
+
return () => clearTimeout(timeout);
|
|
3456
|
+
}, [value, delay]);
|
|
3457
|
+
return debounced;
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3460
|
+
const SEARCH_DEBOUNCE_MS = 300;
|
|
3461
|
+
function useProductSearch(product, term) {
|
|
3462
|
+
const query = term.trim();
|
|
3463
|
+
const debouncedQuery = useDebouncedValue(query, SEARCH_DEBOUNCE_MS);
|
|
3464
|
+
const request = useCachedRequest(debouncedQuery ? productSearchUrl(product, debouncedQuery) : null);
|
|
3465
|
+
const response = "data" in request ? request.data : undefined;
|
|
3466
|
+
const settledProduct = useSettledProduct(product, request.status);
|
|
3467
|
+
// While a request loads, the previous response stays on screen, but only
|
|
3468
|
+
// if it was for this product: People results must never show under the
|
|
3469
|
+
// Services tab.
|
|
3470
|
+
const visibleResponse = request.status === "done" || settledProduct === product ? response : undefined;
|
|
3471
|
+
const groups = React.useMemo(() => visibleResponse && groupByType(visibleResponse), [visibleResponse]);
|
|
3472
|
+
if (!query) {
|
|
3473
|
+
return {
|
|
3474
|
+
status: "idle"
|
|
3475
|
+
};
|
|
3476
|
+
} else if (query !== debouncedQuery) {
|
|
3477
|
+
return {
|
|
3478
|
+
groups,
|
|
3479
|
+
status: "loading"
|
|
3480
|
+
};
|
|
3481
|
+
} else if (request.status === "done") {
|
|
3482
|
+
return {
|
|
3483
|
+
groups: groups !== null && groups !== void 0 ? groups : [],
|
|
3484
|
+
status: "done"
|
|
3485
|
+
};
|
|
3486
|
+
} else if (request.status === "error") {
|
|
3487
|
+
return {
|
|
3488
|
+
status: "error"
|
|
3489
|
+
};
|
|
3490
|
+
} else {
|
|
3491
|
+
return {
|
|
3492
|
+
groups,
|
|
3493
|
+
status: "loading"
|
|
3494
|
+
};
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
// The product the most recent finished request was for.
|
|
3498
|
+
function useSettledProduct(product, status) {
|
|
3499
|
+
const [settledProduct, setSettledProduct] = React.useState();
|
|
3500
|
+
React.useEffect(() => {
|
|
3501
|
+
if (status === "done") setSettledProduct(product);
|
|
3502
|
+
}, [product, status]);
|
|
3503
|
+
return settledProduct;
|
|
3318
3504
|
}
|
|
3319
3505
|
|
|
3320
3506
|
function parseValue(element) {
|
|
@@ -3383,10 +3569,14 @@ true;
|
|
|
3383
3569
|
return shim.useSyncExternalStore(recentlyVisitableMetadataStore.subscribe, () => recentlyVisitableMetadataStore.getState().metadata);
|
|
3384
3570
|
}
|
|
3385
3571
|
|
|
3386
|
-
|
|
3387
|
-
|
|
3572
|
+
// Entries match the ones home-mobile stores, so one list can sync across web
|
|
3573
|
+
// and mobile.
|
|
3574
|
+
const ENTRY_VERSION = 3;
|
|
3575
|
+
const MAX_ENTRIES = 50;
|
|
3388
3576
|
const MAX_TEXT_LENGTH = 200;
|
|
3389
3577
|
const PRODUCTS = ["accounts", "calendar", "check-ins", "giving", "groups", "home", "login", "people", "publishing", "registrations", "services"];
|
|
3578
|
+
// Login has no pages worth returning to.
|
|
3579
|
+
const APPS = PRODUCTS.filter(product => product !== "login");
|
|
3390
3580
|
function isId(value) {
|
|
3391
3581
|
return value !== "" && Array.from(value).every(character => character >= "0" && character <= "9");
|
|
3392
3582
|
}
|
|
@@ -3395,26 +3585,47 @@ true;
|
|
|
3395
3585
|
const segments = value.split("/");
|
|
3396
3586
|
return segments.length === 4 && PRODUCTS.some(product => product === segments[0]) && isId(segments[3]);
|
|
3397
3587
|
}
|
|
3588
|
+
function isApp(value) {
|
|
3589
|
+
return APPS.some(app => app === value);
|
|
3590
|
+
}
|
|
3591
|
+
// Links are built by resolving the path against its app's origin, so a stored
|
|
3592
|
+
// path must not be able to resolve anywhere else (`//evil.com`, `/\evil.com`).
|
|
3593
|
+
function isPath(value) {
|
|
3594
|
+
const origin = "https://app.invalid";
|
|
3595
|
+
try {
|
|
3596
|
+
return typeof value === "string" && value.startsWith("/") && new URL(value, origin).origin === origin;
|
|
3597
|
+
} catch {
|
|
3598
|
+
return false;
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3398
3601
|
function isNonBlankString(value) {
|
|
3399
3602
|
return typeof value === "string" && value.trim() !== "";
|
|
3400
3603
|
}
|
|
3604
|
+
function isOptionalString(value) {
|
|
3605
|
+
return value === undefined || typeof value === "string";
|
|
3606
|
+
}
|
|
3401
3607
|
function isRecord(value) {
|
|
3402
3608
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3403
3609
|
}
|
|
3610
|
+
function isPageMetadata(value) {
|
|
3611
|
+
return value === undefined || isRecord(value) && isOptionalString(value.details) && isOptionalString(value.type);
|
|
3612
|
+
}
|
|
3613
|
+
// The query string is part of the link but not of the page's identity, so
|
|
3614
|
+
// revisiting with other filters moves the existing entry instead of adding one.
|
|
3404
3615
|
function entryKey(entry) {
|
|
3405
3616
|
if (entry.type === "resource") {
|
|
3406
3617
|
return `resource:${entry.pcrl}`;
|
|
3407
3618
|
} else {
|
|
3408
|
-
return `page:${entry.
|
|
3619
|
+
return `page:${entry.app}:${entry.path.split("?")[0]}`;
|
|
3409
3620
|
}
|
|
3410
3621
|
}
|
|
3411
3622
|
function isEntry(value) {
|
|
3412
|
-
if (!isRecord(value)) {
|
|
3623
|
+
if (!isRecord(value) || value.version !== ENTRY_VERSION || typeof value.visitedAt !== "string") {
|
|
3413
3624
|
return false;
|
|
3414
3625
|
} else if (value.type === "resource") {
|
|
3415
3626
|
return typeof value.pcrl === "string" && isPcrl(value.pcrl);
|
|
3416
3627
|
} else if (value.type === "page") {
|
|
3417
|
-
return
|
|
3628
|
+
return isApp(value.app) && isPath(value.path) && isNonBlankString(value.title) && isPageMetadata(value.metadata);
|
|
3418
3629
|
} else {
|
|
3419
3630
|
return false;
|
|
3420
3631
|
}
|
|
@@ -3423,58 +3634,114 @@ true;
|
|
|
3423
3634
|
function clampText(value) {
|
|
3424
3635
|
return Array.from(value).slice(0, MAX_TEXT_LENGTH).join("");
|
|
3425
3636
|
}
|
|
3426
|
-
function
|
|
3427
|
-
|
|
3428
|
-
|
|
3637
|
+
function clampMetadata({
|
|
3638
|
+
details,
|
|
3639
|
+
type
|
|
3640
|
+
}) {
|
|
3641
|
+
return {
|
|
3642
|
+
...(details && {
|
|
3643
|
+
details: clampText(details)
|
|
3644
|
+
}),
|
|
3645
|
+
...(type && {
|
|
3646
|
+
type: clampText(type)
|
|
3647
|
+
})
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
function clampVisit(visit) {
|
|
3651
|
+
if (visit.type === "resource") {
|
|
3652
|
+
return visit;
|
|
3429
3653
|
} else {
|
|
3430
3654
|
return {
|
|
3431
|
-
...
|
|
3432
|
-
|
|
3433
|
-
|
|
3655
|
+
...visit,
|
|
3656
|
+
...(visit.metadata && {
|
|
3657
|
+
metadata: clampMetadata(visit.metadata)
|
|
3658
|
+
}),
|
|
3659
|
+
title: clampText(visit.title.trim())
|
|
3434
3660
|
};
|
|
3435
3661
|
}
|
|
3436
3662
|
}
|
|
3663
|
+
function toEntry(visit, visitedAt) {
|
|
3664
|
+
return {
|
|
3665
|
+
...clampVisit(visit),
|
|
3666
|
+
version: ENTRY_VERSION,
|
|
3667
|
+
visitedAt: visitedAt.toISOString()
|
|
3668
|
+
};
|
|
3669
|
+
}
|
|
3437
3670
|
// Recents are disposable: anything unexpected reads as an empty list (or, for
|
|
3438
3671
|
// a single bad entry, a list without it) rather than throwing.
|
|
3439
|
-
function parseRecentlyVisited(value
|
|
3672
|
+
function parseRecentlyVisited(value) {
|
|
3440
3673
|
let parsed = null;
|
|
3441
3674
|
try {
|
|
3442
3675
|
parsed = JSON.parse(value !== null && value !== void 0 ? value : "null");
|
|
3443
3676
|
} catch {
|
|
3444
3677
|
parsed = null;
|
|
3445
3678
|
}
|
|
3446
|
-
if (
|
|
3447
|
-
return parsed.
|
|
3679
|
+
if (Array.isArray(parsed)) {
|
|
3680
|
+
return parsed.filter(isEntry);
|
|
3448
3681
|
} else {
|
|
3449
3682
|
return [];
|
|
3450
3683
|
}
|
|
3451
3684
|
}
|
|
3452
|
-
function addVisit(entries,
|
|
3453
|
-
const key = entryKey(
|
|
3454
|
-
return [
|
|
3455
|
-
}
|
|
3456
|
-
function serializeRecentlyVisited(entries, personId) {
|
|
3457
|
-
return JSON.stringify({
|
|
3458
|
-
entries,
|
|
3459
|
-
person: personId,
|
|
3460
|
-
v: FORMAT_VERSION
|
|
3461
|
-
});
|
|
3685
|
+
function addVisit(entries, entry) {
|
|
3686
|
+
const key = entryKey(entry);
|
|
3687
|
+
return [entry, ...entries.filter(existing => entryKey(existing) !== key)].slice(0, MAX_ENTRIES);
|
|
3462
3688
|
}
|
|
3463
3689
|
|
|
3464
|
-
// The
|
|
3690
|
+
// The app whose URL, in this environment, has the current page's host.
|
|
3465
3691
|
// Reversing pcoUrl handles every environment @planningcenter/url knows about,
|
|
3466
|
-
// and guarantees the stored
|
|
3467
|
-
function
|
|
3692
|
+
// and guarantees the stored app rebuilds a working link.
|
|
3693
|
+
function currentApp() {
|
|
3468
3694
|
var _a;
|
|
3469
|
-
return (_a =
|
|
3695
|
+
return (_a = APPS.find(app => new URL(pcoUrl$1.pcoUrl(app)).hostname === window.location.hostname)) !== null && _a !== void 0 ? _a : null;
|
|
3470
3696
|
}
|
|
3471
|
-
function
|
|
3697
|
+
function isFilled(value) {
|
|
3698
|
+
return typeof value === "string" && value !== "";
|
|
3699
|
+
}
|
|
3700
|
+
// The tag's metadata is product-supplied JSON; only its string `type` and
|
|
3701
|
+
// `details` carry over, and an entry without either has no metadata at all.
|
|
3702
|
+
function metadataFromPage(metadata) {
|
|
3472
3703
|
var _a;
|
|
3473
3704
|
try {
|
|
3474
|
-
const
|
|
3475
|
-
|
|
3705
|
+
const {
|
|
3706
|
+
details,
|
|
3707
|
+
type
|
|
3708
|
+
} = (_a = JSON.parse(metadata !== null && metadata !== void 0 ? metadata : "{}")) !== null && _a !== void 0 ? _a : {};
|
|
3709
|
+
if (isFilled(details) || isFilled(type)) {
|
|
3710
|
+
return {
|
|
3711
|
+
...(isFilled(details) && {
|
|
3712
|
+
details
|
|
3713
|
+
}),
|
|
3714
|
+
...(isFilled(type) && {
|
|
3715
|
+
type
|
|
3716
|
+
})
|
|
3717
|
+
};
|
|
3718
|
+
} else {
|
|
3719
|
+
return undefined;
|
|
3720
|
+
}
|
|
3476
3721
|
} catch {
|
|
3477
|
-
return
|
|
3722
|
+
return undefined;
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
// Staff impersonating someone browse under `/O<org id>/P<person id>/…`.
|
|
3726
|
+
function withoutImpersonation(segments) {
|
|
3727
|
+
const [org = "", person = ""] = segments;
|
|
3728
|
+
if (org.startsWith("O") && isId(org.slice(1)) && person.startsWith("P") && isId(person.slice(1))) {
|
|
3729
|
+
return segments.slice(2);
|
|
3730
|
+
} else {
|
|
3731
|
+
return segments;
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
// Normalized the way home-mobile does it, so a page visited on web and on
|
|
3735
|
+
// mobile is one entry once the list syncs.
|
|
3736
|
+
function pathFromLocation({
|
|
3737
|
+
pathname,
|
|
3738
|
+
search
|
|
3739
|
+
}) {
|
|
3740
|
+
const segments = withoutImpersonation(pathname.split("/").filter(Boolean));
|
|
3741
|
+
if (segments.length === 0) {
|
|
3742
|
+
return "/";
|
|
3743
|
+
} else {
|
|
3744
|
+
return `/${segments.join("/")}${search.length > 1 ? search : ""}`;
|
|
3478
3745
|
}
|
|
3479
3746
|
}
|
|
3480
3747
|
// pco:resource is the more specific signal, so it wins when both tags are
|
|
@@ -3484,17 +3751,20 @@ true;
|
|
|
3484
3751
|
resource,
|
|
3485
3752
|
title
|
|
3486
3753
|
}) {
|
|
3487
|
-
const
|
|
3754
|
+
const app = currentApp();
|
|
3488
3755
|
if (resource && isPcrl(resource)) {
|
|
3489
3756
|
return {
|
|
3490
3757
|
pcrl: resource,
|
|
3491
3758
|
type: "resource"
|
|
3492
3759
|
};
|
|
3493
|
-
} else if (title && title.trim() !== "" &&
|
|
3760
|
+
} else if (title && title.trim() !== "" && app) {
|
|
3761
|
+
const pageMetadata = metadataFromPage(metadata);
|
|
3494
3762
|
return {
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3763
|
+
app,
|
|
3764
|
+
...(pageMetadata && {
|
|
3765
|
+
metadata: pageMetadata
|
|
3766
|
+
}),
|
|
3767
|
+
path: pathFromLocation(window.location),
|
|
3498
3768
|
title,
|
|
3499
3769
|
type: "page"
|
|
3500
3770
|
};
|
|
@@ -3542,15 +3812,16 @@ true;
|
|
|
3542
3812
|
});
|
|
3543
3813
|
function readRecentlyVisited(scope) {
|
|
3544
3814
|
try {
|
|
3545
|
-
return parseRecentlyVisited(localStorage.getItem(storageKey(scope))
|
|
3815
|
+
return parseRecentlyVisited(localStorage.getItem(storageKey(scope)));
|
|
3546
3816
|
} catch {
|
|
3547
3817
|
return [];
|
|
3548
3818
|
}
|
|
3549
3819
|
}
|
|
3550
3820
|
function recordVisit(visit, scope) {
|
|
3551
|
-
|
|
3821
|
+
const entry = toEntry(visit, new Date());
|
|
3822
|
+
if (isEntry(entry)) {
|
|
3552
3823
|
try {
|
|
3553
|
-
localStorage.setItem(storageKey(scope),
|
|
3824
|
+
localStorage.setItem(storageKey(scope), JSON.stringify(addVisit(readRecentlyVisited(scope), entry)));
|
|
3554
3825
|
changes.setState({
|
|
3555
3826
|
version: changes.getState().version + 1
|
|
3556
3827
|
});
|
|
@@ -3571,153 +3842,6 @@ true;
|
|
|
3571
3842
|
}) : [], [env, personId, version]);
|
|
3572
3843
|
}
|
|
3573
3844
|
|
|
3574
|
-
// The versions home-mobile pins, so web and mobile read the same response
|
|
3575
|
-
// shapes. Some endpoints only exist from a version on: Registrations' me,
|
|
3576
|
-
// product_search_results, and pcrl_lookups need 2025-05-01.
|
|
3577
|
-
const API_VERSIONS = {
|
|
3578
|
-
calendar: "2022-07-07",
|
|
3579
|
-
"check-ins": "2025-05-28",
|
|
3580
|
-
giving: "2019-10-18",
|
|
3581
|
-
groups: "2023-07-10",
|
|
3582
|
-
home: "2018-08-01",
|
|
3583
|
-
people: "2023-03-21",
|
|
3584
|
-
publishing: "2024-03-25",
|
|
3585
|
-
registrations: "2025-05-01",
|
|
3586
|
-
services: "2018-11-01"
|
|
3587
|
-
};
|
|
3588
|
-
// For a `/~api/{product}/v2/...` URL, the header that pins its product's
|
|
3589
|
-
// version.
|
|
3590
|
-
function apiVersionHeaders(url) {
|
|
3591
|
-
const [,, product] = new URL(url).pathname.split("/");
|
|
3592
|
-
const version = API_VERSIONS[product];
|
|
3593
|
-
if (version) {
|
|
3594
|
-
return {
|
|
3595
|
-
"X-PCO-API-Version": version
|
|
3596
|
-
};
|
|
3597
|
-
} else {
|
|
3598
|
-
return {};
|
|
3599
|
-
}
|
|
3600
|
-
}
|
|
3601
|
-
|
|
3602
|
-
const CACHE_TTL_MS = 60000;
|
|
3603
|
-
const MAX_ENTRIES = 50;
|
|
3604
|
-
const cache = new Map();
|
|
3605
|
-
function cachedRequest(url) {
|
|
3606
|
-
const cached = cache.get(url);
|
|
3607
|
-
if (cached && cached.expiresAt > Date.now()) {
|
|
3608
|
-
// Re-inserting keeps the Map in recently-used order for eviction.
|
|
3609
|
-
cache.delete(url);
|
|
3610
|
-
cache.set(url, cached);
|
|
3611
|
-
return cached.promise;
|
|
3612
|
-
} else {
|
|
3613
|
-
return fetchIntoCache(url);
|
|
3614
|
-
}
|
|
3615
|
-
}
|
|
3616
|
-
function fetchIntoCache(url) {
|
|
3617
|
-
const promise = apiRequest(defaultFetch, url, {
|
|
3618
|
-
headers: apiVersionHeaders(url)
|
|
3619
|
-
}).then(({
|
|
3620
|
-
json,
|
|
3621
|
-
ok
|
|
3622
|
-
}) => {
|
|
3623
|
-
if (!ok || json === null) throw new Error(`Request failed: ${url}`);
|
|
3624
|
-
return json;
|
|
3625
|
-
});
|
|
3626
|
-
// In-flight entries never expire, so every caller shares the one fetch.
|
|
3627
|
-
const entry = {
|
|
3628
|
-
expiresAt: Infinity,
|
|
3629
|
-
promise
|
|
3630
|
-
};
|
|
3631
|
-
cache.set(url, entry);
|
|
3632
|
-
promise.then(() => entry.expiresAt = Date.now() + CACHE_TTL_MS, () => cache.get(url) === entry && cache.delete(url));
|
|
3633
|
-
if (cache.size > MAX_ENTRIES) cache.delete(cache.keys().next().value);
|
|
3634
|
-
return promise;
|
|
3635
|
-
}
|
|
3636
|
-
function useCachedRequest(url) {
|
|
3637
|
-
const [settled, setSettled] = React.useState();
|
|
3638
|
-
React.useEffect(() => {
|
|
3639
|
-
if (url) {
|
|
3640
|
-
let current = true;
|
|
3641
|
-
cachedRequest(url).then(data => current && setSettled({
|
|
3642
|
-
data,
|
|
3643
|
-
url
|
|
3644
|
-
}), () => current && setSettled({
|
|
3645
|
-
failed: true,
|
|
3646
|
-
url
|
|
3647
|
-
}));
|
|
3648
|
-
return () => {
|
|
3649
|
-
current = false;
|
|
3650
|
-
};
|
|
3651
|
-
} else {
|
|
3652
|
-
return undefined;
|
|
3653
|
-
}
|
|
3654
|
-
}, [url]);
|
|
3655
|
-
if (!url) {
|
|
3656
|
-
return {
|
|
3657
|
-
status: "idle"
|
|
3658
|
-
};
|
|
3659
|
-
} else if ((settled === null || settled === void 0 ? void 0 : settled.url) !== url) {
|
|
3660
|
-
return {
|
|
3661
|
-
data: settled && "data" in settled ? settled.data : undefined,
|
|
3662
|
-
status: "loading"
|
|
3663
|
-
};
|
|
3664
|
-
} else if ("data" in settled) {
|
|
3665
|
-
return {
|
|
3666
|
-
data: settled.data,
|
|
3667
|
-
status: "done"
|
|
3668
|
-
};
|
|
3669
|
-
} else {
|
|
3670
|
-
return {
|
|
3671
|
-
status: "error"
|
|
3672
|
-
};
|
|
3673
|
-
}
|
|
3674
|
-
}
|
|
3675
|
-
// One request per URL, for callers that fan out to a varying number of
|
|
3676
|
-
// endpoints. Unlike `useCachedRequest`, a URL that hasn't settled yet has no
|
|
3677
|
-
// earlier data to fall back on.
|
|
3678
|
-
function useCachedRequests(urls) {
|
|
3679
|
-
const [settled, setSettled] = React.useState({});
|
|
3680
|
-
// Keyed by value because each settle re-renders the caller, and a caller
|
|
3681
|
-
// that builds a fresh `urls` array on render would otherwise loop forever.
|
|
3682
|
-
const key = urls.join("\n");
|
|
3683
|
-
React.useEffect(() => {
|
|
3684
|
-
let current = true;
|
|
3685
|
-
const settle = result => current && setSettled(prev => ({
|
|
3686
|
-
...prev,
|
|
3687
|
-
[result.url]: result
|
|
3688
|
-
}));
|
|
3689
|
-
for (const url of key.split("\n").filter(Boolean)) {
|
|
3690
|
-
cachedRequest(url).then(data => settle({
|
|
3691
|
-
data,
|
|
3692
|
-
url
|
|
3693
|
-
}), () => settle({
|
|
3694
|
-
failed: true,
|
|
3695
|
-
url
|
|
3696
|
-
}));
|
|
3697
|
-
}
|
|
3698
|
-
return () => {
|
|
3699
|
-
current = false;
|
|
3700
|
-
};
|
|
3701
|
-
}, [key]);
|
|
3702
|
-
return urls.map(url => {
|
|
3703
|
-
const result = settled[url];
|
|
3704
|
-
if (!result) {
|
|
3705
|
-
return {
|
|
3706
|
-
status: "loading"
|
|
3707
|
-
};
|
|
3708
|
-
} else if ("data" in result) {
|
|
3709
|
-
return {
|
|
3710
|
-
data: result.data,
|
|
3711
|
-
status: "done"
|
|
3712
|
-
};
|
|
3713
|
-
} else {
|
|
3714
|
-
return {
|
|
3715
|
-
status: "error"
|
|
3716
|
-
};
|
|
3717
|
-
}
|
|
3718
|
-
});
|
|
3719
|
-
}
|
|
3720
|
-
|
|
3721
3845
|
const pcoUrl = pcoUrl$1;
|
|
3722
3846
|
|
|
3723
3847
|
// Resolves resource entries with one pcrl_lookups request per product.
|
|
@@ -3808,13 +3932,290 @@ true;
|
|
|
3808
3932
|
});
|
|
3809
3933
|
return `${window.location.origin}/~api/${product}/v2/pcrl_lookups?${params}`;
|
|
3810
3934
|
}
|
|
3811
|
-
// Built from the
|
|
3812
|
-
//
|
|
3935
|
+
// Built from the app rather than the current origin, so it stays right once
|
|
3936
|
+
// PCA-409 shares one list across product subdomains.
|
|
3813
3937
|
function pageUrl(entry, env) {
|
|
3814
|
-
return
|
|
3938
|
+
return new URL(entry.path, pcoUrl(env)(entry.app)).href;
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
function useRecentVisits(env) {
|
|
3942
|
+
const personId = useCurrentPersonId();
|
|
3943
|
+
const entries = useRecentlyVisited({
|
|
3944
|
+
env,
|
|
3945
|
+
personId
|
|
3946
|
+
});
|
|
3947
|
+
const [count, setCount] = React.useState(RECENTLY_VISITED_PAGE_SIZE);
|
|
3948
|
+
const shown = React.useMemo(() => entries.slice(0, count), [entries, count]);
|
|
3949
|
+
const hydrated = useHydratedRecentlyVisited(shown, env);
|
|
3950
|
+
// Resources show up once they're found. Ones that can't be found anymore,
|
|
3951
|
+
// or that the person can no longer see, are left out.
|
|
3952
|
+
const visits = hydrated.filter(isShown);
|
|
3953
|
+
const loading = hydrated.some(({
|
|
3954
|
+
status
|
|
3955
|
+
}) => status === "loading");
|
|
3956
|
+
const showMore = React.useCallback(() => setCount(current => current + RECENTLY_VISITED_PAGE_SIZE), []);
|
|
3957
|
+
return {
|
|
3958
|
+
count,
|
|
3959
|
+
hasMore: entries.length > count,
|
|
3960
|
+
loading,
|
|
3961
|
+
showMore,
|
|
3962
|
+
visits
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
function isShown(visit) {
|
|
3966
|
+
return visit.status === "page" || visit.status === "resolved";
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
function open(url, {
|
|
3970
|
+
newTab
|
|
3971
|
+
}) {
|
|
3972
|
+
if (newTab) {
|
|
3973
|
+
window.open(url, "_blank", "noopener");
|
|
3974
|
+
} else {
|
|
3975
|
+
window.location.assign(url);
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
// With text selected, ⌘C should copy that text as usual, not the link.
|
|
3979
|
+
function hasSelectedText(element) {
|
|
3980
|
+
var _a, _b;
|
|
3981
|
+
const selectedInField = element instanceof HTMLInputElement && element.selectionStart !== element.selectionEnd;
|
|
3982
|
+
return selectedInField || ((_b = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "") !== "";
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
const COPIED_FEEDBACK_MS = 1500;
|
|
3986
|
+
// `copiedUrl` stays set briefly after a copy so the UI can confirm it.
|
|
3987
|
+
function useCopyLink() {
|
|
3988
|
+
const [copiedUrl, setCopiedUrl] = React.useState(null);
|
|
3989
|
+
React.useEffect(() => {
|
|
3990
|
+
if (copiedUrl) {
|
|
3991
|
+
const timeout = setTimeout(() => setCopiedUrl(null), COPIED_FEEDBACK_MS);
|
|
3992
|
+
return () => clearTimeout(timeout);
|
|
3993
|
+
} else {
|
|
3994
|
+
return undefined;
|
|
3995
|
+
}
|
|
3996
|
+
}, [copiedUrl]);
|
|
3997
|
+
const copy = React.useCallback(url => {
|
|
3998
|
+
navigator.clipboard.writeText(url).then(() => setCopiedUrl(url));
|
|
3999
|
+
}, []);
|
|
4000
|
+
return {
|
|
4001
|
+
copiedUrl,
|
|
4002
|
+
copy
|
|
4003
|
+
};
|
|
4004
|
+
}
|
|
4005
|
+
|
|
4006
|
+
// Remembering which list the index belongs to puts the highlight back on the
|
|
4007
|
+
// first item whenever a new list replaces it, without an effect to reset it.
|
|
4008
|
+
// A list that grows or fills in under the same `list` keeps its highlight.
|
|
4009
|
+
function useResultNavigation(items, list) {
|
|
4010
|
+
const [highlight, setHighlight] = React.useState({
|
|
4011
|
+
index: 0,
|
|
4012
|
+
list
|
|
4013
|
+
});
|
|
4014
|
+
const highlightedIndex = highlight.list === list ? highlight.index : 0;
|
|
4015
|
+
const highlighted = items[highlightedIndex];
|
|
4016
|
+
const {
|
|
4017
|
+
copiedUrl,
|
|
4018
|
+
copy
|
|
4019
|
+
} = useCopyLink();
|
|
4020
|
+
const highlightIndex = React.useCallback(index => setHighlight(current => current.list === list && current.index === index ? current : {
|
|
4021
|
+
index,
|
|
4022
|
+
list
|
|
4023
|
+
}), [list]);
|
|
4024
|
+
const handleKeyDown = event => {
|
|
4025
|
+
const step = verticalStep(event.key);
|
|
4026
|
+
if (step && items.length > 0) {
|
|
4027
|
+
event.preventDefault();
|
|
4028
|
+
highlightIndex((highlightedIndex + step + items.length) % items.length);
|
|
4029
|
+
} else if (event.key === "Enter" && highlighted && !event.nativeEvent.isComposing) {
|
|
4030
|
+
event.preventDefault();
|
|
4031
|
+
open(highlighted.url, {
|
|
4032
|
+
newTab: hasCommandKey(event)
|
|
4033
|
+
});
|
|
4034
|
+
} else if (isCopyShortcut(event) && highlighted && !hasSelectedText(event.currentTarget)) {
|
|
4035
|
+
event.preventDefault();
|
|
4036
|
+
copy(highlighted.url);
|
|
4037
|
+
}
|
|
4038
|
+
};
|
|
4039
|
+
return {
|
|
4040
|
+
copied: copiedUrl !== null && copiedUrl === (highlighted === null || highlighted === void 0 ? void 0 : highlighted.url),
|
|
4041
|
+
handleKeyDown,
|
|
4042
|
+
highlightIndex,
|
|
4043
|
+
highlighted,
|
|
4044
|
+
highlightedIndex: highlighted ? highlightedIndex : null
|
|
4045
|
+
};
|
|
4046
|
+
}
|
|
4047
|
+
|
|
4048
|
+
function groupSections(groups = []) {
|
|
4049
|
+
return groups.map(({
|
|
4050
|
+
results,
|
|
4051
|
+
type
|
|
4052
|
+
}) => ({
|
|
4053
|
+
heading: type,
|
|
4054
|
+
items: results.map(resultItem),
|
|
4055
|
+
key: type
|
|
4056
|
+
}));
|
|
4057
|
+
}
|
|
4058
|
+
function resultItem({
|
|
4059
|
+
attributes,
|
|
4060
|
+
id
|
|
4061
|
+
}) {
|
|
4062
|
+
return {
|
|
4063
|
+
key: id,
|
|
4064
|
+
subtitle: summarize(attributes.metadata),
|
|
4065
|
+
title: attributes.title,
|
|
4066
|
+
url: attributes.url
|
|
4067
|
+
};
|
|
4068
|
+
}
|
|
4069
|
+
function visitItem(visit) {
|
|
4070
|
+
return {
|
|
4071
|
+
key: entryKey(visit.entry),
|
|
4072
|
+
...describeVisit(visit)
|
|
4073
|
+
};
|
|
4074
|
+
}
|
|
4075
|
+
function summarize(metadata) {
|
|
4076
|
+
return Object.values(metadata !== null && metadata !== void 0 ? metadata : {}).filter(value => typeof value === "string" && value !== "").join(" · ");
|
|
4077
|
+
}
|
|
4078
|
+
// Unlike search results, recents come from every product, so each one names
|
|
4079
|
+
// its product and type.
|
|
4080
|
+
function describeVisit(visit) {
|
|
4081
|
+
var _a, _b;
|
|
4082
|
+
const subtitle = (...parts) => parts.filter(Boolean).join(" · ");
|
|
4083
|
+
if (visit.status === "page") {
|
|
4084
|
+
const {
|
|
4085
|
+
app,
|
|
4086
|
+
metadata,
|
|
4087
|
+
title
|
|
4088
|
+
} = visit.entry;
|
|
4089
|
+
return {
|
|
4090
|
+
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 : ""),
|
|
4091
|
+
title,
|
|
4092
|
+
url: visit.url
|
|
4093
|
+
};
|
|
4094
|
+
} else {
|
|
4095
|
+
const {
|
|
4096
|
+
metadata,
|
|
4097
|
+
product,
|
|
4098
|
+
title,
|
|
4099
|
+
type
|
|
4100
|
+
} = visit.result.attributes;
|
|
4101
|
+
return {
|
|
4102
|
+
subtitle: subtitle(productName(product), type, summarize(metadata)),
|
|
4103
|
+
title,
|
|
4104
|
+
url: visit.url
|
|
4105
|
+
};
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
// check-ins → Check-Ins
|
|
4109
|
+
function productName(slug) {
|
|
4110
|
+
return slug.split("-").map(capitalize).join("-");
|
|
4111
|
+
}
|
|
4112
|
+
function capitalize(word) {
|
|
4113
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4116
|
+
const STORAGE_KEY = "topbar.product_search.last_product";
|
|
4117
|
+
function readLastProduct() {
|
|
4118
|
+
try {
|
|
4119
|
+
return localStorage.getItem(STORAGE_KEY);
|
|
4120
|
+
} catch {
|
|
4121
|
+
return null;
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
function saveLastProduct(slug) {
|
|
4125
|
+
try {
|
|
4126
|
+
localStorage.setItem(STORAGE_KEY, slug);
|
|
4127
|
+
} catch {
|
|
4128
|
+
// Storage can be full or blocked; search still works without it.
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
function initialProduct(products) {
|
|
4132
|
+
var _a, _b, _c;
|
|
4133
|
+
const lastProduct = readLastProduct();
|
|
4134
|
+
const bySlug = slug => products.find(product => product.slug === slug);
|
|
4135
|
+
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];
|
|
3815
4136
|
}
|
|
3816
4137
|
|
|
3817
|
-
|
|
4138
|
+
function KeyboardHints({
|
|
4139
|
+
copied
|
|
4140
|
+
}) {
|
|
4141
|
+
const command = commandKeyLabel();
|
|
4142
|
+
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", {
|
|
4143
|
+
role: "status"
|
|
4144
|
+
}, copied ? "Copied!" : "Copy link"), " \u00B7 ", command, "K Open search");
|
|
4145
|
+
}
|
|
4146
|
+
|
|
4147
|
+
var styles$d = {"tab":"tab-dz8ki"};
|
|
4148
|
+
|
|
4149
|
+
function ProductTabs({
|
|
4150
|
+
children,
|
|
4151
|
+
onKeyDown,
|
|
4152
|
+
onSelect,
|
|
4153
|
+
products,
|
|
4154
|
+
selected
|
|
4155
|
+
}) {
|
|
4156
|
+
const id = useInstanceId("product-tabs");
|
|
4157
|
+
const tabId = slug => `${id}-tab-${slug}`;
|
|
4158
|
+
const tabRefs = React.useRef(new Map());
|
|
4159
|
+
const handleKeyDown = event => {
|
|
4160
|
+
var _a;
|
|
4161
|
+
const offset = horizontalStep(event.key);
|
|
4162
|
+
if (offset) {
|
|
4163
|
+
event.preventDefault();
|
|
4164
|
+
const index = products.indexOf(selected);
|
|
4165
|
+
const next = products[(index + offset + products.length) % products.length];
|
|
4166
|
+
onSelect(next.slug);
|
|
4167
|
+
(_a = tabRefs.current.get(next.slug)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4168
|
+
} else {
|
|
4169
|
+
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
4170
|
+
}
|
|
4171
|
+
};
|
|
4172
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
4173
|
+
"aria-label": "Product",
|
|
4174
|
+
onKeyDown: handleKeyDown,
|
|
4175
|
+
role: "tablist"
|
|
4176
|
+
}, products.map(product => (/*#__PURE__*/React.createElement("button", {
|
|
4177
|
+
"aria-controls": `${id}-panel`,
|
|
4178
|
+
"aria-selected": product === selected,
|
|
4179
|
+
className: styles$d.tab,
|
|
4180
|
+
id: tabId(product.slug),
|
|
4181
|
+
key: product.slug,
|
|
4182
|
+
onClick: () => onSelect(product.slug),
|
|
4183
|
+
ref: element => {
|
|
4184
|
+
if (element) {
|
|
4185
|
+
tabRefs.current.set(product.slug, element);
|
|
4186
|
+
} else {
|
|
4187
|
+
tabRefs.current.delete(product.slug);
|
|
4188
|
+
}
|
|
4189
|
+
},
|
|
4190
|
+
role: "tab",
|
|
4191
|
+
tabIndex: product === selected ? 0 : -1,
|
|
4192
|
+
type: "button"
|
|
4193
|
+
}, product.appName)))), /*#__PURE__*/React.createElement("div", {
|
|
4194
|
+
"aria-labelledby": tabId(selected.slug),
|
|
4195
|
+
id: `${id}-panel`,
|
|
4196
|
+
role: "tabpanel"
|
|
4197
|
+
}, children));
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
function EndOfResultsObserver({
|
|
4201
|
+
onVisible
|
|
4202
|
+
}) {
|
|
4203
|
+
const ref = React.useRef(null);
|
|
4204
|
+
React.useEffect(() => {
|
|
4205
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
4206
|
+
if (entry.isIntersecting) onVisible();
|
|
4207
|
+
});
|
|
4208
|
+
if (ref.current) observer.observe(ref.current);
|
|
4209
|
+
return () => observer.disconnect();
|
|
4210
|
+
}, [onVisible]);
|
|
4211
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
4212
|
+
ref: ref
|
|
4213
|
+
});
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
const resultId = (listboxId, index) => `${listboxId}-result-${index}`;
|
|
4217
|
+
|
|
4218
|
+
var styles$c = {"result":"result-Thq2C"};
|
|
3818
4219
|
|
|
3819
4220
|
function SearchResult({
|
|
3820
4221
|
highlighted,
|
|
@@ -3837,7 +4238,7 @@ true;
|
|
|
3837
4238
|
// pointer, and that shouldn't steal the highlight.
|
|
3838
4239
|
return /*#__PURE__*/React.createElement("a", {
|
|
3839
4240
|
"aria-selected": highlighted,
|
|
3840
|
-
className: styles$
|
|
4241
|
+
className: styles$c.result,
|
|
3841
4242
|
href: url,
|
|
3842
4243
|
id: id,
|
|
3843
4244
|
onMouseMove: onHighlight,
|
|
@@ -3847,21 +4248,129 @@ true;
|
|
|
3847
4248
|
}, /*#__PURE__*/React.createElement("div", null, title), /*#__PURE__*/React.createElement("div", null, subtitle));
|
|
3848
4249
|
}
|
|
3849
4250
|
|
|
3850
|
-
|
|
4251
|
+
// Sections with a heading render as labelled groups; ones without render
|
|
4252
|
+
// their items straight into the listbox. Indexes run across every section.
|
|
4253
|
+
function ResultListbox({
|
|
4254
|
+
busy,
|
|
4255
|
+
highlightedIndex,
|
|
4256
|
+
id,
|
|
4257
|
+
label,
|
|
4258
|
+
labelledBy,
|
|
4259
|
+
onHighlight,
|
|
4260
|
+
sections
|
|
4261
|
+
}) {
|
|
4262
|
+
let index = 0;
|
|
4263
|
+
const renderItem = item => {
|
|
4264
|
+
const itemIndex = index++;
|
|
4265
|
+
return /*#__PURE__*/React.createElement(SearchResult, {
|
|
4266
|
+
highlighted: itemIndex === highlightedIndex,
|
|
4267
|
+
id: resultId(id, itemIndex),
|
|
4268
|
+
key: item.key,
|
|
4269
|
+
onHighlight: () => onHighlight(itemIndex),
|
|
4270
|
+
subtitle: item.subtitle,
|
|
4271
|
+
title: item.title,
|
|
4272
|
+
url: item.url
|
|
4273
|
+
});
|
|
4274
|
+
};
|
|
4275
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
4276
|
+
"aria-busy": busy,
|
|
4277
|
+
"aria-label": label,
|
|
4278
|
+
"aria-labelledby": labelledBy,
|
|
4279
|
+
id: id,
|
|
4280
|
+
role: "listbox"
|
|
4281
|
+
}, sections.map((section, sectionIndex) => {
|
|
4282
|
+
if (section.heading === undefined) {
|
|
4283
|
+
return /*#__PURE__*/React.createElement(React.Fragment, {
|
|
4284
|
+
key: section.key
|
|
4285
|
+
}, section.items.map(renderItem));
|
|
4286
|
+
}
|
|
4287
|
+
const headingId = `${id}-group-${sectionIndex}`;
|
|
4288
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
4289
|
+
"aria-labelledby": headingId,
|
|
4290
|
+
key: section.key,
|
|
4291
|
+
role: "group"
|
|
4292
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
4293
|
+
id: headingId
|
|
4294
|
+
}, section.heading), section.items.map(renderItem));
|
|
4295
|
+
}));
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
function RecentlyVisited({
|
|
4299
|
+
count,
|
|
4300
|
+
hasMore,
|
|
4301
|
+
items,
|
|
4302
|
+
loading,
|
|
4303
|
+
showMore,
|
|
4304
|
+
...navigation
|
|
4305
|
+
}) {
|
|
4306
|
+
const headingId = `${navigation.id}-heading`;
|
|
4307
|
+
if (items.length === 0 && !hasMore && !loading) {
|
|
4308
|
+
return /*#__PURE__*/React.createElement("p", null, "Pages you visit will show up here.");
|
|
4309
|
+
} else {
|
|
4310
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
4311
|
+
id: headingId
|
|
4312
|
+
}, "Recently visited"), /*#__PURE__*/React.createElement(ResultListbox, {
|
|
4313
|
+
labelledBy: headingId,
|
|
4314
|
+
sections: [{
|
|
4315
|
+
items,
|
|
4316
|
+
key: "recents"
|
|
4317
|
+
}],
|
|
4318
|
+
...navigation
|
|
4319
|
+
}), hasMore && /*#__PURE__*/React.createElement(EndOfResultsObserver, {
|
|
4320
|
+
key: count,
|
|
4321
|
+
onVisible: showMore
|
|
4322
|
+
}));
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
|
|
4326
|
+
// A combobox: focus stays here while aria-activedescendant points screen
|
|
4327
|
+
// readers at the highlighted result in the listbox it controls.
|
|
4328
|
+
function SearchInput({
|
|
4329
|
+
expanded,
|
|
4330
|
+
highlightedIndex,
|
|
4331
|
+
inputRef,
|
|
4332
|
+
listboxId,
|
|
4333
|
+
onChange,
|
|
4334
|
+
onFocus,
|
|
4335
|
+
onKeyDown,
|
|
4336
|
+
value
|
|
4337
|
+
}) {
|
|
4338
|
+
return /*#__PURE__*/React.createElement("input", {
|
|
4339
|
+
"aria-activedescendant": highlightedIndex === null ? undefined : resultId(listboxId, highlightedIndex),
|
|
4340
|
+
"aria-autocomplete": "list",
|
|
4341
|
+
"aria-controls": expanded ? listboxId : undefined,
|
|
4342
|
+
"aria-expanded": expanded,
|
|
4343
|
+
"aria-label": "Search",
|
|
4344
|
+
autoFocus: true,
|
|
4345
|
+
onChange: event => onChange(event.target.value),
|
|
4346
|
+
onFocus: onFocus,
|
|
4347
|
+
onKeyDown: onKeyDown,
|
|
4348
|
+
placeholder: "Search",
|
|
4349
|
+
ref: inputRef,
|
|
4350
|
+
role: "combobox",
|
|
4351
|
+
type: "search",
|
|
4352
|
+
value: value
|
|
4353
|
+
});
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
var styles$b = {"visuallyHidden":"visuallyHidden-S9VG5"};
|
|
4357
|
+
|
|
3851
4358
|
function SearchResults({
|
|
3852
|
-
|
|
4359
|
+
label,
|
|
4360
|
+
sections,
|
|
4361
|
+
status,
|
|
3853
4362
|
term,
|
|
3854
4363
|
...navigation
|
|
3855
4364
|
}) {
|
|
3856
|
-
|
|
3857
|
-
switch (search.status) {
|
|
4365
|
+
switch (status) {
|
|
3858
4366
|
case "idle":
|
|
3859
4367
|
return null;
|
|
3860
4368
|
case "loading":
|
|
3861
|
-
if (
|
|
3862
|
-
return /*#__PURE__*/React.createElement(
|
|
4369
|
+
if (sections.length > 0) {
|
|
4370
|
+
return /*#__PURE__*/React.createElement(ResultListbox, {
|
|
3863
4371
|
busy: true,
|
|
3864
|
-
|
|
4372
|
+
label: label,
|
|
4373
|
+
sections: sections,
|
|
3865
4374
|
...navigation
|
|
3866
4375
|
});
|
|
3867
4376
|
}
|
|
@@ -3873,324 +4382,167 @@ true;
|
|
|
3873
4382
|
role: "alert"
|
|
3874
4383
|
}, "Search isn\u2019t working right now. Try again.");
|
|
3875
4384
|
case "done":
|
|
3876
|
-
if (
|
|
4385
|
+
if (sections.length === 0) {
|
|
3877
4386
|
return /*#__PURE__*/React.createElement("p", {
|
|
3878
4387
|
role: "status"
|
|
3879
4388
|
}, "No results for \u201C", term.trim(), "\u201D");
|
|
3880
4389
|
}
|
|
3881
|
-
return /*#__PURE__*/React.createElement(
|
|
3882
|
-
|
|
4390
|
+
return /*#__PURE__*/React.createElement(ResultListbox, {
|
|
4391
|
+
busy: false,
|
|
4392
|
+
label: label,
|
|
4393
|
+
sections: sections,
|
|
3883
4394
|
...navigation
|
|
3884
4395
|
});
|
|
3885
4396
|
}
|
|
3886
4397
|
}
|
|
3887
|
-
function ResultGroups({
|
|
3888
|
-
busy = false,
|
|
3889
|
-
groups,
|
|
3890
|
-
highlightedIndex,
|
|
3891
|
-
id,
|
|
3892
|
-
label,
|
|
3893
|
-
onHighlight
|
|
3894
|
-
}) {
|
|
3895
|
-
let index = 0;
|
|
3896
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
3897
|
-
"aria-busy": busy,
|
|
3898
|
-
"aria-label": label,
|
|
3899
|
-
id: id,
|
|
3900
|
-
role: "listbox"
|
|
3901
|
-
}, groups.map(({
|
|
3902
|
-
results,
|
|
3903
|
-
type
|
|
3904
|
-
}, groupIndex) => {
|
|
3905
|
-
const headingId = `${id}-group-${groupIndex}`;
|
|
3906
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
3907
|
-
"aria-labelledby": headingId,
|
|
3908
|
-
key: type,
|
|
3909
|
-
role: "group"
|
|
3910
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
3911
|
-
id: headingId
|
|
3912
|
-
}, type), results.map(result => {
|
|
3913
|
-
const resultIndex = index++;
|
|
3914
|
-
return /*#__PURE__*/React.createElement(SearchResult, {
|
|
3915
|
-
highlighted: resultIndex === highlightedIndex,
|
|
3916
|
-
id: resultId(id, resultIndex),
|
|
3917
|
-
key: result.id,
|
|
3918
|
-
onHighlight: () => onHighlight(resultIndex),
|
|
3919
|
-
subtitle: summarize(result.attributes.metadata),
|
|
3920
|
-
title: result.attributes.title,
|
|
3921
|
-
url: result.attributes.url
|
|
3922
|
-
});
|
|
3923
|
-
}));
|
|
3924
|
-
}));
|
|
3925
|
-
}
|
|
3926
|
-
function summarize(metadata) {
|
|
3927
|
-
return Object.values(metadata !== null && metadata !== void 0 ? metadata : {}).filter(value => typeof value === "string" && value !== "").join(" · ");
|
|
3928
|
-
}
|
|
3929
4398
|
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
const [count, setCount] = React.useState(RECENTLY_VISITED_PAGE_SIZE);
|
|
3937
|
-
const shown = React.useMemo(() => entries.slice(0, count), [entries, count]);
|
|
3938
|
-
const hydrated = useHydratedRecentlyVisited(shown, env);
|
|
3939
|
-
// Resources show up once they're found. Ones that can't be found anymore,
|
|
3940
|
-
// or that the person can no longer see, are left out.
|
|
3941
|
-
const visits = hydrated.filter(isShown);
|
|
3942
|
-
const loading = hydrated.some(({
|
|
3943
|
-
status
|
|
3944
|
-
}) => status === "loading");
|
|
3945
|
-
const showMore = React.useCallback(() => setCount(current => current + RECENTLY_VISITED_PAGE_SIZE), []);
|
|
3946
|
-
return {
|
|
3947
|
-
count,
|
|
3948
|
-
hasMore: entries.length > count,
|
|
3949
|
-
loading,
|
|
3950
|
-
showMore,
|
|
3951
|
-
visits
|
|
3952
|
-
};
|
|
3953
|
-
}
|
|
3954
|
-
function isShown(visit) {
|
|
3955
|
-
return visit.status === "page" || visit.status === "resolved";
|
|
3956
|
-
}
|
|
3957
|
-
function RecentlyVisited({
|
|
3958
|
-
count,
|
|
3959
|
-
hasMore,
|
|
3960
|
-
highlightedIndex,
|
|
3961
|
-
id,
|
|
3962
|
-
loading,
|
|
3963
|
-
onHighlight,
|
|
3964
|
-
showMore,
|
|
3965
|
-
visits
|
|
3966
|
-
}) {
|
|
3967
|
-
const headingId = `${id}-heading`;
|
|
3968
|
-
if (visits.length === 0 && !hasMore && !loading) {
|
|
3969
|
-
return /*#__PURE__*/React.createElement("p", null, "Pages you visit will show up here.");
|
|
3970
|
-
} else {
|
|
3971
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
|
3972
|
-
id: headingId
|
|
3973
|
-
}, "Recently visited"), /*#__PURE__*/React.createElement("div", {
|
|
3974
|
-
"aria-labelledby": headingId,
|
|
3975
|
-
id: id,
|
|
3976
|
-
role: "listbox"
|
|
3977
|
-
}, visits.map((visit, index) => (/*#__PURE__*/React.createElement(SearchResult, {
|
|
3978
|
-
highlighted: index === highlightedIndex,
|
|
3979
|
-
id: resultId(id, index),
|
|
3980
|
-
key: entryKey(visit.entry),
|
|
3981
|
-
onHighlight: () => onHighlight(index),
|
|
3982
|
-
...describeVisit(visit)
|
|
3983
|
-
})))), hasMore && /*#__PURE__*/React.createElement(ShowMoreWhenVisible, {
|
|
3984
|
-
key: count,
|
|
3985
|
-
onVisible: showMore
|
|
3986
|
-
}));
|
|
3987
|
-
}
|
|
3988
|
-
}
|
|
3989
|
-
function ShowMoreWhenVisible({
|
|
3990
|
-
onVisible
|
|
4399
|
+
// Keys the recents list for navigation, so the highlight
|
|
4400
|
+
// stays put as more recents load and as their lookups answer.
|
|
4401
|
+
const RECENTS = "recents";
|
|
4402
|
+
function SearchPanel({
|
|
4403
|
+
env,
|
|
4404
|
+
products
|
|
3991
4405
|
}) {
|
|
3992
|
-
|
|
4406
|
+
var _a, _b;
|
|
4407
|
+
const listboxId = useInstanceId("product-search-results");
|
|
4408
|
+
const [term, setTerm] = React.useState("");
|
|
4409
|
+
const [selectedSlug, setSelectedSlug] = React.useState(() => initialProduct(products).slug);
|
|
4410
|
+
const product = (_a = products.find(({
|
|
4411
|
+
slug
|
|
4412
|
+
}) => slug === selectedSlug)) !== null && _a !== void 0 ? _a : products[0];
|
|
4413
|
+
const hasTerm = term.trim() !== "";
|
|
4414
|
+
const search = useProductSearch(product.slug, term);
|
|
4415
|
+
const groups = "groups" in search ? search.groups : undefined;
|
|
4416
|
+
const sections = React.useMemo(() => groupSections(groups), [groups]);
|
|
4417
|
+
const {
|
|
4418
|
+
visits,
|
|
4419
|
+
...recents
|
|
4420
|
+
} = useRecentVisits(env);
|
|
4421
|
+
const recentItems = visits.map(visitItem);
|
|
4422
|
+
const items = hasTerm ? sections.flatMap(section => section.items) : recentItems;
|
|
4423
|
+
const navigation = useResultNavigation(items, hasTerm ? sections : RECENTS);
|
|
4424
|
+
const {
|
|
4425
|
+
highlightedIndex
|
|
4426
|
+
} = navigation;
|
|
4427
|
+
const inputRef = React.useRef(null);
|
|
4428
|
+
const [announceHighlight, setAnnounceHighlight] = React.useState(false);
|
|
4429
|
+
// The tabs keep focus while arrowing through results, but only the focused
|
|
4430
|
+
// input can point screen readers at the highlight, so from the tabs it's
|
|
4431
|
+
// announced instead. Typing goes back to the input, keystroke and all.
|
|
4432
|
+
const handleTabsKeyDown = event => {
|
|
4433
|
+
var _a;
|
|
4434
|
+
if (isTypingKey(event)) {
|
|
4435
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4436
|
+
} else if (verticalStep(event.key)) {
|
|
4437
|
+
setAnnounceHighlight(true);
|
|
4438
|
+
navigation.handleKeyDown(event);
|
|
4439
|
+
} else {
|
|
4440
|
+
navigation.handleKeyDown(event);
|
|
4441
|
+
}
|
|
4442
|
+
};
|
|
3993
4443
|
React.useEffect(() => {
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
}
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
};
|
|
4031
|
-
}
|
|
4032
|
-
}
|
|
4033
|
-
// check-ins → Check-Ins
|
|
4034
|
-
function productName(slug) {
|
|
4035
|
-
return slug.split("-").map(capitalize).join("-");
|
|
4036
|
-
}
|
|
4037
|
-
function capitalize(word) {
|
|
4038
|
-
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
4444
|
+
if (hasTerm) saveLastProduct(product.slug);
|
|
4445
|
+
}, [hasTerm, product.slug]);
|
|
4446
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SearchInput, {
|
|
4447
|
+
expanded: items.length > 0,
|
|
4448
|
+
highlightedIndex: highlightedIndex,
|
|
4449
|
+
inputRef: inputRef,
|
|
4450
|
+
listboxId: listboxId,
|
|
4451
|
+
onChange: setTerm,
|
|
4452
|
+
onFocus: () => setAnnounceHighlight(false),
|
|
4453
|
+
onKeyDown: navigation.handleKeyDown,
|
|
4454
|
+
value: term
|
|
4455
|
+
}), /*#__PURE__*/React.createElement(ProductTabs, {
|
|
4456
|
+
onKeyDown: handleTabsKeyDown,
|
|
4457
|
+
onSelect: setSelectedSlug,
|
|
4458
|
+
products: products,
|
|
4459
|
+
selected: product
|
|
4460
|
+
}, hasTerm ? (/*#__PURE__*/React.createElement(SearchResults, {
|
|
4461
|
+
highlightedIndex: highlightedIndex,
|
|
4462
|
+
id: listboxId,
|
|
4463
|
+
label: `${product.appName} results`,
|
|
4464
|
+
onHighlight: navigation.highlightIndex,
|
|
4465
|
+
sections: sections,
|
|
4466
|
+
status: search.status,
|
|
4467
|
+
term: term
|
|
4468
|
+
})) : (/*#__PURE__*/React.createElement(RecentlyVisited, {
|
|
4469
|
+
highlightedIndex: highlightedIndex,
|
|
4470
|
+
id: listboxId,
|
|
4471
|
+
items: recentItems,
|
|
4472
|
+
onHighlight: navigation.highlightIndex,
|
|
4473
|
+
...recents
|
|
4474
|
+
}))), /*#__PURE__*/React.createElement("div", {
|
|
4475
|
+
"aria-live": "polite",
|
|
4476
|
+
className: styles$b.visuallyHidden
|
|
4477
|
+
}, announceHighlight ? (_b = navigation.highlighted) === null || _b === void 0 ? void 0 : _b.title : null), /*#__PURE__*/React.createElement(KeyboardHints, {
|
|
4478
|
+
copied: navigation.copied
|
|
4479
|
+
}));
|
|
4039
4480
|
}
|
|
4040
4481
|
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
const
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
// Services tab.
|
|
4051
|
-
const visibleResponse = request.status === "done" || settledProduct === product ? response : undefined;
|
|
4052
|
-
const groups = React.useMemo(() => visibleResponse && groupByType(visibleResponse), [visibleResponse]);
|
|
4053
|
-
if (!query) {
|
|
4054
|
-
return {
|
|
4055
|
-
status: "idle"
|
|
4056
|
-
};
|
|
4057
|
-
} else if (query !== debouncedQuery) {
|
|
4058
|
-
return {
|
|
4059
|
-
groups,
|
|
4060
|
-
status: "loading"
|
|
4061
|
-
};
|
|
4062
|
-
} else if (request.status === "done") {
|
|
4063
|
-
return {
|
|
4064
|
-
groups: groups !== null && groups !== void 0 ? groups : [],
|
|
4065
|
-
status: "done"
|
|
4066
|
-
};
|
|
4067
|
-
} else if (request.status === "error") {
|
|
4068
|
-
return {
|
|
4069
|
-
status: "error"
|
|
4070
|
-
};
|
|
4071
|
-
} else {
|
|
4072
|
-
return {
|
|
4073
|
-
groups,
|
|
4074
|
-
status: "loading"
|
|
4075
|
-
};
|
|
4076
|
-
}
|
|
4482
|
+
// Products open modals from many libraries, not all of which mark themselves
|
|
4483
|
+
// with roles, so a modal is recognized by what it does: cover the page.
|
|
4484
|
+
function isModalOpen() {
|
|
4485
|
+
const {
|
|
4486
|
+
clientHeight,
|
|
4487
|
+
clientWidth
|
|
4488
|
+
} = document.documentElement;
|
|
4489
|
+
const element = document.elementFromPoint(clientWidth / 2, clientHeight / 2);
|
|
4490
|
+
return element !== null && (isInNativeDialog(element) || hasBackdrop(element, clientWidth, clientHeight));
|
|
4077
4491
|
}
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
});
|
|
4083
|
-
return `${window.location.origin}/~api/${product}/v2/product_search_results?${params}`;
|
|
4492
|
+
// A native modal's backdrop is drawn by the browser rather than being an
|
|
4493
|
+
// element; hit-testing it lands on the dialog itself.
|
|
4494
|
+
function isInNativeDialog(element) {
|
|
4495
|
+
return element.closest("dialog[open]") !== null;
|
|
4084
4496
|
}
|
|
4085
|
-
function
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
var _a, _b;
|
|
4090
|
-
const typeOrder = (_a = meta === null || meta === void 0 ? void 0 : meta.type_order) !== null && _a !== void 0 ? _a : [];
|
|
4091
|
-
const groups = new Map();
|
|
4092
|
-
for (const result of data) {
|
|
4093
|
-
const {
|
|
4094
|
-
type
|
|
4095
|
-
} = result.attributes;
|
|
4096
|
-
if (!groups.has(type)) groups.set(type, {
|
|
4097
|
-
results: [],
|
|
4098
|
-
type
|
|
4099
|
-
});
|
|
4100
|
-
(_b = groups.get(type)) === null || _b === void 0 ? void 0 : _b.results.push(result);
|
|
4497
|
+
function hasBackdrop(element, width, height) {
|
|
4498
|
+
let current = element;
|
|
4499
|
+
while (current && !isBackdrop(current, width, height)) {
|
|
4500
|
+
current = current.parentElement;
|
|
4101
4501
|
}
|
|
4102
|
-
|
|
4103
|
-
const index = typeOrder.indexOf(type);
|
|
4104
|
-
return index === -1 ? typeOrder.length : index;
|
|
4105
|
-
};
|
|
4106
|
-
return [...groups.values()].sort((a, b) => rank(a.type) - rank(b.type));
|
|
4502
|
+
return current !== null;
|
|
4107
4503
|
}
|
|
4108
|
-
//
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
const [debounced, setDebounced] = React.useState(value);
|
|
4118
|
-
React.useEffect(() => {
|
|
4119
|
-
const timeout = setTimeout(() => setDebounced(value), delay);
|
|
4120
|
-
return () => clearTimeout(timeout);
|
|
4121
|
-
}, [value, delay]);
|
|
4122
|
-
return debounced;
|
|
4504
|
+
// Some backdrops start below the topbar rather than at the top of the screen,
|
|
4505
|
+
// so the layer only has to span the width and reach from the center to the
|
|
4506
|
+
// bottom. Its own box has to reach the center: a bar along the bottom can
|
|
4507
|
+
// hold a panel that pops up over the center, like Services' media player.
|
|
4508
|
+
// react-aria leaves a closed modal's backdrop up while it fades out, search's
|
|
4509
|
+
// own included, so one that's on its way out doesn't count.
|
|
4510
|
+
function isBackdrop(element, width, height) {
|
|
4511
|
+
const rect = element.getBoundingClientRect();
|
|
4512
|
+
return !element.matches("[data-exiting]") && getComputedStyle(element).position === "fixed" && rect.width >= width - SCROLLBAR_SLACK && rect.top <= height / 2 && rect.bottom >= height - ROUNDING_SLACK;
|
|
4123
4513
|
}
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
const
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
// A list that grows or fills in under the same `list` keeps its highlight.
|
|
4133
|
-
function useResultNavigation(options, list) {
|
|
4134
|
-
const [highlight, setHighlight] = React.useState({
|
|
4135
|
-
index: 0,
|
|
4136
|
-
list
|
|
4137
|
-
});
|
|
4138
|
-
const highlightedIndex = highlight.list === list ? highlight.index : 0;
|
|
4139
|
-
const highlighted = options[highlightedIndex];
|
|
4140
|
-
const [copiedUrl, setCopiedUrl] = React.useState(null);
|
|
4514
|
+
// react-aria keeps a classic scrollbar's gutter reserved while its modals lock
|
|
4515
|
+
// scrolling, so their backdrops stop short of the right edge by its width.
|
|
4516
|
+
const SCROLLBAR_SLACK = 24;
|
|
4517
|
+
// Rects are fractional at non-100% zoom, but clientWidth and clientHeight are
|
|
4518
|
+
// rounded to whole pixels.
|
|
4519
|
+
const ROUNDING_SLACK = 1;
|
|
4520
|
+
|
|
4521
|
+
function useSearchShortcut(enabled, open, setOpen) {
|
|
4141
4522
|
React.useEffect(() => {
|
|
4142
|
-
if (
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
}
|
|
4164
|
-
|
|
4165
|
-
const {
|
|
4166
|
-
url
|
|
4167
|
-
} = highlighted;
|
|
4168
|
-
navigator.clipboard.writeText(url).then(() => setCopiedUrl(url));
|
|
4169
|
-
}
|
|
4170
|
-
};
|
|
4171
|
-
return {
|
|
4172
|
-
copied: copiedUrl !== null && copiedUrl === (highlighted === null || highlighted === void 0 ? void 0 : highlighted.url),
|
|
4173
|
-
handleKeyDown,
|
|
4174
|
-
highlightIndex,
|
|
4175
|
-
highlighted,
|
|
4176
|
-
highlightedIndex: highlighted ? highlightedIndex : null
|
|
4177
|
-
};
|
|
4178
|
-
}
|
|
4179
|
-
function open(url, {
|
|
4180
|
-
newTab
|
|
4181
|
-
}) {
|
|
4182
|
-
if (newTab) {
|
|
4183
|
-
window.open(url, "_blank", "noopener");
|
|
4184
|
-
} else {
|
|
4185
|
-
window.location.assign(url);
|
|
4186
|
-
}
|
|
4187
|
-
}
|
|
4188
|
-
const isCopyShortcut = event => event.key.toLowerCase() === "c" && !event.altKey && !event.shiftKey && hasCommandKey(event);
|
|
4189
|
-
// With text selected, ⌘C should copy that text as usual, not the link.
|
|
4190
|
-
function hasSelectedText(element) {
|
|
4191
|
-
var _a, _b;
|
|
4192
|
-
const selectedInField = element instanceof HTMLInputElement && element.selectionStart !== element.selectionEnd;
|
|
4193
|
-
return selectedInField || ((_b = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : "") !== "";
|
|
4523
|
+
if (!enabled) return undefined;
|
|
4524
|
+
// Rich text editors like Trix bind ⌘K to "insert link"; capturing at the
|
|
4525
|
+
// window and stopping propagation keeps them from ever seeing it. Under a
|
|
4526
|
+
// product's modal, search stays shut rather than stacking a second modal,
|
|
4527
|
+
// and the keystroke goes on to the product.
|
|
4528
|
+
const handleKeyDown = event => {
|
|
4529
|
+
if (open && isSearchShortcut(event)) {
|
|
4530
|
+
event.preventDefault();
|
|
4531
|
+
event.stopPropagation();
|
|
4532
|
+
setOpen(false);
|
|
4533
|
+
} else if (!open && (isSearchShortcut(event) || isLegacySearchShortcut(event)) && !isModalOpen()) {
|
|
4534
|
+
event.preventDefault();
|
|
4535
|
+
event.stopPropagation();
|
|
4536
|
+
setOpen(true);
|
|
4537
|
+
}
|
|
4538
|
+
};
|
|
4539
|
+
window.addEventListener("keydown", handleKeyDown, {
|
|
4540
|
+
capture: true
|
|
4541
|
+
});
|
|
4542
|
+
return () => window.removeEventListener("keydown", handleKeyDown, {
|
|
4543
|
+
capture: true
|
|
4544
|
+
});
|
|
4545
|
+
}, [enabled, open, setOpen]);
|
|
4194
4546
|
}
|
|
4195
4547
|
|
|
4196
4548
|
const SEARCHABLE_PRODUCTS = [{
|
|
@@ -4218,6 +4570,7 @@ true;
|
|
|
4218
4570
|
appName: "Services",
|
|
4219
4571
|
slug: "services"
|
|
4220
4572
|
}];
|
|
4573
|
+
|
|
4221
4574
|
const PERMISSION_CHECKS = {
|
|
4222
4575
|
"check-ins": () => fetchMe("check-ins", "permission").then(({
|
|
4223
4576
|
permission
|
|
@@ -4280,6 +4633,7 @@ true;
|
|
|
4280
4633
|
return promise;
|
|
4281
4634
|
}
|
|
4282
4635
|
}
|
|
4636
|
+
|
|
4283
4637
|
function useSearchableProducts(apps) {
|
|
4284
4638
|
// Keyed by name because providers hand over a fresh `apps` array on renders
|
|
4285
4639
|
// where nothing changed.
|
|
@@ -4321,181 +4675,27 @@ true;
|
|
|
4321
4675
|
return groupApps(apps).restProducts.flatMap(app => SEARCHABLE_PRODUCTS.filter(product => product.appName === app.name));
|
|
4322
4676
|
}
|
|
4323
4677
|
|
|
4324
|
-
const isSearchShortcut = event => event.key.toLowerCase() === "k" && !event.altKey && !event.shiftKey && hasCommandKey(event);
|
|
4325
|
-
// Products opened their own search with `/` before this one replaced it.
|
|
4326
|
-
const isLegacySearchShortcut = event => event.key === "/" && !event.altKey && !event.ctrlKey && !event.metaKey && !isTypingIn(event.target);
|
|
4327
|
-
const isTypingKey = event => event.key.length === 1 && event.key !== " " && !event.altKey && !event.ctrlKey && !event.metaKey;
|
|
4328
|
-
const isTypingIn = target => target instanceof Element && target.closest('input, select, textarea, [contenteditable]:not([contenteditable="false"])') !== null;
|
|
4329
4678
|
function ProductSearch({
|
|
4330
4679
|
apps,
|
|
4331
4680
|
env
|
|
4332
4681
|
}) {
|
|
4333
4682
|
const searchable = useSearchableProducts(apps);
|
|
4334
|
-
if (searchable.status === "done" && searchable.products.length > 0) {
|
|
4335
|
-
return /*#__PURE__*/React.createElement(SearchButtonAndDialog, {
|
|
4336
|
-
env: env,
|
|
4337
|
-
products: searchable.products
|
|
4338
|
-
});
|
|
4339
|
-
} else {
|
|
4340
|
-
return null;
|
|
4341
|
-
}
|
|
4342
|
-
}
|
|
4343
|
-
function SearchButtonAndDialog({
|
|
4344
|
-
env,
|
|
4345
|
-
products
|
|
4346
|
-
}) {
|
|
4347
4683
|
const [open, setOpen] = React.useState(false);
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
event.stopPropagation();
|
|
4355
|
-
setOpen(wasOpen => !wasOpen);
|
|
4356
|
-
} else if (isLegacySearchShortcut(event)) {
|
|
4357
|
-
event.preventDefault();
|
|
4358
|
-
event.stopPropagation();
|
|
4359
|
-
setOpen(true);
|
|
4360
|
-
}
|
|
4361
|
-
};
|
|
4362
|
-
window.addEventListener("keydown", handleKeyDown, {
|
|
4363
|
-
capture: true
|
|
4364
|
-
});
|
|
4365
|
-
return () => window.removeEventListener("keydown", handleKeyDown, {
|
|
4366
|
-
capture: true
|
|
4367
|
-
});
|
|
4368
|
-
}, []);
|
|
4369
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("button", {
|
|
4370
|
-
"aria-keyshortcuts": `${isMac() ? "Meta+K" : "Control+K"} /`,
|
|
4371
|
-
"aria-label": "Search",
|
|
4372
|
-
onClick: () => setOpen(true),
|
|
4373
|
-
type: "button"
|
|
4374
|
-
}, /*#__PURE__*/React.createElement(Spyglass, {
|
|
4375
|
-
fill: "currentColor"
|
|
4376
|
-
})), /*#__PURE__*/React.createElement(tapestry.Modal, {
|
|
4684
|
+
const available = searchable.status === "done" && searchable.products.length > 0;
|
|
4685
|
+
useSearchShortcut(available, open, setOpen);
|
|
4686
|
+
if (!available) return null;
|
|
4687
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(SearchButton, {
|
|
4688
|
+
onClick: () => setOpen(true)
|
|
4689
|
+
}), /*#__PURE__*/React.createElement(tapestry.Modal, {
|
|
4377
4690
|
"aria-label": "Search",
|
|
4378
4691
|
dismissible: true,
|
|
4379
4692
|
onClose: () => setOpen(false),
|
|
4380
4693
|
open: open
|
|
4381
4694
|
}, /*#__PURE__*/React.createElement(SearchPanel, {
|
|
4382
4695
|
env: env,
|
|
4383
|
-
products: products
|
|
4696
|
+
products: searchable.products
|
|
4384
4697
|
})));
|
|
4385
4698
|
}
|
|
4386
|
-
// Keys the recents list for navigation, so the highlight stays put as more
|
|
4387
|
-
// recents load and as their lookups answer.
|
|
4388
|
-
const RECENTS = "recents";
|
|
4389
|
-
function SearchPanel({
|
|
4390
|
-
env,
|
|
4391
|
-
products
|
|
4392
|
-
}) {
|
|
4393
|
-
var _a, _b;
|
|
4394
|
-
const listboxId = useInstanceId("product-search-results");
|
|
4395
|
-
const [term, setTerm] = React.useState("");
|
|
4396
|
-
const [selectedSlug, setSelectedSlug] = React.useState(() => initialProduct(products).slug);
|
|
4397
|
-
const product = (_a = products.find(({
|
|
4398
|
-
slug
|
|
4399
|
-
}) => slug === selectedSlug)) !== null && _a !== void 0 ? _a : products[0];
|
|
4400
|
-
const hasTerm = term.trim() !== "";
|
|
4401
|
-
const search = useProductSearch(product.slug, term);
|
|
4402
|
-
const groups = "groups" in search ? search.groups : undefined;
|
|
4403
|
-
const results = React.useMemo(() => {
|
|
4404
|
-
var _a;
|
|
4405
|
-
return (_a = groups === null || groups === void 0 ? void 0 : groups.flatMap(group => group.results)) !== null && _a !== void 0 ? _a : [];
|
|
4406
|
-
}, [groups]);
|
|
4407
|
-
const recents = useRecentVisits(env);
|
|
4408
|
-
const options = hasTerm ? results.map(({
|
|
4409
|
-
attributes
|
|
4410
|
-
}) => ({
|
|
4411
|
-
label: attributes.title,
|
|
4412
|
-
url: attributes.url
|
|
4413
|
-
})) : recents.visits.map(visit => {
|
|
4414
|
-
const {
|
|
4415
|
-
title,
|
|
4416
|
-
url
|
|
4417
|
-
} = describeVisit(visit);
|
|
4418
|
-
return {
|
|
4419
|
-
label: title,
|
|
4420
|
-
url
|
|
4421
|
-
};
|
|
4422
|
-
});
|
|
4423
|
-
const navigation = useResultNavigation(options, hasTerm ? results : RECENTS);
|
|
4424
|
-
const {
|
|
4425
|
-
highlightedIndex
|
|
4426
|
-
} = navigation;
|
|
4427
|
-
const inputRef = React.useRef(null);
|
|
4428
|
-
const [announceHighlight, setAnnounceHighlight] = React.useState(false);
|
|
4429
|
-
// The tabs keep focus while arrowing through results, but only the focused
|
|
4430
|
-
// input can point screen readers at the highlight, so from the tabs it's
|
|
4431
|
-
// announced instead. Typing goes back to the input, keystroke and all.
|
|
4432
|
-
const handleTabsKeyDown = event => {
|
|
4433
|
-
var _a;
|
|
4434
|
-
if (isTypingKey(event)) {
|
|
4435
|
-
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
4436
|
-
} else if (verticalStep(event.key)) {
|
|
4437
|
-
setAnnounceHighlight(true);
|
|
4438
|
-
navigation.handleKeyDown(event);
|
|
4439
|
-
} else {
|
|
4440
|
-
navigation.handleKeyDown(event);
|
|
4441
|
-
}
|
|
4442
|
-
};
|
|
4443
|
-
React.useEffect(() => {
|
|
4444
|
-
if (hasTerm) saveLastProduct(product.slug);
|
|
4445
|
-
}, [hasTerm, product.slug]);
|
|
4446
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("input", {
|
|
4447
|
-
"aria-activedescendant": highlightedIndex === null ? undefined : resultId(listboxId, highlightedIndex),
|
|
4448
|
-
"aria-autocomplete": "list",
|
|
4449
|
-
"aria-controls": options.length > 0 ? listboxId : undefined,
|
|
4450
|
-
"aria-expanded": options.length > 0,
|
|
4451
|
-
"aria-label": "Search",
|
|
4452
|
-
autoFocus: true,
|
|
4453
|
-
onChange: event => setTerm(event.target.value),
|
|
4454
|
-
onFocus: () => setAnnounceHighlight(false),
|
|
4455
|
-
onKeyDown: navigation.handleKeyDown,
|
|
4456
|
-
placeholder: "Search",
|
|
4457
|
-
ref: inputRef,
|
|
4458
|
-
role: "combobox",
|
|
4459
|
-
type: "search",
|
|
4460
|
-
value: term
|
|
4461
|
-
}), /*#__PURE__*/React.createElement(ProductTabs, {
|
|
4462
|
-
onKeyDown: handleTabsKeyDown,
|
|
4463
|
-
onSelect: setSelectedSlug,
|
|
4464
|
-
products: products,
|
|
4465
|
-
selected: product
|
|
4466
|
-
}, hasTerm ? (/*#__PURE__*/React.createElement(SearchResults, {
|
|
4467
|
-
highlightedIndex: highlightedIndex,
|
|
4468
|
-
id: listboxId,
|
|
4469
|
-
label: `${product.appName} results`,
|
|
4470
|
-
onHighlight: navigation.highlightIndex,
|
|
4471
|
-
search: search,
|
|
4472
|
-
term: term
|
|
4473
|
-
})) : (/*#__PURE__*/React.createElement(RecentlyVisited, {
|
|
4474
|
-
highlightedIndex: highlightedIndex,
|
|
4475
|
-
id: listboxId,
|
|
4476
|
-
onHighlight: navigation.highlightIndex,
|
|
4477
|
-
...recents
|
|
4478
|
-
}))), /*#__PURE__*/React.createElement("div", {
|
|
4479
|
-
"aria-live": "polite",
|
|
4480
|
-
className: styles$c.visuallyHidden
|
|
4481
|
-
}, announceHighlight ? (_b = navigation.highlighted) === null || _b === void 0 ? void 0 : _b.label : null), /*#__PURE__*/React.createElement(KeyboardHints, {
|
|
4482
|
-
copied: navigation.copied
|
|
4483
|
-
}));
|
|
4484
|
-
}
|
|
4485
|
-
function KeyboardHints({
|
|
4486
|
-
copied
|
|
4487
|
-
}) {
|
|
4488
|
-
const command = commandKeyLabel();
|
|
4489
|
-
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", {
|
|
4490
|
-
role: "status"
|
|
4491
|
-
}, copied ? "Copied!" : "Copy link"), " \u00B7 ", command, "K Open search");
|
|
4492
|
-
}
|
|
4493
|
-
function initialProduct(products) {
|
|
4494
|
-
var _a, _b, _c;
|
|
4495
|
-
const lastProduct = readLastProduct();
|
|
4496
|
-
const bySlug = slug => products.find(product => product.slug === slug);
|
|
4497
|
-
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];
|
|
4498
|
-
}
|
|
4499
4699
|
|
|
4500
4700
|
function useRecordRecentlyVisited({
|
|
4501
4701
|
enabled,
|
|
@@ -4539,9 +4739,9 @@ true;
|
|
|
4539
4739
|
`), children);
|
|
4540
4740
|
}
|
|
4541
4741
|
|
|
4542
|
-
var styles$
|
|
4742
|
+
var styles$a = {"route":"route--8BWe","is-active":"is-active-FsU9Y","apps-routes-separator":"apps-routes-separator-Nlm-N"};
|
|
4543
4743
|
|
|
4544
|
-
var styles$
|
|
4744
|
+
var styles$9 = {"popup":"popup-mDNKn","trigger-wrap":"trigger-wrap-Jd-KR","trigger":"trigger-WgRT5","is-visible":"is-visible-GZC0-","trigger-orgname":"trigger-orgname-TDHCc"};
|
|
4545
4745
|
|
|
4546
4746
|
const UserMenu = ({
|
|
4547
4747
|
appName,
|
|
@@ -4560,7 +4760,7 @@ true;
|
|
|
4560
4760
|
component: Outsider,
|
|
4561
4761
|
onOutsideClick: () => setUserMenuVisible(false),
|
|
4562
4762
|
cleanup: !userMenuVisible,
|
|
4563
|
-
className: styles$
|
|
4763
|
+
className: styles$9.popup,
|
|
4564
4764
|
isVisible: userMenuVisible
|
|
4565
4765
|
}, /*#__PURE__*/React.createElement("div", null, hasConnectedPeople ? (/*#__PURE__*/React.createElement("div", {
|
|
4566
4766
|
style: {
|
|
@@ -4704,11 +4904,11 @@ true;
|
|
|
4704
4904
|
userMenuVisible
|
|
4705
4905
|
}) => {
|
|
4706
4906
|
return /*#__PURE__*/React.createElement("div", {
|
|
4707
|
-
className: styles$
|
|
4907
|
+
className: styles$9["trigger-wrap"],
|
|
4708
4908
|
"data-pendo": "topbar-org-switcher"
|
|
4709
4909
|
}, /*#__PURE__*/React.createElement(Hoverable, {
|
|
4710
|
-
className: classnames(styles$
|
|
4711
|
-
[styles$
|
|
4910
|
+
className: classnames(styles$9["trigger"], {
|
|
4911
|
+
[styles$9["is-visible"]]: userMenuVisible
|
|
4712
4912
|
}),
|
|
4713
4913
|
component: "button",
|
|
4714
4914
|
type: "button",
|
|
@@ -4720,7 +4920,7 @@ true;
|
|
|
4720
4920
|
requestConnectedPeopleFetch();
|
|
4721
4921
|
}
|
|
4722
4922
|
}, showOrgName && (/*#__PURE__*/React.createElement("span", {
|
|
4723
|
-
className: styles$
|
|
4923
|
+
className: styles$9["trigger-orgname"]
|
|
4724
4924
|
}, orgName)), /*#__PURE__*/React.createElement(DisclosureChevronIcon, null)));
|
|
4725
4925
|
};
|
|
4726
4926
|
|
|
@@ -4780,7 +4980,7 @@ true;
|
|
|
4780
4980
|
colors: props.colors,
|
|
4781
4981
|
requestAppsFetch: props.requestAppsFetch
|
|
4782
4982
|
})), /*#__PURE__*/React.createElement("div", {
|
|
4783
|
-
className: styles$
|
|
4983
|
+
className: styles$a["apps-routes-separator"]
|
|
4784
4984
|
}), routesVisible && props.routes, /*#__PURE__*/React.createElement("div", {
|
|
4785
4985
|
style: {
|
|
4786
4986
|
margin: "auto"
|
|
@@ -4821,12 +5021,12 @@ true;
|
|
|
4821
5021
|
...nativeProps
|
|
4822
5022
|
}) => {
|
|
4823
5023
|
return /*#__PURE__*/React.createElement("a", {
|
|
4824
|
-
className: classnames(styles$
|
|
5024
|
+
className: classnames(styles$a["route"], className, active && styles$a["is-active"]),
|
|
4825
5025
|
...nativeProps
|
|
4826
5026
|
});
|
|
4827
5027
|
};
|
|
4828
5028
|
|
|
4829
|
-
var styles$
|
|
5029
|
+
var styles$8 = {"avatar":"avatar-tW-wn"};
|
|
4830
5030
|
|
|
4831
5031
|
function Avatar({
|
|
4832
5032
|
env,
|
|
@@ -4836,7 +5036,7 @@ true;
|
|
|
4836
5036
|
}) {
|
|
4837
5037
|
const url = incomingUrl || `${pcoUrl$1(env)("people")}/static/no_photo_thumbnail_gray.svg`;
|
|
4838
5038
|
return /*#__PURE__*/React.createElement("div", {
|
|
4839
|
-
className: styles$
|
|
5039
|
+
className: styles$8.avatar,
|
|
4840
5040
|
style: {
|
|
4841
5041
|
backgroundImage: `url(${url})`,
|
|
4842
5042
|
...style
|
|
@@ -32595,7 +32795,7 @@ true;
|
|
|
32595
32795
|
|
|
32596
32796
|
var reactDomExports = requireReactDom();
|
|
32597
32797
|
|
|
32598
|
-
var styles$
|
|
32798
|
+
var styles$7 = {"trigger":"trigger-Th-Up","layer":"layer-ck6BD","layer--visible":"layer--visible-4E2p1","panel":"panel-vobWE","header":"header-xndfZ","heading":"heading-uXyQf","close":"close-pK0Lk","list":"list-zWvrn","link":"link-Kf3qj","current":"current-g3Ey-","accounts-item":"accounts-item-eQqDD","accounts-link":"accounts-link-SeIbD"};
|
|
32599
32799
|
|
|
32600
32800
|
const AppsSwitcher = ({
|
|
32601
32801
|
appName,
|
|
@@ -32623,8 +32823,8 @@ true;
|
|
|
32623
32823
|
}, /*#__PURE__*/React.createElement("a", {
|
|
32624
32824
|
"aria-current": name === appName ? "page" : undefined,
|
|
32625
32825
|
"aria-label": name,
|
|
32626
|
-
className: classnames(styles$
|
|
32627
|
-
[styles$
|
|
32826
|
+
className: classnames(styles$7.link, {
|
|
32827
|
+
[styles$7.current]: name === appName
|
|
32628
32828
|
}),
|
|
32629
32829
|
"data-pendo": `app-switcher--change-app--${name}`,
|
|
32630
32830
|
"data-turbolinks": false,
|
|
@@ -32636,48 +32836,48 @@ true;
|
|
|
32636
32836
|
"aria-expanded": visible,
|
|
32637
32837
|
"aria-haspopup": "true",
|
|
32638
32838
|
"aria-label": `App switcher: ${appName}`,
|
|
32639
|
-
className: styles$
|
|
32839
|
+
className: styles$7.trigger,
|
|
32640
32840
|
onClick: onTriggerClick,
|
|
32641
32841
|
type: "button"
|
|
32642
32842
|
}, /*#__PURE__*/React.createElement(ColorAppIcon, {
|
|
32643
32843
|
appName: appName.replace(/[\s-]/, "")
|
|
32644
32844
|
})), /*#__PURE__*/reactDomExports.createPortal(/*#__PURE__*/React.createElement("div", {
|
|
32645
32845
|
ref: containerRef,
|
|
32646
|
-
className: classnames(styles$
|
|
32647
|
-
[styles$
|
|
32846
|
+
className: classnames(styles$7.layer, {
|
|
32847
|
+
[styles$7["layer--visible"]]: visible
|
|
32648
32848
|
}),
|
|
32649
32849
|
onClick: toggle,
|
|
32650
32850
|
onKeyDown: handleKeyDown
|
|
32651
32851
|
}, /*#__PURE__*/React.createElement("nav", {
|
|
32652
32852
|
"aria-label": "Switch app",
|
|
32653
32853
|
"aria-modal": visible,
|
|
32654
|
-
className: styles$
|
|
32854
|
+
className: styles$7.panel,
|
|
32655
32855
|
"data-pendo": "app-switcher",
|
|
32656
32856
|
onClick: event => event.stopPropagation(),
|
|
32657
32857
|
role: "dialog"
|
|
32658
32858
|
}, /*#__PURE__*/React.createElement("div", {
|
|
32659
|
-
className: styles$
|
|
32859
|
+
className: styles$7.header
|
|
32660
32860
|
}, /*#__PURE__*/React.createElement("span", {
|
|
32661
|
-
className: styles$
|
|
32861
|
+
className: styles$7.heading
|
|
32662
32862
|
}, "Switch to"), /*#__PURE__*/React.createElement("button", {
|
|
32663
32863
|
"aria-label": "Close",
|
|
32664
|
-
className: styles$
|
|
32864
|
+
className: styles$7.close,
|
|
32665
32865
|
onClick: toggle,
|
|
32666
32866
|
type: "button"
|
|
32667
32867
|
}, /*#__PURE__*/React.createElement(X, {
|
|
32668
32868
|
"aria-hidden": "true",
|
|
32669
32869
|
fill: "var(--t-icon-color-dim)"
|
|
32670
32870
|
}))), /*#__PURE__*/React.createElement("ul", {
|
|
32671
|
-
className: styles$
|
|
32871
|
+
className: styles$7.list,
|
|
32672
32872
|
role: "list"
|
|
32673
32873
|
}, homeProduct && productLink(homeProduct.name), restProducts.map(({
|
|
32674
32874
|
name
|
|
32675
32875
|
}) => productLink(name)), accountsProduct && (/*#__PURE__*/React.createElement("li", {
|
|
32676
|
-
className: styles$
|
|
32876
|
+
className: styles$7["accounts-item"]
|
|
32677
32877
|
}, /*#__PURE__*/React.createElement("a", {
|
|
32678
32878
|
"aria-current": appName === "Accounts" ? "page" : undefined,
|
|
32679
32879
|
"aria-label": "Account settings",
|
|
32680
|
-
className: classnames(styles$
|
|
32880
|
+
className: classnames(styles$7.link, styles$7["accounts-link"]),
|
|
32681
32881
|
"data-pendo": "app-switcher--change-app--Accounts",
|
|
32682
32882
|
"data-turbolinks": false,
|
|
32683
32883
|
href: pcoUrl$1(env)("accounts") + getAppsSwitchProductPath(accountsProduct.name)
|
|
@@ -32700,14 +32900,14 @@ true;
|
|
|
32700
32900
|
method: "localStorage"
|
|
32701
32901
|
};
|
|
32702
32902
|
|
|
32703
|
-
var styles$
|
|
32903
|
+
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"};
|
|
32704
32904
|
|
|
32705
32905
|
function AccountSettingsLink({
|
|
32706
32906
|
env
|
|
32707
32907
|
}) {
|
|
32708
32908
|
const accountsName = "accounts";
|
|
32709
32909
|
return /*#__PURE__*/React.createElement("a", {
|
|
32710
|
-
className: classnames(styles$
|
|
32910
|
+
className: classnames(styles$6["appmenu-list-a"], styles$6["appmenu-list-a--bottom"]),
|
|
32711
32911
|
"data-pendo": `app-switcher--change-app--${accountsName}`,
|
|
32712
32912
|
"data-turbolinks": false,
|
|
32713
32913
|
href: pcoUrl$1(env)(accountsName) + getAppsSwitchProductPath(accountsName)
|
|
@@ -32730,7 +32930,7 @@ true;
|
|
|
32730
32930
|
}) => (/*#__PURE__*/React.createElement("button", {
|
|
32731
32931
|
"aria-label": "Close menu",
|
|
32732
32932
|
type: "button",
|
|
32733
|
-
className: styles$
|
|
32933
|
+
className: styles$6["appmenu-close-button"],
|
|
32734
32934
|
style: style
|
|
32735
32935
|
}, /*#__PURE__*/React.createElement(X, {
|
|
32736
32936
|
fill: color,
|
|
@@ -32791,7 +32991,7 @@ true;
|
|
|
32791
32991
|
"aria-haspopup": "true",
|
|
32792
32992
|
"aria-label": `App switcher: ${appName}`,
|
|
32793
32993
|
type: "button",
|
|
32794
|
-
className: styles$
|
|
32994
|
+
className: styles$6["appmenu-button"],
|
|
32795
32995
|
onClick: onTriggerClick
|
|
32796
32996
|
}, /*#__PURE__*/React.createElement(ColorAppIcon, {
|
|
32797
32997
|
appName: appName.replace(/[\s-]/, "")
|
|
@@ -32799,7 +32999,7 @@ true;
|
|
|
32799
32999
|
item: "Topbar:Small:Menus:Products:visibility",
|
|
32800
33000
|
render: () => (/*#__PURE__*/React.createElement("div", {
|
|
32801
33001
|
ref: appMenuRef,
|
|
32802
|
-
className: styles$
|
|
33002
|
+
className: styles$6["appmenu-layer"],
|
|
32803
33003
|
style: {
|
|
32804
33004
|
...(visible && {
|
|
32805
33005
|
display: "block"
|
|
@@ -32816,37 +33016,37 @@ true;
|
|
|
32816
33016
|
e.stopPropagation();
|
|
32817
33017
|
}
|
|
32818
33018
|
},
|
|
32819
|
-
className: styles$
|
|
33019
|
+
className: styles$6["appmenu-container"]
|
|
32820
33020
|
}, /*#__PURE__*/React.createElement("a", {
|
|
32821
33021
|
"aria-current": appName === (homeProduct === null || homeProduct === void 0 ? void 0 : homeProduct.name) ? "page" : undefined,
|
|
32822
33022
|
"aria-label": homeProduct ? homeProduct.name : appName,
|
|
32823
33023
|
"data-pendo": `app-switcher--change-app--${homeProduct === null || homeProduct === void 0 ? void 0 : homeProduct.name}`,
|
|
32824
33024
|
"data-turbolinks": false,
|
|
32825
|
-
className: classnames(styles$
|
|
33025
|
+
className: classnames(styles$6["appmenu-list-a"], styles$6["appmenu-list-a--top"]),
|
|
32826
33026
|
href: homeProduct ? pcoUrl$1(env)("accounts") + getAppsSwitchProductPath(homeProduct === null || homeProduct === void 0 ? void 0 : homeProduct.name) : undefined
|
|
32827
33027
|
}, /*#__PURE__*/React.createElement(UserMenuAppLockup, {
|
|
32828
33028
|
appName: homeProduct ? homeProduct.name : appName
|
|
32829
33029
|
})), /*#__PURE__*/React.createElement("div", {
|
|
32830
|
-
className: styles$
|
|
33030
|
+
className: styles$6["appmenu-scroll"]
|
|
32831
33031
|
}, /*#__PURE__*/React.createElement("ul", {
|
|
32832
33032
|
"data-pendo": "app-switcher",
|
|
32833
|
-
className: styles$
|
|
33033
|
+
className: styles$6["appmenu-list"]
|
|
32834
33034
|
}, appsMenuFormatter(restProducts).map(({
|
|
32835
33035
|
name
|
|
32836
33036
|
}) => (/*#__PURE__*/React.createElement("li", {
|
|
32837
33037
|
key: name,
|
|
32838
|
-
className: styles$
|
|
33038
|
+
className: styles$6["appmenu-list-li"]
|
|
32839
33039
|
}, /*#__PURE__*/React.createElement("a", {
|
|
32840
33040
|
"aria-current": name === appName ? "page" : undefined,
|
|
32841
33041
|
"aria-label": name,
|
|
32842
33042
|
"data-pendo": `app-switcher--change-app--${name}`,
|
|
32843
33043
|
"data-turbolinks": false,
|
|
32844
|
-
className: styles$
|
|
33044
|
+
className: styles$6["appmenu-list-a"],
|
|
32845
33045
|
href: pcoUrl$1(env)("accounts") + getAppsSwitchProductPath(name)
|
|
32846
33046
|
}, /*#__PURE__*/React.createElement(UserMenuAppLockup, {
|
|
32847
33047
|
appName: name
|
|
32848
33048
|
}))))), accountsProduct && (/*#__PURE__*/React.createElement("li", {
|
|
32849
|
-
className: styles$
|
|
33049
|
+
className: styles$6["appmenu-list-li"]
|
|
32850
33050
|
}, /*#__PURE__*/React.createElement(AccountSettingsLink, {
|
|
32851
33051
|
env: env
|
|
32852
33052
|
}))))))))
|
|
@@ -32910,11 +33110,11 @@ true;
|
|
|
32910
33110
|
toggle: toggleProductSwitcher,
|
|
32911
33111
|
visible: productSwitcherVisible
|
|
32912
33112
|
})), routesMenuVisible && (/*#__PURE__*/React.createElement("div", {
|
|
32913
|
-
className: styles$
|
|
33113
|
+
className: styles$6["routes"]
|
|
32914
33114
|
}, props.routes)), /*#__PURE__*/React.createElement("button", {
|
|
32915
33115
|
type: "button",
|
|
32916
|
-
className: classnames(styles$
|
|
32917
|
-
[styles$
|
|
33116
|
+
className: classnames(styles$6["current-route"], {
|
|
33117
|
+
[styles$6["is-active"]]: routesMenuVisible
|
|
32918
33118
|
}),
|
|
32919
33119
|
onClick: props.routes.length > 0 ? () => {
|
|
32920
33120
|
setProductSwitcherVisible(false);
|
|
@@ -32922,7 +33122,7 @@ true;
|
|
|
32922
33122
|
} : null
|
|
32923
33123
|
}, /*#__PURE__*/React.createElement(CurrentRouteComponent, null, capitalize$1(currentRouteText)), props.routes.length > 0 && /*#__PURE__*/React.createElement(DisclosureChevronIcon, null)), /*#__PURE__*/React.createElement("button", {
|
|
32924
33124
|
type: "button",
|
|
32925
|
-
className: styles$
|
|
33125
|
+
className: styles$6["profile-button"],
|
|
32926
33126
|
onClick: () => {
|
|
32927
33127
|
var _a, _b;
|
|
32928
33128
|
props.requestConnectedPeopleFetch();
|
|
@@ -32938,7 +33138,7 @@ true;
|
|
|
32938
33138
|
className,
|
|
32939
33139
|
...props
|
|
32940
33140
|
}) => (/*#__PURE__*/React.createElement("a", {
|
|
32941
|
-
className: classnames(styles$
|
|
33141
|
+
className: classnames(styles$6["route"], className, active && styles$6["is-active"]),
|
|
32942
33142
|
...props
|
|
32943
33143
|
}));
|
|
32944
33144
|
|
|
@@ -33077,7 +33277,7 @@ true;
|
|
|
33077
33277
|
id: "topbar"
|
|
33078
33278
|
};
|
|
33079
33279
|
|
|
33080
|
-
var styles$
|
|
33280
|
+
var styles$5 = {"debug-pco-resource":"debug-pco-resource-sLteM","debug-pco-resource-header":"debug-pco-resource-header-5fEbe","debug-pco-resource-badge":"debug-pco-resource-badge-J9v1F","debug-pco-resource-title":"debug-pco-resource-title-volWV","debug-pco-resource-field":"debug-pco-resource-field-7Gitp","debug-pco-resource-field-label":"debug-pco-resource-field-label--f1xX","debug-pco-resource-field-value":"debug-pco-resource-field-value-YoX-C","debug-pco-resource-note":"debug-pco-resource-note-N5xyf","debug-pco-resource-json":"debug-pco-resource-json-Rx-JI"};
|
|
33081
33281
|
|
|
33082
33282
|
function isPresent(value) {
|
|
33083
33283
|
return value !== undefined && value.trim() !== "";
|
|
@@ -33106,11 +33306,11 @@ true;
|
|
|
33106
33306
|
value
|
|
33107
33307
|
}) {
|
|
33108
33308
|
return /*#__PURE__*/React.createElement("div", {
|
|
33109
|
-
className: styles$
|
|
33309
|
+
className: styles$5["debug-pco-resource-field"]
|
|
33110
33310
|
}, /*#__PURE__*/React.createElement("span", {
|
|
33111
|
-
className: styles$
|
|
33311
|
+
className: styles$5["debug-pco-resource-field-label"]
|
|
33112
33312
|
}, label), /*#__PURE__*/React.createElement("span", {
|
|
33113
|
-
className: styles$
|
|
33313
|
+
className: styles$5["debug-pco-resource-field-value"]
|
|
33114
33314
|
}, value));
|
|
33115
33315
|
}
|
|
33116
33316
|
// Only staff ghosting or impersonating a person get pco:staff-access-level,
|
|
@@ -33183,13 +33383,13 @@ true;
|
|
|
33183
33383
|
};
|
|
33184
33384
|
}, [pcrl, env]);
|
|
33185
33385
|
return /*#__PURE__*/React.createElement("div", {
|
|
33186
|
-
className: classnames("staff-only", styles$
|
|
33386
|
+
className: classnames("staff-only", styles$5["debug-pco-resource"])
|
|
33187
33387
|
}, /*#__PURE__*/React.createElement("div", {
|
|
33188
|
-
className: styles$
|
|
33388
|
+
className: styles$5["debug-pco-resource-header"]
|
|
33189
33389
|
}, /*#__PURE__*/React.createElement("span", {
|
|
33190
|
-
className: styles$
|
|
33390
|
+
className: styles$5["debug-pco-resource-badge"]
|
|
33191
33391
|
}, "Staff"), /*#__PURE__*/React.createElement("span", {
|
|
33192
|
-
className: styles$
|
|
33392
|
+
className: styles$5["debug-pco-resource-title"]
|
|
33193
33393
|
}, "Recently Visited debug")), /*#__PURE__*/React.createElement(Field, {
|
|
33194
33394
|
label: "pco:resource",
|
|
33195
33395
|
value: describeTag("resource", resource)
|
|
@@ -33197,29 +33397,29 @@ true;
|
|
|
33197
33397
|
label: "pco:recently_visitable",
|
|
33198
33398
|
value: describeTag("recently_visitable", recentlyVisitable)
|
|
33199
33399
|
}), hasInvalidResource && (/*#__PURE__*/React.createElement("p", {
|
|
33200
|
-
className: styles$
|
|
33400
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33201
33401
|
}, "pco:resource isn't a PCRL (product/v2/type/id), so Recently Visited ignores it.")), visit === null && (/*#__PURE__*/React.createElement("p", {
|
|
33202
|
-
className: styles$
|
|
33402
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33203
33403
|
}, "This page is not eligible for Recently Visited")), pcrl && hasRecentlyVisitable && (/*#__PURE__*/React.createElement("p", {
|
|
33204
|
-
className: styles$
|
|
33404
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33205
33405
|
}, "Both tags are present \u2014 pco:resource takes precedence for the Recently Visited entry.")), pcrl && lookup.status === "loading" && (/*#__PURE__*/React.createElement("p", {
|
|
33206
|
-
className: styles$
|
|
33406
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33207
33407
|
}, "Looking up resource\u2026")), pcrl && lookup.status === "error" && (/*#__PURE__*/React.createElement("p", {
|
|
33208
|
-
className: styles$
|
|
33408
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33209
33409
|
}, lookup.message)), pcrl && lookup.status === "loaded" && (/*#__PURE__*/React.createElement("pre", {
|
|
33210
|
-
className: styles$
|
|
33410
|
+
className: styles$5["debug-pco-resource-json"]
|
|
33211
33411
|
}, JSON.stringify(lookup.json, null, 2))), (visit === null || visit === void 0 ? void 0 : visit.type) === "page" && (/*#__PURE__*/React.createElement("p", {
|
|
33212
|
-
className: styles$
|
|
33412
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33213
33413
|
}, "Recently Visited title: ", visit.title)), /*#__PURE__*/React.createElement("span", {
|
|
33214
|
-
className: styles$
|
|
33414
|
+
className: styles$5["debug-pco-resource-field-label"]
|
|
33215
33415
|
}, "Recently Visited"), personId ? (/*#__PURE__*/React.createElement("pre", {
|
|
33216
|
-
className: styles$
|
|
33416
|
+
className: styles$5["debug-pco-resource-json"]
|
|
33217
33417
|
}, JSON.stringify(recentlyVisited, null, 2))) : (/*#__PURE__*/React.createElement("p", {
|
|
33218
|
-
className: styles$
|
|
33418
|
+
className: styles$5["debug-pco-resource-note"]
|
|
33219
33419
|
}, "No current person, so nothing is recorded.")));
|
|
33220
33420
|
}
|
|
33221
33421
|
|
|
33222
|
-
var styles$
|
|
33422
|
+
var styles$4 = {"drawer-wrap":"drawer-wrap-J0rSL","is-visible":"is-visible-KTME8","drawer":"drawer-j7f4l"};
|
|
33223
33423
|
|
|
33224
33424
|
function Drawer({
|
|
33225
33425
|
children,
|
|
@@ -33227,7 +33427,7 @@ true;
|
|
|
33227
33427
|
}) {
|
|
33228
33428
|
return /*#__PURE__*/React.createElement("div", {
|
|
33229
33429
|
id: id,
|
|
33230
|
-
className: styles$
|
|
33430
|
+
className: styles$4["drawer"]
|
|
33231
33431
|
}, children);
|
|
33232
33432
|
}
|
|
33233
33433
|
function DrawerWrap({
|
|
@@ -33237,7 +33437,7 @@ true;
|
|
|
33237
33437
|
...props
|
|
33238
33438
|
}) {
|
|
33239
33439
|
return /*#__PURE__*/React.createElement("div", {
|
|
33240
|
-
className: classnames(styles$
|
|
33440
|
+
className: classnames(styles$4["drawer-wrap"], className, isVisible && styles$4["is-visible"]),
|
|
33241
33441
|
...props
|
|
33242
33442
|
}, children);
|
|
33243
33443
|
}
|
|
@@ -33453,7 +33653,7 @@ true;
|
|
|
33453
33653
|
}));
|
|
33454
33654
|
}
|
|
33455
33655
|
|
|
33456
|
-
var styles$
|
|
33656
|
+
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"};
|
|
33457
33657
|
|
|
33458
33658
|
const COLOR_MODES = [{
|
|
33459
33659
|
icon: "toolbar.sun",
|
|
@@ -33476,11 +33676,11 @@ true;
|
|
|
33476
33676
|
const updateStore = useUpdateStore();
|
|
33477
33677
|
const [counter] = React.useState(() => COLOR_MODE_INSTANCE_COUNTER++);
|
|
33478
33678
|
return /*#__PURE__*/React.createElement("fieldset", {
|
|
33479
|
-
className: styles$
|
|
33679
|
+
className: styles$3["color-mode-switcher"]
|
|
33480
33680
|
}, /*#__PURE__*/React.createElement("legend", {
|
|
33481
|
-
className: styles$
|
|
33681
|
+
className: styles$3["color-mode-switcher-label"]
|
|
33482
33682
|
}, "Appearance", " "), /*#__PURE__*/React.createElement("div", {
|
|
33483
|
-
className: styles$
|
|
33683
|
+
className: styles$3["color-mode-switcher-modes"]
|
|
33484
33684
|
}, COLOR_MODES.map(({
|
|
33485
33685
|
icon,
|
|
33486
33686
|
label,
|
|
@@ -33750,7 +33950,7 @@ true;
|
|
|
33750
33950
|
...overrides
|
|
33751
33951
|
});
|
|
33752
33952
|
|
|
33753
|
-
var styles$
|
|
33953
|
+
var styles$2 = {"toolbar":"toolbar-KHJR5","toolbar-button":"toolbar-button-Ye4h5","is-current":"is-current-DZK47","toolbar-button--avatar":"toolbar-button--avatar-5FUik","toolbar-button--home":"toolbar-button--home-Pthd0"};
|
|
33754
33954
|
|
|
33755
33955
|
// PCO Box serves TLS by default, and a bare http:// frame inside an https
|
|
33756
33956
|
// product page is blocked as mixed content, so follow the page's scheme.
|
|
@@ -33922,7 +34122,7 @@ true;
|
|
|
33922
34122
|
name: "DeveloperTools"
|
|
33923
34123
|
};
|
|
33924
34124
|
|
|
33925
|
-
var styles = {"banner":"banner-YfQ37","stacked":"stacked-EwLRh","content":"content-lNjWf","icon":"icon-abz7q","iconShape":"iconShape-6uyot","iconSparkle":"iconSparkle-t0OzK","text":"text--Vlhl","title":"title-zOEOR","subtitle":"subtitle-ufLnk","chevron":"chevron-oOUA-","inlineContent":"inlineContent-h5sVl","sparkle":"sparkle-uuMBp","inlineTitle":"inlineTitle-ru2Rk","action":"action-fSY3n","actionLabel":"actionLabel-MRBjb","actionChevron":"actionChevron-DghlN"};
|
|
34125
|
+
var styles$1 = {"banner":"banner-YfQ37","stacked":"stacked-EwLRh","content":"content-lNjWf","icon":"icon-abz7q","iconShape":"iconShape-6uyot","iconSparkle":"iconSparkle-t0OzK","text":"text--Vlhl","title":"title-zOEOR","subtitle":"subtitle-ufLnk","chevron":"chevron-oOUA-","inlineContent":"inlineContent-h5sVl","sparkle":"sparkle-uuMBp","inlineTitle":"inlineTitle-ru2Rk","action":"action-fSY3n","actionLabel":"actionLabel-MRBjb","actionChevron":"actionChevron-DghlN"};
|
|
33926
34126
|
|
|
33927
34127
|
const SPARKLE_PATH$1 = "M3.809 10.1332C3.87511 9.95596 4.12579 9.95588 4.19181 10.1332L4.63712 11.3363C4.64169 11.3487 4.65116 11.359 4.66349 11.3637L5.86661 11.809C6.04452 11.8749 6.04455 12.126 5.86661 12.1918L4.66349 12.6371C4.65134 12.6417 4.64173 12.6513 4.63712 12.6635L4.19181 13.8666C4.12597 14.0445 3.87486 14.0445 3.809 13.8666L3.36368 12.6635C3.35905 12.6512 3.3487 12.6417 3.33634 12.6371L2.13321 12.1918C1.95588 12.1258 1.95596 11.8751 2.13321 11.809L3.33634 11.3637C3.34877 11.3591 3.35908 11.3488 3.36368 11.3363L3.809 10.1332ZM8.52091 3.33341C8.68571 2.88899 9.31518 2.88891 9.47989 3.33341L10.5922 6.34122C10.6037 6.37226 10.6285 6.39712 10.6596 6.4086L13.6664 7.52091C14.1113 7.68553 14.1113 8.31528 13.6664 8.47989L10.6596 9.5922C10.6285 9.6037 10.6037 9.6285 10.5922 9.65958L9.47989 12.6664C9.31528 13.1113 8.68553 13.1113 8.52091 12.6664L7.4086 9.65958C7.39712 9.62853 7.37226 9.60371 7.34122 9.5922L4.33341 8.47989C3.88891 8.31518 3.88899 7.68571 4.33341 7.52091L7.34122 6.4086C7.3723 6.3971 7.3971 6.3723 7.4086 6.34122L8.52091 3.33341ZM3.809 2.13321C3.87511 1.95596 4.12579 1.95588 4.19181 2.13321L4.63712 3.33634C4.64169 3.3487 4.65116 3.35905 4.66349 3.36368L5.86661 3.809C6.04452 3.87486 6.04455 4.12597 5.86661 4.19181L4.66349 4.63712C4.65134 4.64173 4.64173 4.65134 4.63712 4.66349L4.19181 5.86661C4.12597 6.04455 3.87486 6.04452 3.809 5.86661L3.36368 4.66349C3.35905 4.65116 3.3487 4.64169 3.33634 4.63712L2.13321 4.19181C1.95588 4.12579 1.95596 3.87511 2.13321 3.809L3.33634 3.36368C3.34877 3.35908 3.35908 3.34877 3.36368 3.33634L3.809 2.13321Z";
|
|
33928
34128
|
// Same stops as the AskAIBanner border gradient, so the two stay in sync.
|
|
@@ -33982,8 +34182,8 @@ true;
|
|
|
33982
34182
|
var _a, _b;
|
|
33983
34183
|
const isStacked = props.variant !== "inline";
|
|
33984
34184
|
return /*#__PURE__*/React.createElement("button", {
|
|
33985
|
-
className: classnames(styles.banner, {
|
|
33986
|
-
[styles.stacked]: isStacked
|
|
34185
|
+
className: classnames(styles$1.banner, {
|
|
34186
|
+
[styles$1.stacked]: isStacked
|
|
33987
34187
|
}),
|
|
33988
34188
|
onClick: () => props.onClick(),
|
|
33989
34189
|
type: "button"
|
|
@@ -33998,15 +34198,15 @@ true;
|
|
|
33998
34198
|
title
|
|
33999
34199
|
}) {
|
|
34000
34200
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
|
|
34001
|
-
className: styles.content
|
|
34201
|
+
className: styles$1.content
|
|
34002
34202
|
}, /*#__PURE__*/React.createElement(AskAIIcon, null), /*#__PURE__*/React.createElement("span", {
|
|
34003
|
-
className: styles.text
|
|
34203
|
+
className: styles$1.text
|
|
34004
34204
|
}, /*#__PURE__*/React.createElement("span", {
|
|
34005
|
-
className: styles.title
|
|
34205
|
+
className: styles$1.title
|
|
34006
34206
|
}, title), /*#__PURE__*/React.createElement("span", {
|
|
34007
|
-
className: styles.subtitle
|
|
34207
|
+
className: styles$1.subtitle
|
|
34008
34208
|
}, "Support answers tailored to you"))), /*#__PURE__*/React.createElement(tapestryReact.Icon, {
|
|
34009
|
-
className: styles.chevron,
|
|
34209
|
+
className: styles$1.chevron,
|
|
34010
34210
|
name: "general.rightChevron",
|
|
34011
34211
|
size: "16px"
|
|
34012
34212
|
}));
|
|
@@ -34016,18 +34216,18 @@ true;
|
|
|
34016
34216
|
title
|
|
34017
34217
|
}) {
|
|
34018
34218
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
|
|
34019
|
-
className: styles.inlineContent
|
|
34219
|
+
className: styles$1.inlineContent
|
|
34020
34220
|
}, /*#__PURE__*/React.createElement(SparkleIcon, {
|
|
34021
|
-
className: styles.sparkle,
|
|
34221
|
+
className: styles$1.sparkle,
|
|
34022
34222
|
fill: "currentColor"
|
|
34023
34223
|
}), /*#__PURE__*/React.createElement("span", {
|
|
34024
|
-
className: styles.inlineTitle
|
|
34224
|
+
className: styles$1.inlineTitle
|
|
34025
34225
|
}, title)), /*#__PURE__*/React.createElement("span", {
|
|
34026
|
-
className: styles.action
|
|
34226
|
+
className: styles$1.action
|
|
34027
34227
|
}, /*#__PURE__*/React.createElement("span", {
|
|
34028
|
-
className: styles.actionLabel
|
|
34228
|
+
className: styles$1.actionLabel
|
|
34029
34229
|
}, action), /*#__PURE__*/React.createElement(tapestryReact.Icon, {
|
|
34030
|
-
className: styles.actionChevron,
|
|
34230
|
+
className: styles$1.actionChevron,
|
|
34031
34231
|
name: "general.rightChevron",
|
|
34032
34232
|
size: "14px"
|
|
34033
34233
|
})));
|
|
@@ -34044,9 +34244,9 @@ true;
|
|
|
34044
34244
|
const borderA = `${uid}-border-a`;
|
|
34045
34245
|
const borderB = `${uid}-border-b`;
|
|
34046
34246
|
return /*#__PURE__*/React.createElement("span", {
|
|
34047
|
-
className: styles.icon
|
|
34247
|
+
className: styles$1.icon
|
|
34048
34248
|
}, /*#__PURE__*/React.createElement("svg", {
|
|
34049
|
-
className: styles.iconShape,
|
|
34249
|
+
className: styles$1.iconShape,
|
|
34050
34250
|
viewBox: "0 0 32 32",
|
|
34051
34251
|
fill: "none",
|
|
34052
34252
|
"aria-hidden": "true"
|
|
@@ -34217,7 +34417,7 @@ true;
|
|
|
34217
34417
|
stopColor: "#D48B91",
|
|
34218
34418
|
stopOpacity: "0"
|
|
34219
34419
|
})))), /*#__PURE__*/React.createElement("svg", {
|
|
34220
|
-
className: styles.iconSparkle,
|
|
34420
|
+
className: styles$1.iconSparkle,
|
|
34221
34421
|
viewBox: "0 0 19.4995 17.9999",
|
|
34222
34422
|
"aria-hidden": "true"
|
|
34223
34423
|
}, /*#__PURE__*/React.createElement("path", {
|
|
@@ -34226,6 +34426,23 @@ true;
|
|
|
34226
34426
|
})));
|
|
34227
34427
|
}
|
|
34228
34428
|
|
|
34429
|
+
var styles = {"button":"button-2NVI1","sparkle":"sparkle-ruJGP","label":"label-4NUGB"};
|
|
34430
|
+
|
|
34431
|
+
function AskAIButton({
|
|
34432
|
+
onClick,
|
|
34433
|
+
text = "Ask AI"
|
|
34434
|
+
}) {
|
|
34435
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
34436
|
+
className: styles.button,
|
|
34437
|
+
onClick: () => onClick(),
|
|
34438
|
+
type: "button"
|
|
34439
|
+
}, /*#__PURE__*/React.createElement(SparkleIcon, {
|
|
34440
|
+
className: styles.sparkle
|
|
34441
|
+
}), /*#__PURE__*/React.createElement("span", {
|
|
34442
|
+
className: styles.label
|
|
34443
|
+
}, text));
|
|
34444
|
+
}
|
|
34445
|
+
|
|
34229
34446
|
// The article heading lives in the deepest populated hierarchy level (lvl0 is
|
|
34230
34447
|
// always "Planning Center").
|
|
34231
34448
|
const hitTitle = hierarchy => (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl6) || (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl5) || (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl4) || (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl3) || (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl2) || (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl1) || (hierarchy === null || hierarchy === void 0 ? void 0 : hierarchy.lvl0) || "";
|
|
@@ -34536,6 +34753,18 @@ true;
|
|
|
34536
34753
|
}
|
|
34537
34754
|
}
|
|
34538
34755
|
},
|
|
34756
|
+
AskAIButton: {
|
|
34757
|
+
component: AskAIButton,
|
|
34758
|
+
properties: {
|
|
34759
|
+
onClick: {
|
|
34760
|
+
event: false,
|
|
34761
|
+
type: Function
|
|
34762
|
+
},
|
|
34763
|
+
text: {
|
|
34764
|
+
type: String
|
|
34765
|
+
}
|
|
34766
|
+
}
|
|
34767
|
+
},
|
|
34539
34768
|
CalendlyWidget: {
|
|
34540
34769
|
component: CalendlyWidget,
|
|
34541
34770
|
properties: {
|
|
@@ -36044,18 +36273,18 @@ true;
|
|
|
36044
36273
|
return /*#__PURE__*/React.createElement(tapestryReact.ThemeProvider, {
|
|
36045
36274
|
theme: topbarTheme
|
|
36046
36275
|
}, /*#__PURE__*/React.createElement(addOns.UiExtensionDataContext, null, /*#__PURE__*/React.createElement("div", {
|
|
36047
|
-
className: styles$
|
|
36276
|
+
className: styles$2["toolbar"],
|
|
36048
36277
|
"data-pendo": "toolbar-profile-support-wrapper"
|
|
36049
36278
|
}, /*#__PURE__*/React.createElement(ToolbarButton, {
|
|
36050
36279
|
"aria-label": `Open ${userName}’s profile drawer`,
|
|
36051
36280
|
onClick: () => toggleDrawer(Profile),
|
|
36052
36281
|
"data-pendo": "toolbar-profile",
|
|
36053
|
-
className: styles$
|
|
36282
|
+
className: styles$2["toolbar-button--avatar"]
|
|
36054
36283
|
}, /*#__PURE__*/React.createElement(Avatar, {
|
|
36055
36284
|
env: env,
|
|
36056
36285
|
url: userAvatarPath
|
|
36057
36286
|
})), /*#__PURE__*/React.createElement(ToolbarButton, {
|
|
36058
|
-
className: styles$
|
|
36287
|
+
className: styles$2["toolbar-button--home"],
|
|
36059
36288
|
onClick: () => closeDrawer()
|
|
36060
36289
|
}, /*#__PURE__*/React.createElement(tapestryReact.Icon, {
|
|
36061
36290
|
name: "toolbar.planningCenter",
|
|
@@ -36092,7 +36321,7 @@ true;
|
|
|
36092
36321
|
}) => {
|
|
36093
36322
|
return /*#__PURE__*/React.createElement("button", {
|
|
36094
36323
|
type: "button",
|
|
36095
|
-
className: classnames(styles$
|
|
36324
|
+
className: classnames(styles$2["toolbar-button"], className, current && styles$2["is-current"]),
|
|
36096
36325
|
onClick: onClick,
|
|
36097
36326
|
"data-toolbar-link": "true",
|
|
36098
36327
|
...restProps
|