@rspress-theme-anatole/theme-default 0.7.51 → 0.7.53

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.
Files changed (2) hide show
  1. package/dist/bundle.js +128 -69
  2. package/package.json +3 -3
package/dist/bundle.js CHANGED
@@ -6520,34 +6520,54 @@ const ICON_MAP = {
6520
6520
  header: __WEBPACK_EXTERNAL_MODULE__theme_assets_header_54924fa3__["default"],
6521
6521
  content: __WEBPACK_EXTERNAL_MODULE__theme_assets_file_9182f35f__["default"]
6522
6522
  };
6523
- function SuggestItem({ suggestion, closeSearch, isCurrent, setCurrentSuggestionIndex, inCurrentDocIndex, scrollTo, onMouseMove }) {
6523
+ function SuggestItem({ suggestion, query, closeSearch, isCurrent, setCurrentSuggestionIndex, inCurrentDocIndex, scrollTo, onMouseMove }) {
6524
6524
  const HitIcon = ICON_MAP[suggestion.type];
6525
6525
  const link = inCurrentDocIndex && !(0, __WEBPACK_EXTERNAL_MODULE__rspress_runtime_0abd3046__.isProduction)() ? removeDomain(suggestion.link) : suggestion.link;
6526
6526
  const selfRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
6527
6527
  if (isCurrent && selfRef.current?.offsetTop) scrollTo(selfRef.current?.offsetTop, selfRef.current?.offsetHeight);
6528
- const getHighlightedFragments = (rawText, highlights) => {
6528
+ const getHighlightedFragments = (rawText) => {
6529
+ if (!rawText || !query) return [rawText];
6530
+ const terms = [...new Set(
6531
+ query.trim().split(/\s+/).filter(Boolean)
6532
+ .sort((a, b) => b.length - a.length)
6533
+ )];
6534
+ if (terms.length === 0) return [rawText];
6535
+
6536
+ const pattern = new RegExp(
6537
+ `(${terms.map(t => t.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')).join('|')})`,
6538
+ 'giu'
6539
+ );
6540
+
6529
6541
  const fragmentList = [];
6530
6542
  let lastIndex = 0;
6531
- for (const highlightInfo of highlights) {
6532
- const { start, length } = highlightInfo;
6533
- const prefix = rawText.slice(lastIndex, start);
6534
- const queryStr = getSlicedStrByByteLength(rawText, start, length);
6535
- fragmentList.push(prefix);
6536
- fragmentList.push((0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("span", {
6537
- className: Search_index_module.mark,
6538
- children: queryStr
6539
- }, start));
6540
- lastIndex = start + queryStr.length;
6543
+ let match;
6544
+ pattern.lastIndex = 0;
6545
+
6546
+ while ((match = pattern.exec(rawText)) !== null) {
6547
+ if (match.index > lastIndex) {
6548
+ fragmentList.push(rawText.slice(lastIndex, match.index));
6549
+ }
6550
+ fragmentList.push(
6551
+ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(
6552
+ "span",
6553
+ { className: Search_index_module.mark, children: match[0] },
6554
+ match.index
6555
+ )
6556
+ );
6557
+ lastIndex = match.index + match[0].length;
6558
+ }
6559
+
6560
+ if (lastIndex < rawText.length) {
6561
+ fragmentList.push(rawText.slice(lastIndex));
6541
6562
  }
6542
- if (lastIndex < rawText.length) fragmentList.push(rawText.slice(lastIndex));
6543
6563
  return fragmentList;
6544
6564
  };
6565
+
6545
6566
  const renderHeaderMatch = () => {
6546
6567
  if ('header' === suggestion.type || 'title' === suggestion.type) {
6547
- const { header, highlightInfoList } = suggestion;
6548
6568
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
6549
6569
  className: "font-medium",
6550
- children: getHighlightedFragments(header, highlightInfoList)
6570
+ children: getHighlightedFragments(suggestion.header)
6551
6571
  });
6552
6572
  }
6553
6573
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
@@ -6555,19 +6575,20 @@ function SuggestItem({ suggestion, closeSearch, isCurrent, setCurrentSuggestionI
6555
6575
  children: suggestion.header
6556
6576
  });
6557
6577
  };
6578
+
6558
6579
  const renderStatementMatch = () => {
6559
6580
  if ('content' !== suggestion.type) return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {});
6560
- const { statement, highlightInfoList } = suggestion;
6561
6581
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
6562
6582
  className: "text-sm text-gray-light w-full",
6563
- children: getHighlightedFragments(statement, highlightInfoList)
6583
+ children: getHighlightedFragments(suggestion.statement)
6564
6584
  });
6565
6585
  };
