@paubox/ui 2.0.0 → 3.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 CHANGED
@@ -30939,12 +30939,12 @@ function _templateObject9() {
30939
30939
  }
30940
30940
  function _templateObject10() {
30941
30941
  var data = _tagged_template_literal$5([
30942
- "\n border-top: 1px solid ",
30943
- ";\n ",
30942
+ "\n ",
30944
30943
  "\n color: ",
30945
- ";\n html.dark & {\n border-top-color: ",
30946
- ";\n color: ",
30947
- ";\n }\n"
30944
+ ";\n html.dark & {\n color: ",
30945
+ ";\n }\n /* Divider above the footer only when there are suggestion rows above\n it. When the footer is the only item in the dropdown (fetchSuggestions\n false, no candidates, non-empty query), the static border-top would\n bleed past the rounded corners of the dropdown container as a stray\n line at the top of the menu. */\n &:not(:first-child) {\n border-top: 1px solid ",
30946
+ ";\n html.dark & {\n border-top-color: ",
30947
+ ";\n }\n }\n"
30948
30948
  ]);
30949
30949
  _templateObject10 = function _templateObject() {
30950
30950
  return data;
@@ -30992,7 +30992,7 @@ var DropdownRow = styled.button(_templateObject6$1(), spacing(1), spacing(1), sp
30992
30992
  var RowIcon = styled.span(_templateObject7$1(), neutral500$1);
30993
30993
  var RowText = styled.span(_templateObject8$1());
30994
30994
  var RowMeta = styled.span(_templateObject9(), $paragraph300Regular, neutral600$1, neutral300$1);
30995
- var FooterRow = styled(DropdownRow)(_templateObject10(), neutral200$1, $paragraph200Regular, neutral700$1, surfaceRaised, neutral300$1);
30995
+ var FooterRow = styled(DropdownRow)(_templateObject10(), $paragraph200Regular, neutral700$1, neutral300$1, neutral200$1, surfaceRaised);
30996
30996
  var PressEnter = styled.span(_templateObject11(), $paragraph300Regular, neutral500$1);
30997
30997
  var DeleteHandle = styled.span(_templateObject12());
30998
30998
  // ─── Inline icons (kept local to avoid bloating @icons) ─────────────────────
@@ -31073,7 +31073,7 @@ var EMPTY_CANDIDATES = [];
31073
31073
  var SearchOmnibox = function(param) {
31074
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() {
31075
31075
  return '';
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;
31076
+ } : _param_getAuthToken, _param_fetchSuggestions = param.fetchSuggestions, fetchSuggestions = _param_fetchSuggestions === void 0 ? true : _param_fetchSuggestions, _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;
31077
31077
  var _useState = _sliced_to_array$4(useState(initialQuery), 2), query = _useState[0], setQuery = _useState[1];
31078
31078
  var _useState1 = _sliced_to_array$4(useState(initialQuery), 2), debouncedQuery = _useState1[0], setDebouncedQuery = _useState1[1];
31079
31079
  var _useState2 = _sliced_to_array$4(useState(false), 2), focused = _useState2[0], setFocused = _useState2[1];
@@ -31217,7 +31217,7 @@ var SearchOmnibox = function(param) {
31217
31217
  ]);
31218
31218
  // Remote autocomplete fetch
31219
31219
  useEffect(function() {
31220
- if (mode !== 'remote' || !debouncedQuery) {
31220
+ if (!fetchSuggestions || !debouncedQuery) {
31221
31221
  setResults([]);
31222
31222
  return;
31223
31223
  }
@@ -31272,7 +31272,7 @@ var SearchOmnibox = function(param) {
31272
31272
  }, [
31273
31273
  debouncedQuery,
31274
31274
  bar,
31275
- mode,
31275
+ fetchSuggestions,
31276
31276
  apiFetch
31277
31277
  ]);
31278
31278
  // Tracks the last query value we've notified the parent about via the
@@ -31321,7 +31321,7 @@ var SearchOmnibox = function(param) {
31321
31321
  // re-render even when the previous state was also `[]`, because React
31322
31322
  // bails out only on Object.is equality.
31323
31323
  useEffect(function() {
31324
- if (mode !== 'local') return;
31324
+ if (fetchSuggestions) return;
31325
31325
  var q = debouncedQuery.trim().toLowerCase();
31326
31326
  if (!q) {
31327
31327
  setLocalMatches(function(prev) {
@@ -31339,13 +31339,13 @@ var SearchOmnibox = function(param) {
31339
31339
  }
31340
31340
  }, [
31341
31341
  debouncedQuery,
31342
- mode,
31342
+ fetchSuggestions,
31343
31343
  localCandidates
31344
31344
  ]);
31345
31345
  // Live-change notification: fires on debounced typing in both modes.
31346
31346
  // Pages that want to live-filter their table (or fetch as the user
31347
31347
  // types) pass `onLiveChange`; pages that only care about explicit
31348
- // commits leave it out. Independent of `mode`.
31348
+ // commits leave it out. Independent of `fetchSuggestions`.
31349
31349
  useEffect(function() {
31350
31350
  notifyLiveChange(debouncedQuery);
31351
31351
  }, [
@@ -31482,20 +31482,24 @@ var SearchOmnibox = function(param) {
31482
31482
  });
31483
31483
  }
31484
31484
  if (dropdownState === 'results') {
31485
- if (mode === 'local') {
31486
- return localMatches.map(function(s) {
31487
- return {
31488
- kind: 'local',
31489
- key: s
31490
- };
31491
- });
31492
- }
31493
- return _to_consumable_array$2(results.slice(0, 5).map(function(r) {
31485
+ // Per PRD §1.5 every typing-state dropdown ends in the
31486
+ // "All search results for X — Press ENTER" footer row, regardless
31487
+ // of how many (or whether any) suggestion rows precede it. Bars
31488
+ // with fetchSuggestions=false and no localCandidates therefore show
31489
+ // only the footer when the user has typed text, which is the only
31490
+ // mobile-friendly affordance for committing the search.
31491
+ var suggestionRows = !fetchSuggestions ? localMatches.map(function(s) {
31492
+ return {
31493
+ kind: 'local',
31494
+ key: s
31495
+ };
31496
+ }) : results.slice(0, 5).map(function(r) {
31494
31497
  return {
31495
31498
  kind: 'result',
31496
31499
  key: r.message_id
31497
31500
  };
31498
- })).concat([
31501
+ });
31502
+ return _to_consumable_array$2(suggestionRows).concat([
31499
31503
  {
31500
31504
  kind: 'footer',
31501
31505
  key: '__footer__'
@@ -31508,7 +31512,7 @@ var SearchOmnibox = function(param) {
31508
31512
  recent,
31509
31513
  results,
31510
31514
  localMatches,
31511
- mode
31515
+ fetchSuggestions
31512
31516
  ]);
31513
31517
  // Reset highlight whenever the item set changes — including same-length
31514
31518
  // swaps (e.g. one page of 5 results replaced by a different 5 + footer).
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@paubox/ui",
3
3
  "author": "Paubox, Inc.",
4
4
  "description": "Paubox Component Library",
5
- "version": "2.0.0",
5
+ "version": "3.0.0",
6
6
  "type": "module",
7
7
  "private": false,
8
8
  "publishConfig": {
@@ -25,19 +25,38 @@ export interface SearchOmniboxProps {
25
25
  placeholder?: string;
26
26
  /**
27
27
  * Base URL of the pb_search service (no trailing slash).
28
- * Required when `mode='remote'` or `withHistory !== false`. Ignored otherwise.
28
+ * Required when `fetchSuggestions !== false` or `withHistory !== false`. Ignored otherwise.
29
29
  */
30
30
  pbSearchBaseUrl?: string;
31
31
  /**
32
32
  * Returns the current Bearer token to send to pb_search.
33
- * Required when `mode='remote'` or `withHistory !== false`. Ignored otherwise.
33
+ * Required when `fetchSuggestions !== false` or `withHistory !== false`. Ignored otherwise.
34
34
  */
35
35
  getAuthToken?: () => Promise<string> | string;
36
36
  /**
37
- * 'remote' (default for mail bars) autocomplete dropdown fetches results from pb_search.
38
- * 'local' autocomplete dropdown filters `localCandidates` client-side; recent searches still come from Redis (unless `withHistory` is false).
37
+ * Whether to fetch suggestion rows from pb_search as the user types.
38
+ * Defaults to `true`.
39
+ *
40
+ * - `true` — fires `GET /search/autocomplete` against pb_search on
41
+ * debounced typing and renders the top-5 hits above the footer row.
42
+ * Use on bars whose data is indexed in pb_search (every mail bar
43
+ * today).
44
+ * - `false` — never fetches `/search/autocomplete`. If `localCandidates`
45
+ * is passed, those are filtered client-side and shown as suggestions;
46
+ * otherwise only the footer row appears. Use on bars whose data
47
+ * isn't indexed in pb_search (rulesets, relays, settings, etc.).
48
+ *
49
+ * Independent of:
50
+ * - `withHistory`, which gates recent-search behavior (Redis), and
51
+ * - the Tab-accept ghost text, which is sourced from recent search
52
+ * history and is always on when `withHistory` is enabled.
53
+ *
54
+ * Named `fetchSuggestions` rather than `autocomplete` to avoid
55
+ * collision with the Tab-accept ghost-text autocomplete feature —
56
+ * both could reasonably be called "autocomplete" but they're
57
+ * independent.
39
58
  */
40
- mode?: 'remote' | 'local';
59
+ fetchSuggestions?: boolean;
41
60
  /**
42
61
  * Whether to use Redis-backed recent-search history. Defaults to `true`.
43
62
  *
@@ -47,12 +66,13 @@ export interface SearchOmniboxProps {
47
66
  * - Ghost-text tab autocomplete is disabled (it's sourced from recent searches)
48
67
  *
49
68
  * Set this to `false` for config / list pages that don't need per-user history.
50
- * Pairs naturally with `mode='local'` to keep the component fully decoupled
51
- * from pb_search.
69
+ * Pairs naturally with `fetchSuggestions={false}` to keep the component
70
+ * fully decoupled from pb_search.
52
71
  */
53
72
  withHistory?: boolean;
54
73
  /** 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). */
74
+ * (only fires when `fetchSuggestions !== false`; the dropdown is a
75
+ * pb_search-fed top-5 list). */
56
76
  onResultClick?: (result: SearchOmniboxResult) => void;
57
77
  /** Called when the user **commits** a search — explicit action.
58
78
  * Triggers: Enter on the input (no row highlighted), click on the
@@ -65,11 +85,14 @@ export interface SearchOmniboxProps {
65
85
  * Fires in both `local` and `remote` modes. Optional — pages that
66
86
  * only care about explicit commits should just not pass this. */
67
87
  onLiveChange?: (query: string) => void;
68
- /** Local mode only: candidate strings to filter against (e.g. ruleset names, usernames). */
88
+ /** Optional candidate strings to filter client-side when
89
+ * `fetchSuggestions={false}` (e.g. ruleset names, usernames). Ignored
90
+ * when `fetchSuggestions` is truthy — pb_search drives the suggestions
91
+ * instead. */
69
92
  localCandidates?: string[];
70
93
  /** Test id prefix; defaults to `search-omnibox`. */
71
94
  testId?: string;
72
95
  /** Optional initial query (e.g. when restoring from URL state). */
73
96
  initialQuery?: string;
74
97
  }
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;
98
+ export declare const SearchOmnibox: ({ bar, placeholder, pbSearchBaseUrl, getAuthToken, fetchSuggestions, withHistory, onResultClick, onCommit, onLiveChange, localCandidates, testId, initialQuery, }: SearchOmniboxProps) => import("@emotion/react/jsx-runtime").JSX.Element;