dumi 2.0.3 → 2.0.5

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 (32) hide show
  1. package/dist/client/theme-api/AtomRenderer.d.ts +8 -0
  2. package/dist/client/theme-api/AtomRenderer.js +99 -0
  3. package/dist/client/theme-api/context.d.ts +1 -0
  4. package/dist/client/theme-api/context.js +1 -0
  5. package/dist/client/theme-api/index.d.ts +1 -0
  6. package/dist/client/theme-api/index.js +1 -0
  7. package/dist/features/compile/index.js +1 -1
  8. package/dist/features/derivative.js +4 -1
  9. package/dist/features/tabs.js +3 -3
  10. package/dist/features/theme/index.js +26 -6
  11. package/dist/loaders/markdown/index.js +1 -0
  12. package/dist/loaders/markdown/transformer/rehypeDemo.js +3 -2
  13. package/dist/loaders/markdown/transformer/remarkContainer.d.ts +1 -1
  14. package/dist/loaders/markdown/transformer/remarkContainer.js +4 -0
  15. package/dist/loaders/pre-raw/index.d.ts +4 -0
  16. package/dist/loaders/pre-raw/index.js +33 -0
  17. package/dist/service/service.d.ts +1 -1
  18. package/dist/service/service.js +2 -1
  19. package/package.json +2 -1
  20. package/theme-default/builtins/SourceCode/index.d.ts +1 -1
  21. package/theme-default/builtins/SourceCode/index.js +1 -1
  22. package/theme-default/slots/Content/index.less +4 -0
  23. package/theme-default/slots/RtlSwitch/index.less +6 -0
  24. package/theme-default/slots/SearchBar/Input.d.ts +6 -0
  25. package/theme-default/slots/SearchBar/Input.js +40 -0
  26. package/theme-default/slots/SearchBar/Mask.d.ts +9 -0
  27. package/theme-default/slots/SearchBar/Mask.js +21 -0
  28. package/theme-default/slots/SearchBar/index.d.ts +2 -0
  29. package/theme-default/slots/SearchBar/index.js +105 -35
  30. package/theme-default/slots/SearchBar/index.less +87 -2
  31. package/theme-default/slots/SearchResult/index.d.ts +1 -0
  32. package/theme-default/slots/SearchResult/index.js +11 -3
@@ -0,0 +1,8 @@
1
+ import { AtomAsset, ExamplePresetAsset } from 'dumi-assets-types';
2
+ import { type FC } from 'react';
3
+ interface IAtomRendererProps {
4
+ type: AtomAsset['type'];
5
+ value: ExamplePresetAsset['value'];
6
+ }
7
+ export declare const AtomRenderer: FC<IAtomRendererProps>;
8
+ export {};
@@ -0,0 +1,99 @@
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
+
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+
5
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+
7
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
8
+
9
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
10
+
11
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
12
+
13
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
14
+
15
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
16
+
17
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
18
+
19
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
20
+
21
+ import { useSiteData } from 'dumi';
22
+ import React from 'react';
23
+
24
+ function builtInProcessor(entity, entryExports) {
25
+ var mod;
26
+
27
+ switch (entity.$$__type) {
28
+ case 'function':
29
+ // eslint-disable-next-line no-eval
30
+ return eval(entity.$$__body.sourceCode);
31
+
32
+ case 'element':
33
+ // find child component from entry exports
34
+ mod = entity.$$__body.componentName.split('.').reduce(function (col, cur) {
35
+ return col[cur];
36
+ }, entryExports); // fallback to HTML tag
37
+
38
+ if (mod === undefined) return entity.$$__body.componentName; // support pure render for antd components
39
+
40
+ return '_InternalPanelDoNotUseOrYouWillBeFired' in mod ? mod._InternalPanelDoNotUseOrYouWillBeFired : mod;
41
+ }
42
+ }
43
+
44
+ function deepReplace(value, entityProcessor) {
45
+ // transform array props
46
+ if (Array.isArray(value)) {
47
+ return value.map(function (e) {
48
+ return deepReplace(e, entityProcessor);
49
+ });
50
+ } // transform element props
51
+
52
+
53
+ if (_typeof(value) === 'object' && (value === null || value === void 0 ? void 0 : value.$$__type) === 'element') {
54
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
55
+ return translatePresetToReact(value.$$__body, entityProcessor);
56
+ } // transform pure object props
57
+
58
+
59
+ if (_typeof(value) === 'object' && Object.prototype.toString.call(value) === '[object Object]') {
60
+ return Object.entries(value).reduce(function (col, _ref) {
61
+ var _ref2 = _slicedToArray(_ref, 2),
62
+ key = _ref2[0],
63
+ value = _ref2[1];
64
+
65
+ return _objectSpread(_objectSpread({}, col), {}, _defineProperty({}, key, deepReplace(value, entityProcessor)));
66
+ }, {});
67
+ }
68
+
69
+ return value;
70
+ }
71
+
72
+ function translatePresetToReact(value, processor) {
73
+ var props = value.props,
74
+ size = value.size;
75
+ var Component = processor({
76
+ $$__type: 'element',
77
+ $$__body: value
78
+ });
79
+ return /*#__PURE__*/React.createElement(Component, deepReplace(_objectSpread(_objectSpread({}, props), {}, {
80
+ style: _objectSpread(_objectSpread({}, props.style), size)
81
+ }), processor));
82
+ }
83
+
84
+ export var AtomRenderer = function AtomRenderer(props) {
85
+ var _useSiteData = useSiteData(),
86
+ entryExports = _useSiteData.entryExports;
87
+
88
+ switch (props.type) {
89
+ case 'COMPONENT':
90
+ return translatePresetToReact(props.value, function (entity) {
91
+ // TODO: support custom processor
92
+ return builtInProcessor(entity, entryExports);
93
+ });
94
+
95
+ default:
96
+ // TODO: handle FUNCTION type
97
+ return /*#__PURE__*/React.createElement(React.Fragment, null, props.type, " atom is not supported.");
98
+ }
99
+ };
@@ -4,6 +4,7 @@ import { type ComponentType } from 'react';
4
4
  import type { ILocalesConfig, IPreviewerProps, IThemeConfig } from './types';
