@paubox/ui 1.19.0 → 2.0.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/index.esm.js +80 -35
- package/package.json +1 -1
- package/src/lib/SearchOmnibox/SearchOmnibox.d.ts +14 -6
package/index.esm.js
CHANGED
|
@@ -31063,11 +31063,17 @@ var formatDate = function(iso) {
|
|
|
31063
31063
|
}
|
|
31064
31064
|
return null;
|
|
31065
31065
|
};
|
|
31066
|
+
// Stable empty-array reference for the `localCandidates` default. Using
|
|
31067
|
+
// `localCandidates = []` would allocate a fresh array on every render,
|
|
31068
|
+
// which churns the local-autocomplete effect's dep array and (combined
|
|
31069
|
+
// with non-memoized callbacks from the parent) drove an infinite render
|
|
31070
|
+
// loop on pages that don't pass `localCandidates`.
|
|
31071
|
+
var EMPTY_CANDIDATES = [];
|
|
31066
31072
|
// ─── Component ──────────────────────────────────────────────────────────────
|
|
31067
31073
|
var SearchOmnibox = function(param) {
|
|
31068
31074
|
var bar = param.bar, _param_placeholder = param.placeholder, placeholder = _param_placeholder === void 0 ? 'Search' : _param_placeholder, _param_pbSearchBaseUrl = param.pbSearchBaseUrl, pbSearchBaseUrl = _param_pbSearchBaseUrl === void 0 ? '' : _param_pbSearchBaseUrl, _param_getAuthToken = param.getAuthToken, getAuthToken = _param_getAuthToken === void 0 ? function() {
|
|
31069
31075
|
return '';
|
|
31070
|
-
} : _param_getAuthToken, _param_mode = param.mode, mode = _param_mode === void 0 ? 'remote' : _param_mode, _param_withHistory = param.withHistory, withHistory = _param_withHistory === void 0 ? true : _param_withHistory, onResultClick = param.onResultClick,
|
|
31076
|
+
} : _param_getAuthToken, _param_mode = param.mode, mode = _param_mode === void 0 ? 'remote' : _param_mode, _param_withHistory = param.withHistory, withHistory = _param_withHistory === void 0 ? true : _param_withHistory, onResultClick = param.onResultClick, onCommit = param.onCommit, onLiveChange = param.onLiveChange, _param_localCandidates = param.localCandidates, localCandidates = _param_localCandidates === void 0 ? EMPTY_CANDIDATES : _param_localCandidates, _param_testId = param.testId, testId = _param_testId === void 0 ? 'search-omnibox' : _param_testId, _param_initialQuery = param.initialQuery, initialQuery = _param_initialQuery === void 0 ? '' : _param_initialQuery;
|
|
31071
31077
|
var _useState = _sliced_to_array$4(useState(initialQuery), 2), query = _useState[0], setQuery = _useState[1];
|
|
31072
31078
|
var _useState1 = _sliced_to_array$4(useState(initialQuery), 2), debouncedQuery = _useState1[0], setDebouncedQuery = _useState1[1];
|
|
31073
31079
|
var _useState2 = _sliced_to_array$4(useState(false), 2), focused = _useState2[0], setFocused = _useState2[1];
|
|
@@ -31269,43 +31275,82 @@ var SearchOmnibox = function(param) {
|
|
|
31269
31275
|
mode,
|
|
31270
31276
|
apiFetch
|
|
31271
31277
|
]);
|
|
31272
|
-
// Tracks the last query value we've notified the
|
|
31273
|
-
//
|
|
31274
|
-
// echoed ~200ms later
|
|
31275
|
-
|
|
31276
|
-
|
|
31277
|
-
//
|
|
31278
|
-
//
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31282
|
-
|
|
31283
|
-
|
|
31284
|
-
|
|
31285
|
-
|
|
31286
|
-
}
|
|
31278
|
+
// Tracks the last query value we've notified the parent about via the
|
|
31279
|
+
// debounced live-change path, so a synchronous commit (Enter / footer /
|
|
31280
|
+
// recent / local) isn't echoed ~200ms later when the debounced effect
|
|
31281
|
+
// fires for the same query.
|
|
31282
|
+
var lastLiveChangeRef = useRef(undefined);
|
|
31283
|
+
// Hold the parent callbacks in refs so the firing functions stay stable
|
|
31284
|
+
// across renders. Otherwise any caller passing inline arrow functions
|
|
31285
|
+
// (the common case) would re-allocate the firing closures every render,
|
|
31286
|
+
// churning effect dependencies and triggering loops. Refs decouple the
|
|
31287
|
+
// parent's reference identity from our effect deps.
|
|
31288
|
+
var onCommitRef = useRef(onCommit);
|
|
31289
|
+
var onLiveChangeRef = useRef(onLiveChange);
|
|
31290
|
+
useEffect(function() {
|
|
31291
|
+
onCommitRef.current = onCommit;
|
|
31287
31292
|
}, [
|
|
31288
|
-
|
|
31289
|
-
onLocalQueryChange,
|
|
31290
|
-
onSubmitFullSearch
|
|
31293
|
+
onCommit
|
|
31291
31294
|
]);
|
|
31292
|
-
|
|
31295
|
+
useEffect(function() {
|
|
31296
|
+
onLiveChangeRef.current = onLiveChange;
|
|
31297
|
+
}, [
|
|
31298
|
+
onLiveChange
|
|
31299
|
+
]);
|
|
31300
|
+
// Fire when the user has explicitly committed (Enter, footer click,
|
|
31301
|
+
// recent-row select, local-row select). Always invokes onCommit, in both
|
|
31302
|
+
// modes. Also seeds `lastLiveChangeRef` so the imminent debounced
|
|
31303
|
+
// `notifyLiveChange` doesn't re-fire for the same query.
|
|
31304
|
+
var fireCommit = useCallback(function(q) {
|
|
31305
|
+
var _onCommitRef_current;
|
|
31306
|
+
lastLiveChangeRef.current = q;
|
|
31307
|
+
(_onCommitRef_current = onCommitRef.current) === null || _onCommitRef_current === void 0 ? void 0 : _onCommitRef_current.call(onCommitRef, q);
|
|
31308
|
+
}, []);
|
|
31309
|
+
// Fire when the debounced query changes — every keystroke (200ms after
|
|
31310
|
+
// the last). Deduped so repeated identical values don't fire twice.
|
|
31311
|
+
// Invokes onLiveChange in both modes.
|
|
31312
|
+
var notifyLiveChange = useCallback(function(q) {
|
|
31313
|
+
var _onLiveChangeRef_current;
|
|
31314
|
+
if (lastLiveChangeRef.current === q) return;
|
|
31315
|
+
lastLiveChangeRef.current = q;
|
|
31316
|
+
(_onLiveChangeRef_current = onLiveChangeRef.current) === null || _onLiveChangeRef_current === void 0 ? void 0 : _onLiveChangeRef_current.call(onLiveChangeRef, q);
|
|
31317
|
+
}, []);
|
|
31318
|
+
// Local autocomplete: filter candidates client-side.
|
|
31319
|
+
// The `setLocalMatches` calls are guarded against no-op writes — calling
|
|
31320
|
+
// setState with a fresh `[]` literal every render is enough to cause a
|
|
31321
|
+
// re-render even when the previous state was also `[]`, because React
|
|
31322
|
+
// bails out only on Object.is equality.
|
|
31293
31323
|
useEffect(function() {
|
|
31294
31324
|
if (mode !== 'local') return;
|
|
31295
31325
|
var q = debouncedQuery.trim().toLowerCase();
|
|
31296
31326
|
if (!q) {
|
|
31297
|
-
setLocalMatches(
|
|
31327
|
+
setLocalMatches(function(prev) {
|
|
31328
|
+
return prev.length === 0 ? prev : [];
|
|
31329
|
+
});
|
|
31298
31330
|
} else {
|
|
31299
|
-
|
|
31331
|
+
var next = localCandidates.filter(function(c) {
|
|
31300
31332
|
return c.toLowerCase().includes(q);
|
|
31301
|
-
}).slice(0, 5)
|
|
31333
|
+
}).slice(0, 5);
|
|
31334
|
+
setLocalMatches(function(prev) {
|
|
31335
|
+
return prev.length === next.length && prev.every(function(v, i) {
|
|
31336
|
+
return v === next[i];
|
|
31337
|
+
}) ? prev : next;
|
|
31338
|
+
});
|
|
31302
31339
|
}
|
|
31303
|
-
notifyParent(debouncedQuery);
|
|
31304
31340
|
}, [
|
|
31305
31341
|
debouncedQuery,
|
|
31306
31342
|
mode,
|
|
31307
|
-
localCandidates
|
|
31308
|
-
|
|
31343
|
+
localCandidates
|
|
31344
|
+
]);
|
|
31345
|
+
// Live-change notification: fires on debounced typing in both modes.
|
|
31346
|
+
// Pages that want to live-filter their table (or fetch as the user
|
|
31347
|
+
// types) pass `onLiveChange`; pages that only care about explicit
|
|
31348
|
+
// commits leave it out. Independent of `mode`.
|
|
31349
|
+
useEffect(function() {
|
|
31350
|
+
notifyLiveChange(debouncedQuery);
|
|
31351
|
+
}, [
|
|
31352
|
+
debouncedQuery,
|
|
31353
|
+
notifyLiveChange
|
|
31309
31354
|
]);
|
|
31310
31355
|
// Note: click-outside dismissal is handled by Popper's built-in useClickOutside
|
|
31311
31356
|
// (it watches the anchorRef + its own container ref) via the onClose callback.
|
|
@@ -31504,7 +31549,7 @@ var SearchOmnibox = function(param) {
|
|
|
31504
31549
|
// empty input is a legitimate "clear filter, show everything" action.
|
|
31505
31550
|
// recordSearch itself guards against recording empty strings, so we
|
|
31506
31551
|
// don't pollute history.
|
|
31507
|
-
|
|
31552
|
+
fireCommit(q);
|
|
31508
31553
|
void recordSearch(q);
|
|
31509
31554
|
setFocused(false);
|
|
31510
31555
|
return [
|
|
@@ -31516,14 +31561,14 @@ var SearchOmnibox = function(param) {
|
|
|
31516
31561
|
return _ref.apply(this, arguments);
|
|
31517
31562
|
};
|
|
31518
31563
|
}(), [
|
|
31519
|
-
|
|
31564
|
+
fireCommit,
|
|
31520
31565
|
recordSearch
|
|
31521
31566
|
]);
|
|
31522
31567
|
var selectRecent = useCallback(function() {
|
|
31523
31568
|
var _ref = _async_to_generator(function(q) {
|
|
31524
31569
|
return _ts_generator(this, function(_state) {
|
|
31525
31570
|
setQuery(q);
|
|
31526
|
-
|
|
31571
|
+
fireCommit(q);
|
|
31527
31572
|
void recordSearch(q);
|
|
31528
31573
|
setFocused(false);
|
|
31529
31574
|
return [
|
|
@@ -31535,7 +31580,7 @@ var SearchOmnibox = function(param) {
|
|
|
31535
31580
|
return _ref.apply(this, arguments);
|
|
31536
31581
|
};
|
|
31537
31582
|
}(), [
|
|
31538
|
-
|
|
31583
|
+
fireCommit,
|
|
31539
31584
|
recordSearch
|
|
31540
31585
|
]);
|
|
31541
31586
|
var selectResult = useCallback(function(result) {
|
|
@@ -31549,11 +31594,11 @@ var SearchOmnibox = function(param) {
|
|
|
31549
31594
|
]);
|
|
31550
31595
|
var selectLocal = useCallback(function(s) {
|
|
31551
31596
|
setQuery(s);
|
|
31552
|
-
|
|
31597
|
+
fireCommit(s);
|
|
31553
31598
|
void recordSearch(s);
|
|
31554
31599
|
setFocused(false);
|
|
31555
31600
|
}, [
|
|
31556
|
-
|
|
31601
|
+
fireCommit,
|
|
31557
31602
|
recordSearch
|
|
31558
31603
|
]);
|
|
31559
31604
|
var handleKeyDown = function(e) {
|
|
@@ -31688,10 +31733,10 @@ var SearchOmnibox = function(param) {
|
|
|
31688
31733
|
onClick: function() {
|
|
31689
31734
|
var _inputRef_current;
|
|
31690
31735
|
setQuery('');
|
|
31691
|
-
// Clearing the input is a "remove the filter" action
|
|
31692
|
-
//
|
|
31736
|
+
// Clearing the input is a "remove the filter" action — fire
|
|
31737
|
+
// commit so the page-level data resets to its unfiltered
|
|
31693
31738
|
// state, the same way pressing Enter on an empty input would.
|
|
31694
|
-
|
|
31739
|
+
fireCommit('');
|
|
31695
31740
|
// After a prior commit the dropdown is closed (`focused=false`)
|
|
31696
31741
|
// even though the input has DOM focus. Re-engage explicitly so
|
|
31697
31742
|
// the recent-searches view reappears for the now-empty input.
|
package/package.json
CHANGED
|
@@ -51,17 +51,25 @@ export interface SearchOmniboxProps {
|
|
|
51
51
|
* from pb_search.
|
|
52
52
|
*/
|
|
53
53
|
withHistory?: boolean;
|
|
54
|
-
/**
|
|
54
|
+
/** Called when the user clicks a result row in the live-results dropdown
|
|
55
|
+
* (remote mode only; the dropdown is a pb_search-fed top-5 list). */
|
|
55
56
|
onResultClick?: (result: SearchOmniboxResult) => void;
|
|
56
|
-
/** Called when
|
|
57
|
-
|
|
57
|
+
/** Called when the user **commits** a search — explicit action.
|
|
58
|
+
* Triggers: Enter on the input (no row highlighted), click on the
|
|
59
|
+
* "All search results for X" footer row, Enter or click on a
|
|
60
|
+
* recent-search row, Enter or click on a local-match row.
|
|
61
|
+
* Fires in both `local` and `remote` modes. */
|
|
62
|
+
onCommit?: (query: string) => void;
|
|
63
|
+
/** Called when the user's typed query changes, debounced (~200ms).
|
|
64
|
+
* Lets pages live-filter their table or fetch as the user types.
|
|
65
|
+
* Fires in both `local` and `remote` modes. Optional — pages that
|
|
66
|
+
* only care about explicit commits should just not pass this. */
|
|
67
|
+
onLiveChange?: (query: string) => void;
|
|
58
68
|
/** Local mode only: candidate strings to filter against (e.g. ruleset names, usernames). */
|
|
59
69
|
localCandidates?: string[];
|
|
60
|
-
/** Local mode: fires when the (debounced) query changes; let the page filter its own table. */
|
|
61
|
-
onLocalQueryChange?: (query: string) => void;
|
|
62
70
|
/** Test id prefix; defaults to `search-omnibox`. */
|
|
63
71
|
testId?: string;
|
|
64
72
|
/** Optional initial query (e.g. when restoring from URL state). */
|
|
65
73
|
initialQuery?: string;
|
|
66
74
|
}
|
|
67
|
-
export declare const SearchOmnibox: ({ bar, placeholder, pbSearchBaseUrl, getAuthToken, mode, withHistory, onResultClick,
|
|
75
|
+
export declare const SearchOmnibox: ({ bar, placeholder, pbSearchBaseUrl, getAuthToken, mode, withHistory, onResultClick, onCommit, onLiveChange, localCandidates, testId, initialQuery, }: SearchOmniboxProps) => import("@emotion/react/jsx-runtime").JSX.Element;
|