6566
6586
  const renderLink = () => {
6567
6587
  const displayLink = removeDomain(suggestion.link);
6588
+ const cleanDisplayLink = displayLink.replace(/([?&])kb_highlight=[^&#]*/,'').replace(/\?$/,'') ;
6568
6589
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("p", {
6569
6590
  className: "text-xs text-gray-400 mt-1 truncate opacity-70",
6570
- children: displayLink
6591
+ children: cleanDisplayLink
6571
6592
  });
6572
6593
  };
6573
6594
  let hitContent = null;
@@ -7023,56 +7044,93 @@ function SearchPanel({ focused, setFocused }) {
7023
7044
  const handleQueryChangedImpl = async (value) => {
7024
7045
  let newQuery = value;
7025
7046
  setQuery(newQuery);
7026
- if (search && 'remote' === search.mode && search.searchLoading) setIsSearching(true);
7027
- if (newQuery) setIsSearching(true);
7028
- if (newQuery) {
7029
- try {
7030
- await ensureSearcherReady();
7031
- } catch (_error) {
7032
- setIsSearching(false);
7033
- return;
7034
- }
7035
- const searchResult = [];
7036
- if ('beforeSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7037
- const key = 'beforeSearch';
7038
- const transformedQuery = await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery);
7039
- if (transformedQuery) newQuery = transformedQuery;
7040
- }
7041
- let defaultSearchResult = await pageSearcherRef.current?.match(newQuery, getScopedSearchLimit(searchScope));
7042
- let filteredDefaultSearchResult = filterResultsByScope(
7043
- defaultSearchResult || DEFAULT_RESULT,
7044
- searchScope,
7045
- base,
7046
- lang
7047
- );
7048
- if (searchScope?.scopeType && !hasSearchResults(filteredDefaultSearchResult)) {
7049
- defaultSearchResult = await pageSearcherRef.current?.match(newQuery, getScopedSearchLimit(searchScope, true));
7050
- }
7051
- if (defaultSearchResult) searchResult.push(...defaultSearchResult);
7052
- if ('onSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7053
- const key = 'onSearch';
7054
- const customSearchResult = await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, searchResult, searchScope);
7055
- if (customSearchResult) searchResult.push(...customSearchResult.map((item) => ({
7056
- renderType: types_RenderType.Custom,
7057
- ...item
7058
- })));
7059
- }
7060
- if ('afterSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7061
- const key = 'afterSearch';
7062
- await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, searchResult);
7063
- }
7064
- const currQuery = searchInputRef.current?.value;
7065
- if (currQuery === newQuery) {
7066
- const filteredResult = filterResultsByScope(
7067
- searchResult || DEFAULT_RESULT,
7068
- searchScope,
7069
- base,
7070
- lang
7071
- );
7072
- setSearchResult(filteredResult);
7073
- setIsSearching(false);
7074
- }
7047
+
7048
+ if (!newQuery) {
7049
+ setIsSearching(false);
7050
+ return;
7075
7051
  }
7052
+
7053
+ setIsSearching(true);
7054
+
7055
+ // Kick off local searcher init in background (non-blocking)
7056
+ const searcherPromise = ensureSearcherReady().catch(() => null);
7057
+
7058
+ // === TYPESENSE FIRST (not wait local searcher) ===
7059
+ const typesenseResult = [...DEFAULT_RESULT];
7060
+
7061
+ if ('beforeSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7062
+ const key = 'beforeSearch';
7063
+ const transformedQuery = await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery);
7064
+ if (transformedQuery) newQuery = transformedQuery;
7065
+ }
7066
+
7067
+ if ('onSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7068
+ const key = 'onSearch';
7069
+ await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, typesenseResult, searchScope);
7070
+ }
7071
+
7072
+ if ('afterSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7073
+ const key = 'afterSearch';
7074
+ await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, typesenseResult);
7075
+ }
7076
+
7077
+ // If the query has changed while waiting → skip
7078
+ if (searchInputRef.current?.value !== value) return;
7079
+
7080
+ const typesenseHasResults = hasSearchResults(typesenseResult);
7081
+
7082
+ if (typesenseHasResults) {
7083
+ // Typesense has results → display immediately, do not wait for local
7084
+ const filtered = filterResultsByScope(typesenseResult, searchScope, base, lang);
7085
+ setSearchResult(filtered);
7086
+ setIsSearching(false);
7087
+ // Local searcher still warms up in the background for the next time
7088
+ return;
7089
+ }
7090
+
7091
+ // === FALLBACK: wait for local FlexSearch searcher ===
7092
+ const searcher = await searcherPromise;
7093
+
7094
+ if (searchInputRef.current?.value !== value) return;
7095
+
7096
+ if (!searcher) {
7097
+ // Local searcher also failed → show empty
7098
+ setSearchResult(DEFAULT_RESULT);
7099
+ setIsSearching(false);
7100
+ return;
7101
+ }
7102
+
7103
+ const localResult = [];
7104
+ let defaultSearchResult = await searcher.match(newQuery, getScopedSearchLimit(searchScope));
7105
+ let filteredDefaultSearchResult = filterResultsByScope(
7106
+ defaultSearchResult || DEFAULT_RESULT,
7107
+ searchScope,
7108
+ base,
7109
+ lang
7110
+ );
7111
+
7112
+ if (searchScope?.scopeType && !hasSearchResults(filteredDefaultSearchResult)) {
7113
+ defaultSearchResult = await searcher.match(newQuery, getScopedSearchLimit(searchScope, true));
7114
+ }
7115
+
7116
+ if (defaultSearchResult) localResult.push(...defaultSearchResult);
7117
+
7118
+ // Re-run onSearch/afterSearch với local result
7119
+ if ('onSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7120
+ const key = 'onSearch';
7121
+ await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, localResult, searchScope);
7122
+ }
7123
+
7124
+ if ('afterSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7125
+ const key = 'afterSearch';
7126
+ await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, localResult);
7127
+ }
7128
+
7129
+ if (searchInputRef.current?.value !== value) return;
7130
+
7131
+ const filtered = filterResultsByScope(localResult || DEFAULT_RESULT, searchScope, base, lang);
7132
+ setSearchResult(filtered);
7133
+ setIsSearching(false);
7076
7134
  };