5
5
  interface ISiteContext {
6
6
  pkg: Partial<Record<keyof typeof PICKED_PKG_FIELDS, any>>;
7
+ entryExports: Record<string, any>;
7
8
  demos: Record<string, {
8
9
  component: ComponentType;
9
10
  asset: IPreviewerProps['asset'];
@@ -1,6 +1,7 @@
1
1
  import { createContext, useContext } from 'react';
2
2
  export var SiteContext = /*#__PURE__*/createContext({
3
3
  pkg: {},
4
+ entryExports: {},
4
5
  demos: {},
5
6
  components: {},
6
7
  locales: [],
@@ -1,4 +1,5 @@
1
1
  export { createIntlCache, defineMessages, FormattedDate, FormattedDateParts, FormattedDisplayName, FormattedList, FormattedMessage, FormattedNumber, FormattedNumberParts, FormattedPlural, FormattedRelativeTime, FormattedTime, FormattedTimeParts, injectIntl, IntlContext, IntlProvider, RawIntlProvider, useIntl, } from 'react-intl';
2
+ export { AtomRenderer } from './AtomRenderer';
2
3
  export { useSiteData } from './context';
3
4
  export { DumiDemo } from './DumiDemo';
4
5
  export { DumiDemoGrid } from './DumiDemoGrid';
@@ -1,4 +1,5 @@
1
1
  export { createIntlCache, defineMessages, FormattedDate, FormattedDateParts, FormattedDisplayName, FormattedList, FormattedMessage, FormattedNumber, FormattedNumberParts, FormattedPlural, FormattedRelativeTime, FormattedTime, FormattedTimeParts, injectIntl, IntlContext, IntlProvider, RawIntlProvider, useIntl } from 'react-intl';
2
+ export { AtomRenderer } from "./AtomRenderer";
2
3
  export { useSiteData } from "./context";
3
4
  export { DumiDemo } from "./DumiDemo";
4
5
  export { DumiDemoGrid } from "./DumiDemoGrid";
@@ -75,7 +75,7 @@ var compile_default = (api) => {
75
75
  });
76
76
  memo.module.rule("dumi-page").type("javascript/auto").test(/\.(j|t)sx?$/).resourceQuery(/meta$/).use("page-meta-loader").loader(require.resolve("../../loaders/page"));
77
77
  memo.module.rule("dumi-demo").type("javascript/auto").test(/\..+$/).enforce("pre").resourceQuery(/techStack/).use("demo-loader").loader(require.resolve("../../loaders/demo")).options({ techStacks, cwd: api.cwd });
78
- memo.module.rule("dumi-raw").post().resourceQuery(/dumi-raw/).use("raw-loader").loader(require.resolve("raw-loader"));
78
+ memo.module.rule("dumi-raw").post().resourceQuery(/dumi-raw/).use("raw-loader").loader(require.resolve("raw-loader")).end().use("pre-raw-loader").loader(require.resolve("../../loaders/pre-raw"));
79
79
  if (api.env === "development" && memo.plugins.has("fastRefresh")) {
80
80
  memo.plugin("fastRefresh").tap(([params]) => [
81
81
  {
@@ -71,11 +71,14 @@ var derivative_default = (api) => {
71
71
  };
72
72
  api.describe({ key: "dumi:derivative" });
73
73
  api.onCheck(() => {
74
- var _a;
74
+ var _a, _b;
75
75
  (0, import_assert.default)(!api.config.mpa, "MPA mode is not supported in dumi!");
76
76
  (0, import_assert.default)(!api.config.vite, "Vite mode is not supported yet!");
77
77
  (0, import_assert.default)(((_a = api.config.mfsu) == null ? void 0 : _a.strategy) !== "eager", "MFSU eager mode is not supported yet!");
78
78
  (0, import_assert.default)(!api.config.ssr || api.config.ssr.builder === "webpack", "Only `webpack` builder is supported in SSR mode!");
79
+ if (((_b = api.userConfig.history) == null ? void 0 : _b.type) === "hash") {
80
+ import_plugin_utils.logger.warn("Hash history is temporarily incompatible, it is recommended to use browser history for now.");
81
+ }
79
82
  });
80
83
  safeExcludeInMFSU(api, [new RegExp("dumi/dist/client")]);
81
84
  api.modifyDefaultConfig((memo) => {
@@ -47,7 +47,7 @@ var tabs_default = (api) => {
47
47
  key: "addContentTab"
48
48
  });
49
49
  tabsFromPlugins.forEach((tab) => {
50
- tab.id ?? (tab.id = `plugin-tab${tab.test ? `-${tab.test}` : ""}-${tab.key}`);
50
+ tab.id ?? (tab.id = `plugin-tab-${tab.key}`);
51
51
  tab.component = (0, import_plugin_utils.winPath)(tab.component);
52
52
  });
53
53
  return memo;
@@ -82,8 +82,8 @@ var tabs_default = (api) => {
82
82
  });
83
83
  }
84
84
  });
85
- tabs.push(...tabsFromPlugins.map((tab) => ({
86
- index: tabs.length,
85
+ tabs.push(...tabsFromPlugins.map((tab, index) => ({
86
+ index: tabs.length + index,
87
87
  key: tab.key,
88
88
  id: tab.id,
89
89
  file: tab.component
@@ -42,6 +42,12 @@ function getPkgThemePath(api) {
42
42
  const pkgThemeName = getPkgThemeName(api);
43
43
  return pkgThemeName && import_path.default.dirname(require.resolve(`${pkgThemeName}/package.json`, { paths: [api.cwd] }));
44
44
  }
45
+ function getModuleExports(modulePath) {
46
+ return (0, import_bundler_utils.parseModuleSync)({
47
+ path: modulePath,
48
+ content: import_fs.default.readFileSync(modulePath, "utf-8")
49
+ })[1];
50
+ }
45
51
  var theme_default = (api) => {
46
52
  const defaultThemeData = (0, import_loader.default)(DEFAULT_THEME_PATH);
47
53
  const pkgThemePath = getPkgThemePath(api);
@@ -60,7 +66,12 @@ var theme_default = (api) => {
60
66
  api.registerPlugins([plugin]);
61
67
  }
62
68
  });
63
- (0, import_derivative.safeExcludeInMFSU)(api, ["dumi/theme-default", "@ant-design/icons-svg", getPkgThemeName(api)].filter(Boolean).map((pkg) => new RegExp(pkg)));
69
+ (0, import_derivative.safeExcludeInMFSU)(api, [
70
+ "dumi/theme-default",
71
+ "@ant-design/icons-svg",
72
+ "highlight-words-core",
73
+ getPkgThemeName(api)
74
+ ].filter(Boolean).map((pkg) => new RegExp(pkg)));
64
75
  api.register({
65
76
  key: "modifyAppData",
66
77
  before: "appData",
@@ -113,10 +124,7 @@ var theme_default = (api) => {
113
124
  if (item.source === "dumi")
114
125
  return;
115
126
  let contents = [];
116
- const [, exports] = (0, import_bundler_utils.parseModuleSync)({
117
- path: item.source,
118
- content: import_fs.default.readFileSync(item.source, "utf-8")
119
- });
127
+ const exports = getModuleExports(item.source);
120
128
  if (exports.includes("default")) {
121
129
  contents.push(`export { default } from '${item.source}';`);
122
130
  }
@@ -130,6 +138,10 @@ var theme_default = (api) => {
130
138
  });
131
139
  });
132
140
  });
141
+ const entryFile = api.config.resolve.entryFile && [import_path.default.resolve(api.cwd, api.config.resolve.entryFile)].find(import_fs.default.existsSync);
142
+ const entryExports = entryFile ? getModuleExports(entryFile) : [];
143
+ const hasDefaultExport = entryExports.includes("default");
144
+ const hasNamedExport = entryExports.some((exp) => exp !== "default");
133
145
  api.writeTmpFile({
134
146
  noPluginDir: true,
135
147
  path: "dumi/theme/ContextWrapper.tsx",
@@ -137,7 +149,14 @@ var theme_default = (api) => {
137
149
  import { useOutlet, history } from 'dumi';
138
150
  import { SiteContext } from '${(0, import_plugin_utils.winPath)(require.resolve("../../client/theme-api/context"))}';
139
151
  import { demos, components } from '../meta';
140
- import { locales } from '../locales/config';
152
+ import { locales } from '../locales/config';${hasDefaultExport ? `
153
+ import entryDefaultExport from '${(0, import_plugin_utils.winPath)(entryFile)}';` : ""}${hasNamedExport ? `
154
+ import * as entryMemberExports from '${(0, import_plugin_utils.winPath)(entryFile)}';` : ""}
155
+
156
+ const entryExports = {
157
+ ${hasDefaultExport ? "default: entryDefaultExport," : ""}
158
+ ${hasNamedExport ? "...entryMemberExports," : ""}
159
+ };
141
160
 
142
161
  export default function DumiContextWrapper() {
143
162
  const outlet = useOutlet();
@@ -160,6 +179,7 @@ export default function DumiContextWrapper() {
160
179
  return (
161
180
  <SiteContext.Provider value={{
162
181
  pkg: ${JSON.stringify(import_plugin_utils.lodash.pick(api.pkg, ...Object.keys(import_constants.PICKED_PKG_FIELDS)))},
182
+ entryExports,
163
183
  demos,
164
184
  components,
165
185
  locales,
@@ -137,6 +137,7 @@ function mdLoader(content) {
137
137
  ].join(":");
138
138
  cache.setSync(finalCacheKey, ret);
139
139
  cb(null, emit.call(this, opts, ret));
140
+ delete deferrer[cacheKey];
140
141
  }).catch(cb);
141
142
  }
142
143
  // Annotate the CommonJS export names for ESM import in node:
@@ -143,14 +143,15 @@ function rehypeDemo(opts) {
143
143
  parseOpts.fileAbsPath = codeNode.properties.src;
144
144
  parseOpts.id = getCodeId(opts.cwd, opts.fileAbsPath, import_path.default.parse(parseOpts.fileAbsPath).name, vFile.data.frontmatter.atomId);
145
145
  component = `React.lazy(() => import( /* webpackChunkName: "${chunkName}" */ '${(0, import_plugin_utils.winPath)(parseOpts.fileAbsPath)}?techStack=${techStack.name}'))`;
146
- codeNode.properties.title = codeValue || void 0;
146
+ if (codeValue)
147
+ codeNode.properties.title = codeValue;
147
148
  (_a2 = codeNode.properties).filename ?? (_a2.filename = (0, import_plugin_utils.winPath)(import_path.default.relative(opts.cwd, parseOpts.fileAbsPath)));
148
149
  } else {
149
150
  parseOpts.fileAbsPath = opts.fileAbsPath.replace(".md", ".tsx");
150
151
  parseOpts.id = getCodeId(opts.cwd, opts.fileAbsPath, String(index++), vFile.data.frontmatter.atomId);
151
152
  component = techStack.transformCode(codeValue, {
152
153
  type: "code-block",
153
- fileAbsPath: opts.fileAbsPath
154
+ fileAbsPath: parseOpts.fileAbsPath
154
155
  });
155
156
  }
156
157
  const propDemo = { id: parseOpts.id };
@@ -1,3 +1,3 @@
1
1
  import type { Root } from 'mdast';
2
2
  import type { Transformer } from 'unified';
3
- export default function remarkContainer(): Transformer<Root>;
3
+ export default function remarkContainer(this: any): Transformer<Root>;
@@ -32,6 +32,10 @@ var VALID_CONTAINER_TYPES = ["info", "warning", "success", "error"];
32
32
  ({ visit, SKIP } = await import("unist-util-visit"));
33
33
  })();
34
34
  function remarkContainer() {
35
+ const data = this.data();
36
+ const micromarkExtensions = data.micromarkExtensions.find(({ flow, text }) => flow && "58" in flow && text && "58" in text);
37
+ delete micromarkExtensions.text;
38
+ micromarkExtensions.flow["58"].splice(1, 1);
35
39
  return (tree) => {
36
40
  visit(tree, (node, i, parent) => {
37
41
  if (node.type === "containerDirective" && VALID_CONTAINER_TYPES.includes(node.name)) {
@@ -0,0 +1,4 @@
1
+ /**
2
+ * loader for discard frontmatter from code file content
3
+ */
4
+ export default function preRawLoader(this: any, raw: string): string;
@@ -0,0 +1,33 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/loaders/pre-raw/index.ts
20
+ var pre_raw_exports = {};
21
+ __export(pre_raw_exports, {
22
+ default: () => preRawLoader
23
+ });
24
+ module.exports = __toCommonJS(pre_raw_exports);
25
+ var import_utils = require("../../utils");
26
+ function preRawLoader(raw) {
27
+ if (/\.(j|t)sx?$/.test(this.resourcePath)) {
28
+ return (0, import_utils.parseCodeFrontmatter)(raw).code;
29
+ }
30
+ return raw;
31
+ }
32
+ // Annotate the CommonJS export names for ESM import in node:
33
+ 0 && (module.exports = {});
@@ -3,7 +3,7 @@ export declare class DumiService extends Service {
3
3
  constructor();
4
4
  getPaths(): Promise<{
5
5
  cwd: string;
6
- absSrcPath: string;
6
+ absSrcPath: any;
7
7
  absPagesPath: string;
8
8
  absApiRoutesPath: string;
9
9
  absTmpPath: string;
@@ -38,8 +38,9 @@ var DumiService = class extends import_umi.Service {
38
38
  });
39
39
  }
40
40
  async getPaths() {
41
+ var _a;
41
42
  const cwd = this.cwd;
42
- const absSrcPath = cwd;
43
+ const absSrcPath = ((_a = this.userConfig.alias) == null ? void 0 : _a["@"]) ?? cwd;
43
44
  const absPagesPath = winJoin(absSrcPath, "pages");
44
45
  const absApiRoutesPath = winJoin(absSrcPath, "api");
45
46
  const tmp = this.env === import_core.Env.development ? `tmp` : `tmp-${this.env}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dumi",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "📖 Documentation Generator of React Component",
5
5
  "keywords": [
6
6
  "generator",
@@ -102,6 +102,7 @@
102
102
  "mdast-util-to-string": "^3.1.0",
103
103
  "pluralize": "^8.0.0",
104
104
  "prism-react-renderer": "^1.3.5",
105
+ "prism-themes": "^1.9.0",
105
106
  "prismjs": "^1.29.0",
106
107
  "raw-loader": "^4.0.2",
107
108
  "rc-tabs": "12.1.0-alpha.1",
@@ -1,5 +1,5 @@
1
1
  import { type Language } from 'prism-react-renderer';
2
- import 'prismjs/themes/prism-coy.css';
2
+ import 'prism-themes/themes/prism-one-light.css';
3
3
  import { type FC } from 'react';
4
4
  import './index.less';
5
5
  declare const SourceCode: FC<{
@@ -15,7 +15,7 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
15
15
  import { ReactComponent as IconCheck } from '@ant-design/icons-svg/inline-svg/outlined/check.svg';
16
16
  import { ReactComponent as IconCopy } from '@ant-design/icons-svg/inline-svg/outlined/copy.svg';
17
17
  import Highlight, { defaultProps } from 'prism-react-renderer';
18
- import 'prismjs/themes/prism-coy.css';
18
+ import 'prism-themes/themes/prism-one-light.css';
19
19
  import React, { useRef, useState } from 'react';
20
20
  import { CopyToClipboard } from 'react-copy-to-clipboard';
21
21
  import "./index.less";
@@ -8,6 +8,10 @@
8
8
  color: @c-primary;
9
9
  }
10
10
 
11
+ img {
12
+ max-width: 100%;
13
+ }
14
+
11
15
  // inline code
12
16
  *:not(pre) code {
13
17
  padding: 2px 5px;
@@ -1,5 +1,11 @@
1
1
  @import '../LangSwitch/index.less';
2
2
 
3
+ .@{prefix}-lang-switch {
4
+ + & {
5
+ margin-inline-start: 20px;
6
+ }
7
+ }
8
+
3
9
  html[data-direction='rtl'] {
4
10
  direction: rtl;
5
11
  }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ declare type NativeInputProps = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
3
+ export declare const Input: React.ForwardRefExoticComponent<{
4
+ onChange: (keywords: string) => void;
5
+ } & Pick<NativeInputProps, "onFocus" | "onBlur"> & React.RefAttributes<HTMLInputElement>>;
6
+ export {};
@@ -0,0 +1,40 @@
1
+ import { useIntl } from 'dumi';
2
+ import React, { forwardRef, useImperativeHandle, useRef } from 'react';
3
+ export var Input = /*#__PURE__*/forwardRef(function (props, ref) {
4
+ var intl = useIntl();
5
+ var imeWaiting = useRef(false);
6
+ var nativeInputRef = useRef(null);
7
+ useImperativeHandle(ref, function () {
8
+ return nativeInputRef.current;
9
+ });
10
+ return /*#__PURE__*/React.createElement("input", {
11
+ className: "dumi-default-search-bar-input",
12
+ onCompositionStart: function onCompositionStart() {
13
+ return imeWaiting.current = true;
14
+ },
15
+ onCompositionEnd: function onCompositionEnd(ev) {
16
+ imeWaiting.current = false; // special case: press Enter open IME panel will not trigger onChange
17
+
18
+ props.onChange(ev.currentTarget.value);
19
+ },
20
+ onFocus: props.onFocus,
21
+ onBlur: props.onBlur,
22
+ onKeyDown: function onKeyDown(ev) {
23
+ if (['ArrowDown', 'ArrowUp'].includes(ev.key)) ev.preventDefault(); // esc to blur input
24
+
25
+ if (ev.key === 'Escape' && !imeWaiting.current) ev.currentTarget.blur();
26
+ },
27
+ onChange: function onChange(ev) {
28
+ // wait for onCompositionEnd event be triggered
29
+ setTimeout(function () {
30
+ if (!imeWaiting.current) {
31
+ props.onChange(ev.target.value);
32
+ }
33
+ }, 1);
34
+ },
35
+ placeholder: intl.formatMessage({
36
+ id: 'header.search.placeholder'
37
+ }),
38
+ ref: nativeInputRef
39
+ });
40
+ });
@@ -0,0 +1,9 @@
1
+ import { type FC, type ReactNode } from 'react';
2
+ declare type MaskProps = {
3
+ visible: boolean;
4
+ children: ReactNode;
5
+ onMaskClick?: () => void;
6
+ onClose?: () => void;
7
+ };
8
+ export declare const Mask: FC<MaskProps>;
9
+ export {};
@@ -0,0 +1,21 @@
1
+ import React, { useEffect } from 'react';
2
+ export var Mask = function Mask(props) {
3
+ useEffect(function () {
4
+ if (props.visible) {
5
+ document.body.style.overflow = 'hidden';
6
+ } else {
7
+ var _props$onClose;
8
+
9
+ document.body.style.overflow = '';
10
+ (_props$onClose = props.onClose) === null || _props$onClose === void 0 ? void 0 : _props$onClose.call(props);
11
+ }
12
+ }, [props.visible]);
13
+ return props.visible ? /*#__PURE__*/React.createElement("div", {
14
+ className: "dumi-default-search-modal"
15
+ }, /*#__PURE__*/React.createElement("div", {
16
+ className: "dumi-default-search-modal-mask",
17
+ onClick: props.onMaskClick
18
+ }), /*#__PURE__*/React.createElement("div", {
19
+ className: "dumi-default-search-modal-content"
20
+ }, props.children)) : null;
21
+ };
@@ -1,4 +1,6 @@
1
1
  import { type FC } from 'react';
2
2
  import './index.less';
3
+ export { Input as SearchInput } from './Input';
4
+ export { Mask as SearchMask } from './Mask';
3
5
  declare const SearchBar: FC;
4
6
  export default SearchBar;
@@ -12,23 +12,27 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
12
12
 
13
13
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
14
14
 
15
+ import { ReactComponent as IconArrowDown } from '@ant-design/icons-svg/inline-svg/outlined/arrow-down.svg';
16
+ import { ReactComponent as IconArrowUp } from '@ant-design/icons-svg/inline-svg/outlined/arrow-up.svg';
15
17
  import { ReactComponent as IconSearch } from '@ant-design/icons-svg/inline-svg/outlined/search.svg';
16
- import { useIntl, useSiteSearch } from 'dumi';
18
+ import { useSiteSearch } from 'dumi';
17
19
  import React, { useEffect, useRef, useState } from 'react';
18
20
  import SearchResult from "../SearchResult";
19
21
  import "./index.less";
22
+ import { Input } from "./Input";
23
+ import { Mask } from "./Mask";
24
+ export { Input as SearchInput } from "./Input";
25
+ export { Mask as SearchMask } from "./Mask";
20
26
  var isAppleDevice = /(mac|iphone|ipod|ipad)/i.test(typeof navigator !== 'undefined' ? (_navigator = navigator) === null || _navigator === void 0 ? void 0 : _navigator.platform : '');
21
27
 
22
28
  var SearchBar = function SearchBar() {
23
- var intl = useIntl();
24
- var imeWaiting = useRef(false);
25
-
26
29
  var _useState = useState(false),
27
30
  _useState2 = _slicedToArray(_useState, 2),
28
31
  focusing = _useState2[0],
29
32
  setFocusing = _useState2[1];
30
33
 
31
- var input = useRef(null);
34
+ var inputRef = useRef(null);
35
+ var modalInputRef = useRef(null);
32
36
 
33
37
  var _useState3 = useState('⌘'),
34
38
  _useState4 = _slicedToArray(_useState3, 2),
@@ -41,6 +45,11 @@ var SearchBar = function SearchBar() {
41
45
  result = _useSiteSearch.result,
42
46
  loading = _useSiteSearch.loading;
43
47
 
48
+ var _useState5 = useState(false),
49
+ _useState6 = _slicedToArray(_useState5, 2),
50
+ modalVisible = _useState6[0],
51
+ setModalVisible = _useState6[1];
52
+
44
53
  useEffect(function () {
45
54
  // why put useEffect?
46
55
  // to avoid Text content mismatch between server & client in ssr
@@ -49,11 +58,35 @@ var SearchBar = function SearchBar() {
49
58
  }
50
59
 
51
60
  var handler = function handler(ev) {
52
- if ((isAppleDevice ? ev.metaKey : ev.ctrlKey) && ev.key === 'k') {
53
- var _input$current;
61
+ if ((isAppleDevice ? ev.metaKey : ev.ctrlKey) && ev.key === 'k' || ev.key === '/') {
62
+ ev.preventDefault();
63
+
64
+ if (inputRef.current) {
65
+ var _inputRef$current$get = inputRef.current.getBoundingClientRect(),
66
+ top = _inputRef$current$get.top,
67
+ bottom = _inputRef$current$get.bottom,
68
+ left = _inputRef$current$get.left,
69
+ right = _inputRef$current$get.right;
70
+
71
+ var isInViewport = top >= 0 && left >= 0 && bottom <= window.innerHeight && right <= window.innerWidth;
72
+
73
+ if (isInViewport) {
74
+ inputRef.current.focus();
75
+ } else {
76
+ setKeywords('');
77
+ setModalVisible(true);
78
+ setTimeout(function () {
79
+ var _modalInputRef$curren;
80
+
81
+ (_modalInputRef$curren = modalInputRef.current) === null || _modalInputRef$curren === void 0 ? void 0 : _modalInputRef$curren.focus();
82
+ });
83
+ }
84
+ }
85
+ }
54
86
 
55
- (_input$current = input.current) === null || _input$current === void 0 ? void 0 : _input$current.focus();
87
+ if (ev.key === 'Escape') {
56
88
  ev.preventDefault();
89
+ setModalVisible(false);
57
90
  }
58
91
  };
59
92
 
@@ -64,15 +97,9 @@ var SearchBar = function SearchBar() {
64
97
  }, []);
65
98
  return /*#__PURE__*/React.createElement("div", {
66
99
  className: "dumi-default-search-bar"
67
- }, /*#__PURE__*/React.createElement(IconSearch, null), /*#__PURE__*/React.createElement("input", {
68
- onCompositionStart: function onCompositionStart() {
69
- return imeWaiting.current = true;
70
- },
71
- onCompositionEnd: function onCompositionEnd(ev) {
72
- imeWaiting.current = false; // special case: press Enter open IME panel will not trigger onChange
73
-
74
- setKeywords(ev.currentTarget.value);
75
- },
100
+ }, /*#__PURE__*/React.createElement(IconSearch, {
101
+ className: "dumi-default-search-bar-svg"
102
+ }), /*#__PURE__*/React.createElement(Input, {
76
103
  onFocus: function onFocus() {
77
104
  return setFocusing(true);
78
105
  },
@@ -82,31 +109,74 @@ var SearchBar = function SearchBar() {
82
109
  setFocusing(false);
83
110
  }, 1);
84
111
  },
85
- onKeyDown: function onKeyDown(ev) {
86
- if (['ArrowDown', 'ArrowUp'].includes(ev.key)) ev.preventDefault(); // esc to blur input
87
-
88
- if (ev.key === 'Escape' && !imeWaiting.current) ev.currentTarget.blur();
112
+ onChange: function onChange(keywords) {
113
+ return setKeywords(keywords);
89
114
  },
90
- onChange: function onChange(ev) {
91
- // wait for onCompositionEnd event be triggered
92
- setTimeout(function () {
93
- if (!imeWaiting.current) {
94
- setKeywords(ev.target.value);
95
- }
96
- }, 1);
97
- },
98
- placeholder: intl.formatMessage({
99
- id: 'header.search.placeholder'
100
- }),
101
- ref: input
115
+ ref: inputRef
102
116
  }), /*#__PURE__*/React.createElement("span", {
103
117
  className: "dumi-default-search-shortcut"
104
- }, symbol, " K"), keywords.trim() && focusing && (result.length || !loading) && /*#__PURE__*/React.createElement("div", {
118
+ }, symbol, " K"), keywords.trim() && focusing && (result.length || !loading) && !modalVisible && /*#__PURE__*/React.createElement("div", {
105
119
  className: "dumi-default-search-popover"
106
120
  }, /*#__PURE__*/React.createElement("section", null, /*#__PURE__*/React.createElement(SearchResult, {
107
121
  data: result,
108
122
  loading: loading
109
- }))));
123
+ }))), /*#__PURE__*/React.createElement(Mask, {
124
+ visible: modalVisible,
125
+ onMaskClick: function onMaskClick() {
126
+ setModalVisible(false);
127
+ },
128
+ onClose: function onClose() {
129
+ return setKeywords('');
130
+ }
131
+ }, /*#__PURE__*/React.createElement("div", {
132
+ style: {
133
+ position: 'relative'
134
+ }
135
+ }, /*#__PURE__*/React.createElement(IconSearch, {
136
+ className: "dumi-default-search-bar-svg"
137
+ }), /*#__PURE__*/React.createElement(Input, {
138
+ onFocus: function onFocus() {
139
+ return setFocusing(true);
140
+ },
141
+ onBlur: function onBlur() {
142
+ // wait for item click
143
+ setTimeout(function () {
144
+ setFocusing(false);
145
+ }, 1);
146
+ },
147
+ onChange: function onChange(keywords) {
148
+ return setKeywords(keywords);
149
+ },
150
+ ref: modalInputRef
151
+ })), /*#__PURE__*/React.createElement(SearchResult, {
152
+ data: result,
153
+ loading: loading,
154
+ onItemSelect: function onItemSelect() {
155
+ setModalVisible(false);
156
+ }
157
+ }), /*#__PURE__*/React.createElement("footer", null, /*#__PURE__*/React.createElement("ul", {
158
+ className: "dumi-default-search-modal-commands"
159
+ }, /*#__PURE__*/React.createElement("li", {
160
+ className: "dumi-default-search-modal-commands-arrow"
161
+ }, /*#__PURE__*/React.createElement("span", {
162
+ className: "dumi-default-search-modal-shortcut"
163
+ }, /*#__PURE__*/React.createElement(IconArrowUp, {
164
+ width: "10px",
165
+ height: "10px",
166
+ fill: "rgba(0, 0, 0, 0.45)"
167
+ })), /*#__PURE__*/React.createElement("span", {
168
+ className: "dumi-default-search-modal-shortcut"
169
+ }, /*#__PURE__*/React.createElement(IconArrowDown, {
170
+ width: "10px",
171
+ height: "10px",
172
+ fill: "rgba(0, 0, 0, 0.45)"
173
+ })), /*#__PURE__*/React.createElement("span", {
174
+ className: "dumi-default-search-modal-commands-text"
175
+ }, "to navigate")), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("span", {
176
+ className: "dumi-default-search-modal-shortcut"
177
+ }, "esc"), /*#__PURE__*/React.createElement("span", {
178
+ className: "dumi-default-search-modal-commands-text"
179
+ }, "to close"))))));
110
180
  };
111
181
 
112
182
  export default SearchBar;
@@ -12,7 +12,7 @@
12
12
  margin-inline-end: 28px;
13
13
  }
14
14
 
15
- > svg {
15
+ &-svg {
16
16
  position: absolute;
17
17
  top: 50%;
18
18
  margin-top: 1px;
@@ -22,7 +22,7 @@
22
22
  transform: translateY(-50%);
23
23
  }
24
24
 
25
- > input {
25
+ &-input {
26
26
  width: 280px;
27
27
  height: 40px;
28
28
  padding: 0;
@@ -104,4 +104,89 @@
104
104
  border-radius: inherit;
105
105
  }
106
106
  }
107
+
108
+ .@{prefix}-search-modal {
109
+ position: fixed;
110
+ top: 0;
111
+ inset-inline-start: 0;
112
+ z-index: 1000;
113
+ width: 100vw;
114
+ height: 100vh;
115
+ display: flex;
116
+ justify-content: center;
117
+
118
+ &-mask {
119
+ background-color: rgb(0 0 0 / 45%);
120
+ width: 100%;
121
+ height: 100%;
122
+ }
123
+
124
+ &-content {
125
+ position: absolute;
126
+ top: 60px;
127
+ background-color: #fff;
128
+ width: 500px;
129
+ padding: 12px;
130
+ box-sizing: border-box;
131
+ box-shadow: inset 1px 1px 0 0 hsl(0deg 0% 100% / 50%), 0 3px 8px 0 #555a64;
132
+ border-radius: 8px;
133
+ }
134
+
135
+ .@{prefix}-search-bar-input {
136
+ width: 100%;
137
+ border-radius: 4px;
138
+ }
139
+
140
+ .@{prefix}-search-result {
141
+ min-height: 60px;
142
+ margin-top: 12px;
143
+
144
+ > dl > dd {
145
+ margin: 0 auto;
146
+ }
147
+ }
148
+
149
+ &-commands {
150
+ justify-content: flex-start;
151
+ font-size: 12px;
152
+ color: @c-text-note;
153
+ list-style: none;
154
+ padding: 0;
155
+ margin: 0;
156
+ border-top: 1px solid @c-border-light;
157
+ padding-top: 12px;
158
+ display: flex;
159
+ align-items: center;
160
+ user-select: none;
161
+
162
+ > li {
163
+ margin-inline-end: 10px;
164
+ }
165
+
166
+ &-arrow {
167
+ .@{prefix}-search-modal-shortcut {
168
+ margin-inline-end: 4px;
169
+ }
170
+ }
171
+
172
+ &-text {
173
+ margin-inline-start: 5px;
174
+ }
175
+ }
176
+
177
+ &-shortcut {
178
+ display: inline-block;
179
+ padding: 4px 8px;
180
+ color: @c-text-note;
181
+ font-size: 12px;
182
+ line-height: 1;
183
+ white-space: nowrap;
184
+ background-color: @c-site-bg;
185
+ border-radius: 3px;
186
+ border: 1px solid @c-border;
187
+ border-bottom-width: 2px;
188
+ transition: all 0.3s;
189
+ pointer-events: none;
190
+ }
191
+ }
107
192
  }
@@ -5,5 +5,6 @@ declare type ISearchResult = ReturnType<typeof useSiteSearch>['result'];
5
5
  declare const SearchResult: FC<{
6
6
  data: ISearchResult;
7
7
  loading: boolean;
8
+ onItemSelect?: (item: ISearchResult[0]['hints'][0]) => void;
8
9
  }>;
9
10
  export default SearchResult;
@@ -125,10 +125,13 @@ var SearchResult = function SearchResult(props) {
125
125
  } else if (ev.key === 'ArrowUp') {
126
126
  setActiveIndex((activeIndex + histsCount - 1) % histsCount);
127
127
  } else if (ev.key === 'Enter' && activeIndex >= 0) {
128
- var item = data.find(function (item) {
128
+ var _props$onItemSelect;
129
+
130
+ var _item = data.find(function (item) {
129
131
  return item.type === 'hint' && item.activeIndex === activeIndex;
130
132
  }).value;
131
- history.push(item.link);
133
+ history.push(_item.link);
134
+ (_props$onItemSelect = props.onItemSelect) === null || _props$onItemSelect === void 0 ? void 0 : _props$onItemSelect.call(props, _item);
132
135
  document.activeElement.blur();
133
136
  }
134
137
 
@@ -161,7 +164,12 @@ var SearchResult = function SearchResult(props) {
161
164
  key: String(i)
162
165
  }, /*#__PURE__*/React.createElement(Link, {
163
166
  to: item.value.link,
164
- "data-active": activeIndex === item.activeIndex || undefined
167
+ "data-active": activeIndex === item.activeIndex || undefined,
168
+ onClick: function onClick() {
169
+ var _props$onItemSelect2;
170
+
171
+ return (_props$onItemSelect2 = props.onItemSelect) === null || _props$onItemSelect2 === void 0 ? void 0 : _props$onItemSelect2.call(props, item.value);
172
+ }
165
173
  }, /*#__PURE__*/React.createElement(ICONS_MAPPING[item.value.type]), /*#__PURE__*/React.createElement("h4", null, /*#__PURE__*/React.createElement(Highlight, {
166
174
  texts: item.value.highlightTitleTexts
167
175
  })), /*#__PURE__*/React.createElement("p", null, /*#__PURE__*/React.createElement(Highlight, {