@planningcenter/topbar 12.5.0-rc.3 → 12.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/topbar.js +69 -18
- package/dist/topbar.js.map +1 -1
- package/dist/topbar.modern.js +69 -18
- package/dist/topbar.modern.js.map +1 -1
- package/dist/topbar.module.js +69 -18
- package/dist/topbar.module.js.map +1 -1
- package/dist/topbar.umd.js +69 -18
- package/dist/topbar.umd.js.map +1 -1
- package/package.json +3 -4
package/dist/topbar.module.js
CHANGED
|
@@ -3337,6 +3337,25 @@ function SearchButton({
|
|
|
3337
3337
|
}));
|
|
3338
3338
|
}
|
|
3339
3339
|
|
|
3340
|
+
// With the search's own debounce, about 1.4 seconds after the last keystroke,
|
|
3341
|
+
// as in GOV.UK's accessible-autocomplete.
|
|
3342
|
+
const ANNOUNCEMENT_DELAY_MS = 1100;
|
|
3343
|
+
// Screen readers echo typing themselves, as each person has set them to, so
|
|
3344
|
+
// the message waits until typing settles instead of talking over it. Waiting
|
|
3345
|
+
// also lets VoiceOver finish what focus had to say, since it often skips a
|
|
3346
|
+
// change made as focus moves, as when a tab with cached results is selected,
|
|
3347
|
+
// and only the tab someone stops on when arrowing through them is announced.
|
|
3348
|
+
// The region empties at once, so a message that comes back is read again.
|
|
3349
|
+
function useAnnouncement(message) {
|
|
3350
|
+
const [announcement, setAnnouncement] = React__default.useState(null);
|
|
3351
|
+
React__default.useEffect(() => {
|
|
3352
|
+
setAnnouncement(null);
|
|
3353
|
+
const timeout = setTimeout(() => setAnnouncement(message), ANNOUNCEMENT_DELAY_MS);
|
|
3354
|
+
return () => clearTimeout(timeout);
|
|
3355
|
+
}, [message]);
|
|
3356
|
+
return announcement;
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3340
3359
|
// useId isn't available on React 17, which our peer range still supports.
|
|
3341
3360
|
let instanceCount$1 = 0;
|
|
3342
3361
|
function useInstanceId(prefix) {
|
|
@@ -4086,7 +4105,18 @@ function subject(token) {
|
|
|
4086
4105
|
return undefined;
|
|
4087
4106
|
}
|
|
4088
4107
|
}
|
|
4089
|
-
|
|
4108
|
+
const minting = new Map();
|
|
4109
|
+
function mintToken(personId) {
|
|
4110
|
+
const running = minting.get(personId);
|
|
4111
|
+
if (running) {
|
|
4112
|
+
return running;
|
|
4113
|
+
} else {
|
|
4114
|
+
const run = mint(personId).finally(() => minting.delete(personId));
|
|
4115
|
+
minting.set(personId, run);
|
|
4116
|
+
return run;
|
|
4117
|
+
}
|
|
4118
|
+
}
|
|
4119
|
+
async function mint(personId) {
|
|
4090
4120
|
const {
|
|
4091
4121
|
json,
|
|
4092
4122
|
ok,
|
|
@@ -4110,6 +4140,10 @@ async function mintToken(personId) {
|
|
|
4110
4140
|
}
|
|
4111
4141
|
return token;
|
|
4112
4142
|
}
|
|
4143
|
+
function currentToken(personId) {
|
|
4144
|
+
var _a;
|
|
4145
|
+
return (_a = cachedToken(personId)) !== null && _a !== void 0 ? _a : mintToken(personId).catch(() => null);
|
|
4146
|
+
}
|
|
4113
4147
|
async function request(personId, key, init = {}, isRetry = false) {
|
|
4114
4148
|
var _a;
|
|
4115
4149
|
const token = isRetry ? await mintToken(personId) : (_a = cachedToken(personId)) !== null && _a !== void 0 ? _a : await mintToken(personId);
|
|
@@ -4145,8 +4179,8 @@ function ifMatch(version) {
|
|
|
4145
4179
|
// retrying when another tab or device wrote in between. `change` returns null
|
|
4146
4180
|
// when there's nothing to write. A read-only token (staff impersonating
|
|
4147
4181
|
// someone) only reads, so nothing is written into the person's history.
|
|
4148
|
-
// Resolves to the value now stored,
|
|
4149
|
-
// reached.
|
|
4182
|
+
// Resolves to the value now stored, with whether the token was read-only, or
|
|
4183
|
+
// null when the service couldn't be reached.
|
|
4150
4184
|
async function updateStoredValue(personId, key, change, attemptsLeft = MAX_ATTEMPTS) {
|
|
4151
4185
|
const read = await request(personId, key);
|
|
4152
4186
|
if (read === null || read === void 0 ? void 0 : read.response.ok) {
|
|
@@ -4154,9 +4188,15 @@ async function updateStoredValue(personId, key, change, attemptsLeft = MAX_ATTEM
|
|
|
4154
4188
|
value,
|
|
4155
4189
|
version
|
|
4156
4190
|
} = await read.response.json();
|
|
4157
|
-
const
|
|
4191
|
+
const {
|
|
4192
|
+
readOnly
|
|
4193
|
+
} = read.token;
|
|
4194
|
+
const next = readOnly ? null : change(value);
|
|
4158
4195
|
if (next === null) {
|
|
4159
|
-
return
|
|
4196
|
+
return {
|
|
4197
|
+
readOnly,
|
|
4198
|
+
value: Array.isArray(value) ? value : []
|
|
4199
|
+
};
|
|
4160
4200
|
} else {
|
|
4161
4201
|
const write = await request(personId, key, {
|
|
4162
4202
|
body: JSON.stringify({
|
|
@@ -4169,7 +4209,10 @@ async function updateStoredValue(personId, key, change, attemptsLeft = MAX_ATTEM
|
|
|
4169
4209
|
method: "PUT"
|
|
4170
4210
|
});
|
|
4171
4211
|
if (write === null || write === void 0 ? void 0 : write.response.ok) {
|
|
4172
|
-
return
|
|
4212
|
+
return {
|
|
4213
|
+
readOnly,
|
|
4214
|
+
value: next
|
|
4215
|
+
};
|
|
4173
4216
|
} else if ((write === null || write === void 0 ? void 0 : write.response.status) === 409 && attemptsLeft > 1) {
|
|
4174
4217
|
return updateStoredValue(personId, key, change, attemptsLeft - 1);
|
|
4175
4218
|
} else {
|
|
@@ -4221,7 +4264,8 @@ async function syncOnce(scope) {
|
|
|
4221
4264
|
return isSameList(mergeEntries(shared, local), shared) ? null : mergeStored(stored, local);
|
|
4222
4265
|
});
|
|
4223
4266
|
if (synced) {
|
|
4224
|
-
|
|
4267
|
+
const shared = entriesFrom(synced.value);
|
|
4268
|
+
writeRecentlyVisited(scope, synced.readOnly ? shared : mergeEntries(shared, readRecentlyVisited(scope)));
|
|
4225
4269
|
}
|
|
4226
4270
|
} catch {
|
|
4227
4271
|
// The service is best-effort; the local copy stands on its own.
|
|
@@ -4252,11 +4296,23 @@ function sync(scope, followUp) {
|
|
|
4252
4296
|
function syncRecentlyVisited(scope) {
|
|
4253
4297
|
return sync(scope, false);
|
|
4254
4298
|
}
|
|
4299
|
+
function record(entry, scope, token) {
|
|
4300
|
+
if (!(token === null || token === void 0 ? void 0 : token.readOnly)) {
|
|
4301
|
+
writeRecentlyVisited(scope, addVisit(readRecentlyVisited(scope), entry));
|
|
4302
|
+
if (token) sync(scope, true);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4255
4305
|
function recordVisit(visit, scope) {
|
|
4256
4306
|
const entry = toEntry(visit, new Date());
|
|
4257
|
-
if (isEntry(entry)) {
|
|
4258
|
-
|
|
4259
|
-
|
|
4307
|
+
if (!isEntry(entry)) {
|
|
4308
|
+
return Promise.resolve();
|
|
4309
|
+
}
|
|
4310
|
+
const token = isUserStoreSyncUnavailable() ? null : currentToken(scope.personId);
|
|
4311
|
+
if (token instanceof Promise) {
|
|
4312
|
+
return token.then(minted => record(entry, scope, minted));
|
|
4313
|
+
} else {
|
|
4314
|
+
record(entry, scope, token);
|
|
4315
|
+
return Promise.resolve();
|
|
4260
4316
|
}
|
|
4261
4317
|
}
|
|
4262
4318
|
function useRecentlyVisited({
|
|
@@ -4937,7 +4993,6 @@ function ProductTabs({
|
|
|
4937
4993
|
role: "tablist"
|
|
4938
4994
|
}, products.map(product => (/*#__PURE__*/React__default.createElement(Tab, {
|
|
4939
4995
|
"aria-controls": `${id}-panel`,
|
|
4940
|
-
"aria-describedby": `${tabId(product.slug)}-description`,
|
|
4941
4996
|
"aria-selected": product === selected,
|
|
4942
4997
|
id: tabId(product.slug),
|
|
4943
4998
|
key: product.slug,
|
|
@@ -4955,11 +5010,6 @@ function ProductTabs({
|
|
|
4955
5010
|
}), showAllNames || product === selected ? product.appName : (/*#__PURE__*/React__default.createElement("span", {
|
|
4956
5011
|
className: styles$k.visuallyHidden
|
|
4957
5012
|
}, product.appName)))))), /*#__PURE__*/React__default.createElement("div", {
|
|
4958
|
-
className: styles$k.visuallyHidden
|
|
4959
|
-
}, products.map(product => (/*#__PURE__*/React__default.createElement("span", {
|
|
4960
|
-
id: `${tabId(product.slug)}-description`,
|
|
4961
|
-
key: product.slug
|
|
4962
|
-
}, "Planning Center ", product.appName)))), /*#__PURE__*/React__default.createElement("div", {
|
|
4963
5013
|
"aria-labelledby": tabId(selected.slug),
|
|
4964
5014
|
className: styles$k.panel,
|
|
4965
5015
|
id: `${id}-panel`,
|
|
@@ -6054,9 +6104,9 @@ function SearchResults({
|
|
|
6054
6104
|
});
|
|
6055
6105
|
case "done":
|
|
6056
6106
|
if (sections.length === 0) {
|
|
6107
|
+
// The panel's result count announces this, so it isn't read twice.
|
|
6057
6108
|
return /*#__PURE__*/React__default.createElement(BlankState$1, {
|
|
6058
6109
|
image: /*#__PURE__*/React__default.createElement(BlankStateNoResults, null),
|
|
6059
|
-
role: "status",
|
|
6060
6110
|
subtitle: "Clear search and try again.",
|
|
6061
6111
|
title: `No results for “${term.trim()}”`
|
|
6062
6112
|
});
|
|
@@ -6110,6 +6160,7 @@ function SearchPanel({
|
|
|
6110
6160
|
highlightedIndex
|
|
6111
6161
|
} = navigation;
|
|
6112
6162
|
const inputRef = React__default.useRef(null);
|
|
6163
|
+
const resultCount = useAnnouncement(hasTerm && search.status === "done" ? `${items.length === 0 ? "No results" : `${items.length} ${items.length === 1 ? "result" : "results"}`} for “${term.trim()}” in ${product.appName}` : null);
|
|
6113
6164
|
const [announceHighlight, setAnnounceHighlight] = React__default.useState(false);
|
|
6114
6165
|
// The tabs keep focus while arrowing through results, but only the focused
|
|
6115
6166
|
// input can point screen readers at the highlight, so from the tabs it's
|
|
@@ -6168,7 +6219,7 @@ function SearchPanel({
|
|
|
6168
6219
|
"aria-live": "polite",
|
|
6169
6220
|
className: styles$k.visuallyHidden,
|
|
6170
6221
|
"data-testid": "result-count"
|
|
6171
|
-
},
|
|
6222
|
+
}, resultCount), mobile ? null : /*#__PURE__*/React__default.createElement(KeyboardHints, {
|
|
6172
6223
|
copied: navigation.copied
|
|
6173
6224
|
}));
|
|
6174
6225
|
}
|