7077
7135
  const handleQueryChange = useDebounce(handleQueryChangedImpl);
7078
7136
  const normalizeSuggestions = (suggestions) => suggestions.reduce((groups, item) => {
@@ -7145,6 +7203,7 @@ function SearchPanel({ focused, setFocused }) {
7145
7203
  const suggestionIndex = accumulateIndex;
7146
7204
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(SuggestItem, {
7147
7205
  suggestion: suggestion,
7206
+ query: query,
7148
7207
  isCurrent: suggestionIndex === currentSuggestionIndex,
7149
7208
  setCurrentSuggestionIndex: (event) => {
7150
7209
  if (mousePositionRef.current.pageX === event.pageX && mousePositionRef.current.pageY === event.pageY) return;
@@ -7215,8 +7274,8 @@ function SearchPanel({ focused, setFocused }) {
7215
7274
  "aria-label": "SearchPanelInput",
7216
7275
  autoComplete: "off",
7217
7276
  autoFocus: true,
7218
- // onChange: (e) => handleQueryChange(e.target.value)
7219
- onKeyUp: (e) => handleQueryChange(e.target.value)
7277
+ onChange: (e) => handleQueryChange(e.target.value)
7278
+ // onKeyUp: (e) => handleQueryChange(e.target.value)
7220
7279
  }),
7221
7280
  (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("label", {
7222
7281
  children: (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(SvgWrapper, {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rspress-theme-anatole/theme-default",
3
3
  "author": "Anatole Tong",
4
- "version": "0.7.51",
4
+ "version": "0.7.53",
5
5
  "license": "MIT",
6
6
  "sideEffects": [
7
7
  "*.css",
@@ -21,8 +21,8 @@
21
21
  "types": "./dist/bundle.d.ts",
22
22
  "dependencies": {
23
23
  "@mdx-js/react": "2.3.0",
24
- "@rspress-theme-anatole/rspress-plugin-mermaid": "0.7.51",
25
- "@rspress-theme-anatole/shared": "0.7.51",
24
+ "@rspress-theme-anatole/rspress-plugin-mermaid": "0.7.53",
25
+ "@rspress-theme-anatole/shared": "0.7.53",
26
26
  "@rspress/runtime": "1.43.8",
27
27
  "body-scroll-lock": "4.0.0-beta.0",
28
28
  "copy-to-clipboard": "^3.3.3",