From fdea97236ca0317061776acbee2765de6d209709 Mon Sep 17 00:00:00 2001 From: mantou132 <709922234@qq.com> Date: Tue, 12 Dec 2023 18:18:11 +0800 Subject: [PATCH] Closed #93, #105 --- packages/duoyun-ui/docs/en/01-guide/README.md | 2 +- .../docs/en/02-elements/contextmenu.md | 41 +++++++++++++ .../duoyun-ui/docs/en/02-elements/menu.md | 44 +------------- packages/duoyun-ui/docs/zh/01-guide/README.md | 2 +- .../docs/zh/02-elements/contextmenu.md | 41 +++++++++++++ .../duoyun-ui/docs/zh/02-elements/menu.md | 44 +------------- packages/duoyun-ui/package.json | 2 +- packages/duoyun-ui/src/elements/button.ts | 4 +- packages/duoyun-ui/src/elements/card.ts | 4 +- .../duoyun-ui/src/elements/cascader-picker.ts | 2 +- packages/duoyun-ui/src/elements/coach-mark.ts | 2 +- .../src/elements/{menu.ts => contextmenu.ts} | 60 +++++++++---------- .../duoyun-ui/src/elements/date-picker.ts | 2 +- .../src/elements/date-range-picker.ts | 2 +- packages/duoyun-ui/src/elements/picker.ts | 4 +- packages/duoyun-ui/src/elements/table.ts | 6 +- .../duoyun-ui/src/elements/time-picker.ts | 2 +- .../docs/en/002-guide/004-metadata.md | 20 +++++-- packages/gem-book/docs/en/002-guide/README.md | 9 ++- .../docs/zh/002-guide/004-metadata.md | 20 +++++-- packages/gem-book/docs/zh/002-guide/README.md | 9 ++- packages/gem-book/package.json | 2 +- packages/gem-book/src/bin/index.ts | 9 ++- packages/gem-book/src/common/config.ts | 1 + packages/gem-book/src/common/frontmatter.ts | 1 + .../gem-book/src/element/elements/main.ts | 3 + packages/gem-book/src/element/store.ts | 25 +++++++- packages/gem-examples/package.json | 2 +- packages/gem-examples/src/tree/index.ts | 2 +- 29 files changed, 221 insertions(+), 146 deletions(-) create mode 100644 packages/duoyun-ui/docs/en/02-elements/contextmenu.md create mode 100644 packages/duoyun-ui/docs/zh/02-elements/contextmenu.md rename packages/duoyun-ui/src/elements/{menu.ts => contextmenu.ts} (85%) diff --git a/packages/duoyun-ui/docs/en/01-guide/README.md b/packages/duoyun-ui/docs/en/01-guide/README.md index b7c225af..cf2488e7 100644 --- a/packages/duoyun-ui/docs/en/01-guide/README.md +++ b/packages/duoyun-ui/docs/en/01-guide/README.md @@ -13,7 +13,7 @@ DuoyunUI aims to provide a UI library for lightweight, high performance, full fe - Form > [``](../02-elements/cascader-picker.md), [``](../02-elements/cascader.md), [``](../02-elements/checkbox.md), [``](../02-elements/color-panel.md), [``](../02-elements/color-picker.md), [``](../02-elements/date-panel.md), [``](../02-elements/date-picker.md), [``](../02-elements/date-range-panel.md), [``](../02-elements/date-range-picker.md), [``](../02-elements/drop-area.md), [``](../02-elements/file-picker.md), [``](../02-elements/form.md), [``](../02-elements/input.md), [``](../02-elements/picker.md), [``](../02-elements/radio.md), [``](../02-elements/rating.md), [``](../02-elements/select.md), [``](../02-elements/shortcut-record.md), [``](../02-elements/slider.md), [``](../02-elements/switch.md), [``](../02-elements/time-panel.md), [``](../02-elements/time-picker.md) - Action - > [``](../02-elements/action-text.md), [``](../02-elements/button.md), [``](../02-elements/copy.md), [``](../02-elements/link.md), [``](../02-elements/menu.md), [``](../02-elements/options.md) + > [``](../02-elements/action-text.md), [``](../02-elements/button.md), [``](../02-elements/copy.md), [``](../02-elements/link.md), [``](../02-elements/contextmenu.md), [``](../02-elements/options.md) - Feedback > [``](../02-elements/coach-mark.md), [``](../02-elements/drawer.md), [``](../02-elements/help-text.md), [``](../02-elements/input-capture.md), [``](../02-elements/keyboard-access.md), [``](../02-elements/loading.md), [``](../02-elements/meter.md), [``](../02-elements/modal.md), [``](../02-elements/page-loadbar.md), [``](../02-elements/placeholder.md), [``](../02-elements/popover.md), [``](../02-elements/progress.md), [``](../02-elements/status-light.md), [``](../02-elements/toast.md), [``](../02-elements/tooltip.md), [``](../02-elements/wait.md) - Navigator diff --git a/packages/duoyun-ui/docs/en/02-elements/contextmenu.md b/packages/duoyun-ui/docs/en/02-elements/contextmenu.md new file mode 100644 index 00000000..4b745298 --- /dev/null +++ b/packages/duoyun-ui/docs/en/02-elements/contextmenu.md @@ -0,0 +1,41 @@ +# `` + +## Example + + + +```ts +import { render, html } from '@mantou/gem'; +import { ContextMenu } from 'duoyun-ui/elements/contextmenu'; + +import 'duoyun-ui/elements/button'; + +const onClick = (e: MouseEvent) => { + ContextMenu.open( + [ + { + text: 'Add', + }, + { + text: 'Edit', + }, + { + text: '---', + }, + { + text: 'Delete', + danger: true, + }, + ], + { activeElement: e.target }, + ); +}; + +render(html`Open ContextMenu`, document.getElementById('root')); +``` + + + +## API + + diff --git a/packages/duoyun-ui/docs/en/02-elements/menu.md b/packages/duoyun-ui/docs/en/02-elements/menu.md index cbfc3206..3a4d7ac4 100644 --- a/packages/duoyun-ui/docs/en/02-elements/menu.md +++ b/packages/duoyun-ui/docs/en/02-elements/menu.md @@ -1,41 +1,3 @@ -# `` - -## Example - - - -```ts -import { render, html } from '@mantou/gem'; -import { ContextMenu } from 'duoyun-ui/elements/menu'; - -import 'duoyun-ui/elements/button'; - -const onClick = (e: MouseEvent) => { - ContextMenu.open( - [ - { - text: 'Add', - }, - { - text: 'Edit', - }, - { - text: '---', - }, - { - text: 'Delete', - danger: true, - }, - ], - { activeElement: e.target }, - ); -}; - -render(html`Open Menu`, document.getElementById('root')); -``` - - - -## API - - +--- +redirect: ./contextmenu.md +--- diff --git a/packages/duoyun-ui/docs/zh/01-guide/README.md b/packages/duoyun-ui/docs/zh/01-guide/README.md index 1d9783e8..99530f68 100644 --- a/packages/duoyun-ui/docs/zh/01-guide/README.md +++ b/packages/duoyun-ui/docs/zh/01-guide/README.md @@ -12,7 +12,7 @@ DuoyunUI 是使用 [Gem](https://gemjs.org/) 开发的桌面端中后台 Web UI - 表单元素 > [``](../02-elements/cascader-picker.md), [``](../02-elements/cascader.md), [``](../02-elements/checkbox.md), [``](../02-elements/color-panel.md), [``](../02-elements/color-picker.md), [``](../02-elements/date-panel.md), [``](../02-elements/date-picker.md), [``](../02-elements/date-range-panel.md), [``](../02-elements/date-range-picker.md), [``](../02-elements/drop-area.md), [``](../02-elements/file-picker.md), [``](../02-elements/form.md), [``](../02-elements/input.md), [``](../02-elements/picker.md), [``](../02-elements/radio.md), [``](../02-elements/rating.md), [``](../02-elements/select.md), [``](../02-elements/shortcut-record.md), [``](../02-elements/slider.md), [``](../02-elements/switch.md), [``](../02-elements/time-panel.md), [``](../02-elements/time-picker.md) - 动作元素 - > [``](../02-elements/action-text.md), [``](../02-elements/button.md), [``](../02-elements/copy.md), [``](../02-elements/link.md), [``](../02-elements/menu.md), [``](../02-elements/options.md) + > [``](../02-elements/action-text.md), [``](../02-elements/button.md), [``](../02-elements/copy.md), [``](../02-elements/link.md), [``](../02-elements/contextmenu.md), [``](../02-elements/options.md) - 反馈元素 > [``](../02-elements/coach-mark.md), [``](../02-elements/drawer.md), [``](../02-elements/help-text.md), [``](../02-elements/input-capture.md), [``](../02-elements/keyboard-access.md), [``](../02-elements/loading.md), [``](../02-elements/meter.md), [``](../02-elements/modal.md), [``](../02-elements/page-loadbar.md), [``](../02-elements/placeholder.md), [``](../02-elements/popover.md), [``](../02-elements/progress.md), [``](../02-elements/status-light.md), [``](../02-elements/toast.md), [``](../02-elements/tooltip.md), [``](../02-elements/wait.md) - 导航元素 diff --git a/packages/duoyun-ui/docs/zh/02-elements/contextmenu.md b/packages/duoyun-ui/docs/zh/02-elements/contextmenu.md new file mode 100644 index 00000000..93696e1a --- /dev/null +++ b/packages/duoyun-ui/docs/zh/02-elements/contextmenu.md @@ -0,0 +1,41 @@ +# `` + +## Example + + + +```ts +import { render, html } from '@mantou/gem'; +import { ContextMenu } from 'duoyun-ui/elements/contextmenu'; + +import 'duoyun-ui/elements/button'; + +const onClick = (e: MouseEvent) => { + ContextMenu.open( + [ + { + text: '新增', + }, + { + text: '编辑', + }, + { + text: '---', + }, + { + text: '删除', + danger: true, + }, + ], + { activeElement: e.target }, + ); +}; + +render(html`打开上下文菜单`, document.getElementById('root')); +``` + + + +## API + + diff --git a/packages/duoyun-ui/docs/zh/02-elements/menu.md b/packages/duoyun-ui/docs/zh/02-elements/menu.md index e6dbfa88..3a4d7ac4 100644 --- a/packages/duoyun-ui/docs/zh/02-elements/menu.md +++ b/packages/duoyun-ui/docs/zh/02-elements/menu.md @@ -1,41 +1,3 @@ -# `` - -## Example - - - -```ts -import { render, html } from '@mantou/gem'; -import { ContextMenu } from 'duoyun-ui/elements/menu'; - -import 'duoyun-ui/elements/button'; - -const onClick = (e: MouseEvent) => { - ContextMenu.open( - [ - { - text: '新增', - }, - { - text: '编辑', - }, - { - text: '---', - }, - { - text: '删除', - danger: true, - }, - ], - { activeElement: e.target }, - ); -}; - -render(html`打开菜单`, document.getElementById('root')); -``` - - - -## API - - +--- +redirect: ./contextmenu.md +--- diff --git a/packages/duoyun-ui/package.json b/packages/duoyun-ui/package.json index c23452b1..13565cb0 100644 --- a/packages/duoyun-ui/package.json +++ b/packages/duoyun-ui/package.json @@ -1,6 +1,6 @@ { "name": "duoyun-ui", - "version": "1.0.2", + "version": "1.1.0", "description": "WebComponts UI", "exports": { "./elements/*": "./elements/*.js", diff --git a/packages/duoyun-ui/src/elements/button.ts b/packages/duoyun-ui/src/elements/button.ts index e46b0dbf..32509ec9 100644 --- a/packages/duoyun-ui/src/elements/button.ts +++ b/packages/duoyun-ui/src/elements/button.ts @@ -22,7 +22,7 @@ import { focusStyle } from '../lib/styles'; import { DuoyunUseElement } from './use'; import { createHistoryParams, RouteItem } from './route'; -import { MenuItem, ContextMenu } from './menu'; +import { ContextMenuItem, ContextMenu } from './contextmenu'; const style = createCSSSheet(css` :host(:where(:not([hidden]))) { @@ -126,7 +126,7 @@ export class DuoyunButtonElement extends GemElement { @boolattribute small: boolean; @boolattribute disabled: boolean; - @property dropdown?: MenuItem[] | null; + @property dropdown?: ContextMenuItem[] | null; @property route?: RouteItem; @property params?: Record; @property query?: Record; diff --git a/packages/duoyun-ui/src/elements/card.ts b/packages/duoyun-ui/src/elements/card.ts index fcfc52c0..4833cada 100644 --- a/packages/duoyun-ui/src/elements/card.ts +++ b/packages/duoyun-ui/src/elements/card.ts @@ -9,7 +9,7 @@ import { commonHandle } from '../lib/hotkeys'; import { focusStyle } from '../lib/styles'; import { DuoyunLoadableBaseElement } from './base/loadable'; -import { MenuItem, ContextMenu } from './menu'; +import { ContextMenuItem, ContextMenu } from './contextmenu'; import './use'; @@ -86,7 +86,7 @@ const style = createCSSSheet(css` } `); -export type ActionItem = Omit & { handle: (rest: HTMLElement) => void | Promise }; +export type ActionItem = Omit & { handle: (rest: HTMLElement) => void | Promise }; /** * @customElement dy-card diff --git a/packages/duoyun-ui/src/elements/cascader-picker.ts b/packages/duoyun-ui/src/elements/cascader-picker.ts index ee805cf6..0da08e66 100644 --- a/packages/duoyun-ui/src/elements/cascader-picker.ts +++ b/packages/duoyun-ui/src/elements/cascader-picker.ts @@ -18,7 +18,7 @@ import { getCascaderDeep } from '../lib/utils'; import { commonHandle } from '../lib/hotkeys'; import { focusStyle } from '../lib/styles'; -import { ContextMenu } from './menu'; +import { ContextMenu } from './contextmenu'; import { BasePickerElement, pickerStyle } from './picker'; import type { Option, DuoyunCascaderElement, OptionValue } from './cascader'; diff --git a/packages/duoyun-ui/src/elements/coach-mark.ts b/packages/duoyun-ui/src/elements/coach-mark.ts index d46fc017..4594ffac 100644 --- a/packages/duoyun-ui/src/elements/coach-mark.ts +++ b/packages/duoyun-ui/src/elements/coach-mark.ts @@ -8,7 +8,7 @@ import { splice } from '@mantou/gem/helper/i18n'; import { theme, getSemanticColor } from '../lib/theme'; import { locale } from '../lib/locale'; -import { ContextMenu } from './menu'; +import { ContextMenu } from './contextmenu'; import { DuoyunVisibleBaseElement } from './base/visible'; import { DuoyunWaitElement } from './wait'; diff --git a/packages/duoyun-ui/src/elements/menu.ts b/packages/duoyun-ui/src/elements/contextmenu.ts similarity index 85% rename from packages/duoyun-ui/src/elements/menu.ts rename to packages/duoyun-ui/src/elements/contextmenu.ts index d42b82df..71826a88 100644 --- a/packages/duoyun-ui/src/elements/menu.ts +++ b/packages/duoyun-ui/src/elements/contextmenu.ts @@ -14,8 +14,8 @@ import './compartment'; import './button'; import './options'; -export type Menu = MenuItem[] | TemplateResult; -export interface MenuItem { +type Menu = ContextMenuItem[] | TemplateResult; +export interface ContextMenuItem { /**`---` is separator */ text: string | TemplateResult; description?: string | TemplateResult; @@ -28,7 +28,7 @@ export interface MenuItem { menu?: Menu; } -type MenuStore = { +type ContextMenuStore = { // support `auto` width?: string; maxHeight?: string; @@ -45,7 +45,7 @@ type MenuStore = { }[]; }; -type MenuOptions = { +type ContextMenuOptions = { x?: number; y?: number; /**auto calc `x`/`y` via `activeElement` */ @@ -63,7 +63,7 @@ type MenuOptions = { header?: TemplateResult; }; -export const menuStore = createStore({ +const contextmenuStore = createStore({ menuStack: [], }); @@ -104,15 +104,15 @@ const style = createCSSSheet(css` `); /** - * @customElement dy-menu + * @customElement dy-contextmenu */ -@customElement('dy-menu') -@connectStore(menuStore) +@customElement('dy-contextmenu') +@connectStore(contextmenuStore) @adoptedStyle(style) -export class DuoyunMenuElement extends GemElement { - static instance?: DuoyunMenuElement; +export class DuoyunContextMenuElement extends GemElement { + static instance?: DuoyunContextMenuElement; - static async open(menu: Menu, options: MenuOptions = {}) { + static async open(contextmenu: Menu, options: ContextMenuOptions = {}) { const { activeElement, openLeft, @@ -124,15 +124,15 @@ export class DuoyunMenuElement extends GemElement { header, maskClosable = true, } = options; - if (Array.isArray(menu) && menu.length === 0) throw new Error('menu length is 0'); + if (Array.isArray(contextmenu) && contextmenu.length === 0) throw new Error('menu length is 0'); toggleActiveState(activeElement, true); - updateStore(menuStore, { + updateStore(contextmenuStore, { width, maxHeight, activeElement, openLeft, maskClosable, - menuStack: [{ x, y, menu, searchable, header }], + menuStack: [{ x, y, menu: contextmenu, searchable, header }], }); if (ContextMenu.instance) { await ContextMenu.instance.#initPosition(); @@ -144,7 +144,7 @@ export class DuoyunMenuElement extends GemElement { static async confirm( text: string | TemplateResult, - options: MenuOptions & { danger?: boolean; okText?: string | TemplateResult }, + options: ContextMenuOptions & { danger?: boolean; okText?: string | TemplateResult }, ) { return new Promise((res, rej) => { const onClick = () => { @@ -173,16 +173,16 @@ export class DuoyunMenuElement extends GemElement { static close() { if (!ContextMenu.instance) return; - toggleActiveState(menuStore.activeElement, false); + toggleActiveState(contextmenuStore.activeElement, false); closeResolve(); ContextMenu.instance.remove(); // specify keyboard navigation location - menuStore.activeElement?.focus(); - menuStore.activeElement?.blur(); + contextmenuStore.activeElement?.focus(); + contextmenuStore.activeElement?.blur(); } get #width() { - return menuStore.width || '15em'; + return contextmenuStore.width || '15em'; } get #menuElements() { @@ -197,7 +197,7 @@ export class DuoyunMenuElement extends GemElement { #offset = 4; #onEnterMenu = (evt: PointerEvent, menuStackIndex: number, subMenu?: Menu) => { - const { menuStack, openLeft } = menuStore; + const { menuStack, openLeft } = contextmenuStore; if (subMenu) { const itemEle = evt.currentTarget as HTMLDivElement; const { left, right, top, bottom, width } = itemEle.getBoundingClientRect(); @@ -210,7 +210,7 @@ export class DuoyunMenuElement extends GemElement { openLeft || (menuStackIndex > 0 && menuStack[menuStackIndex].x < menuStack[menuStackIndex - 1].x)) && left > 300; - updateStore(menuStore, { + updateStore(contextmenuStore, { menuStack: [ ...menuStack.slice(0, menuStackIndex + 1), { @@ -222,7 +222,7 @@ export class DuoyunMenuElement extends GemElement { ], }); } else { - updateStore(menuStore, { + updateStore(contextmenuStore, { menuStack: menuStack.slice(0, menuStackIndex + 1), }); } @@ -238,8 +238,8 @@ export class DuoyunMenuElement extends GemElement { #onKeydown = (evt: KeyboardEvent, menuStackIndex: number) => { evt.stopPropagation(); const focusPrevMenu = () => { - updateStore(menuStore, { - menuStack: menuStore.menuStack.slice(0, menuStackIndex), + updateStore(contextmenuStore, { + menuStack: contextmenuStore.menuStack.slice(0, menuStackIndex), }); this.#menuElements[menuStackIndex - 1]?.focus(); }; @@ -258,7 +258,7 @@ export class DuoyunMenuElement extends GemElement { // await `ContextMenu` content update await Promise.resolve(); const element = this.#menuElements.shift(); - const { activeElement, openLeft, menuStack, maxHeight } = menuStore; + const { activeElement, openLeft, menuStack, maxHeight } = contextmenuStore; const { scrollHeight, clientHeight, clientWidth } = element!; const menu = menuStack[0]; const height = scrollHeight + 2; @@ -269,18 +269,18 @@ export class DuoyunMenuElement extends GemElement { const showToTop = innerHeight - bottom < height + 2 * this.#offset && top > innerHeight - bottom; const x = showToLeft ? right - width : left; const y = showToTop ? Math.max(top - height - 2 * this.#offset, 0) : bottom; - updateStore(menuStore, { + updateStore(contextmenuStore, { maxHeight: maxHeight || `${showToTop ? top - 2 * this.#offset : innerHeight - bottom - 2 * this.#offset}px`, menuStack: [{ ...menu, x, y }], }); } else { const y = innerHeight - menu.y > width ? menu.y : Math.max(0, menu.y - (scrollHeight - clientHeight)); - updateStore(menuStore, { menuStack: [{ ...menu, y }] }); + updateStore(contextmenuStore, { menuStack: [{ ...menu, y }] }); } }; #onMaskClick = () => { - if (menuStore.maskClosable) { + if (contextmenuStore.maskClosable) { ContextMenu.close(); } }; @@ -298,7 +298,7 @@ export class DuoyunMenuElement extends GemElement { }; render = () => { - const { menuStack, maxHeight, maskClosable } = menuStore; + const { menuStack, maxHeight, maskClosable } = contextmenuStore; return html`
${menuStack.map( @@ -358,4 +358,4 @@ export class DuoyunMenuElement extends GemElement { }; } -export const ContextMenu = DuoyunMenuElement; +export const ContextMenu = DuoyunContextMenuElement; diff --git a/packages/duoyun-ui/src/elements/date-picker.ts b/packages/duoyun-ui/src/elements/date-picker.ts index 991bea39..417cc068 100644 --- a/packages/duoyun-ui/src/elements/date-picker.ts +++ b/packages/duoyun-ui/src/elements/date-picker.ts @@ -23,7 +23,7 @@ import { focusStyle } from '../lib/styles'; import type { DuoyunButtonElement } from './button'; import type { DuoyunDatePanelElement } from './date-panel'; -import { ContextMenu } from './menu'; +import { ContextMenu } from './contextmenu'; import { BasePickerElement, pickerStyle } from './picker'; import './use'; diff --git a/packages/duoyun-ui/src/elements/date-range-picker.ts b/packages/duoyun-ui/src/elements/date-range-picker.ts index 13e4be89..c12d2eee 100644 --- a/packages/duoyun-ui/src/elements/date-range-picker.ts +++ b/packages/duoyun-ui/src/elements/date-range-picker.ts @@ -21,7 +21,7 @@ import { commonHandle } from '../lib/hotkeys'; import { focusStyle } from '../lib/styles'; import type { DuoyunButtonElement } from './button'; -import { ContextMenu } from './menu'; +import { ContextMenu } from './contextmenu'; import { BasePickerElement, pickerStyle } from './picker'; import './use'; diff --git a/packages/duoyun-ui/src/elements/picker.ts b/packages/duoyun-ui/src/elements/picker.ts index 0a469549..66d930e7 100644 --- a/packages/duoyun-ui/src/elements/picker.ts +++ b/packages/duoyun-ui/src/elements/picker.ts @@ -17,7 +17,7 @@ import { icons } from '../lib/icons'; import { commonHandle } from '../lib/hotkeys'; import { focusStyle } from '../lib/styles'; -import { ContextMenu, MenuItem } from './menu'; +import { ContextMenu, ContextMenuItem } from './contextmenu'; import './use'; @@ -124,7 +124,7 @@ export class DuoyunPickElement extends GemElement implements BasePickerElement { return this.multiple ? (this.value as any[]).includes(value) : this.value === value; }; - #genMenu = ({ label, description, value, children }: Option): MenuItem => { + #genMenu = ({ label, description, value, children }: Option): ContextMenuItem => { const v = value ?? label; return { text: label, diff --git a/packages/duoyun-ui/src/elements/table.ts b/packages/duoyun-ui/src/elements/table.ts index 93eaa195..791239ed 100644 --- a/packages/duoyun-ui/src/elements/table.ts +++ b/packages/duoyun-ui/src/elements/table.ts @@ -21,7 +21,7 @@ import { commonHandle } from '../lib/hotkeys'; import { focusStyle } from '../lib/styles'; import { DuoyunUseElement } from './use'; -import { MenuItem, ContextMenu } from './menu'; +import { ContextMenuItem, ContextMenu } from './contextmenu'; import type { SelectionChange } from './selection-box'; import './placeholder'; @@ -122,7 +122,7 @@ export type Column = { tooltip?: string; dataIndex?: keyof T | string[]; render?: (record: T) => string | TemplateResult; - getActions?: (record: T, evt: HTMLElement) => MenuItem[]; + getActions?: (record: T, evt: HTMLElement) => ContextMenuItem[]; getColSpan?: (record: T, arr: T[]) => number; getRowSpan?: (record: T, arr: T[]) => number; data?: Record; @@ -224,7 +224,7 @@ export class DuoyunTableElement extends GemElement { }); }; - #openActions = (evt: PointerEvent, menu: MenuItem[]) => { + #openActions = (evt: PointerEvent, menu: ContextMenuItem[]) => { if (evt.target instanceof DuoyunUseElement) { ContextMenu.open(menu, { activeElement: evt.target as HTMLElement, diff --git a/packages/duoyun-ui/src/elements/time-picker.ts b/packages/duoyun-ui/src/elements/time-picker.ts index 95dec94d..1b55507e 100644 --- a/packages/duoyun-ui/src/elements/time-picker.ts +++ b/packages/duoyun-ui/src/elements/time-picker.ts @@ -20,7 +20,7 @@ import { isNotNullish } from '../lib/types'; import { commonHandle } from '../lib/hotkeys'; import { focusStyle } from '../lib/styles'; -import { ContextMenu } from './menu'; +import { ContextMenu } from './contextmenu'; import { BasePickerElement, pickerStyle } from './picker'; import type { DuoyunButtonElement } from './button'; import type { DuoyunTimePanelElement } from './time-panel'; diff --git a/packages/gem-book/docs/en/002-guide/004-metadata.md b/packages/gem-book/docs/en/002-guide/004-metadata.md index 169f362e..5bcb3dbb 100644 --- a/packages/gem-book/docs/en/002-guide/004-metadata.md +++ b/packages/gem-book/docs/en/002-guide/004-metadata.md @@ -13,12 +13,24 @@ sidebarIgnore: true # Markdown title ``` -In addition, the homepage also supports `hero` and `features`, for example: +## Homepage + +The homepage also supports `hero` and `features`, for example: -Full definition: +You can also use `config.yml` to specify metadata for the folder. - +## Redirect -You can also use `config.yml` to specify metadata for the folder. +Use redirects to prevent links from breaking if the document is moved or renamed: + +```md +--- +redirect: ./new.md +--- +``` + +## Definition + + diff --git a/packages/gem-book/docs/en/002-guide/README.md b/packages/gem-book/docs/en/002-guide/README.md index 5858daf9..2a19cf17 100644 --- a/packages/gem-book/docs/en/002-guide/README.md +++ b/packages/gem-book/docs/en/002-guide/README.md @@ -47,7 +47,12 @@ gem-book docs -t MyApp -i logo.png --home-mode --build More [options](./003-cli.md). -### Use `` +
+ + +Use `` + + The above command uses `webpack` to package a complete front-end project, but you can also use the `` element directly in HTML. @@ -71,6 +76,8 @@ render(html``, document.body); You can use the `` element in any framework. +
+ ### Rendering rules The command line tool directly maps the directory structure to the sidebar structure. The level 1 and level 2 titles in the document will be used as the titles of the links in the sidebar. If there is no first-level title, the file name will be used. diff --git a/packages/gem-book/docs/zh/002-guide/004-metadata.md b/packages/gem-book/docs/zh/002-guide/004-metadata.md index 84abb91d..e66d3abf 100644 --- a/packages/gem-book/docs/zh/002-guide/004-metadata.md +++ b/packages/gem-book/docs/zh/002-guide/004-metadata.md @@ -13,12 +13,24 @@ sidebarIgnore: true # Markdown 标题 ``` -此外,首页还支持 `hero` `features`,例如: +## 首页 + +首页还支持 `hero` `features`,例如: -完整定义: +你也可以使用 `config.yml` 为文件夹指定元数据。 - +## 重定向 -你也可以使用 `config.yml` 为文件夹指定元数据。 +如果文档移动或者重命名,可以使用重定向防止链接失效: + +```md +--- +redirect: ./new.md +--- +``` + +## 完整定义 + + diff --git a/packages/gem-book/docs/zh/002-guide/README.md b/packages/gem-book/docs/zh/002-guide/README.md index 4ed87eb4..98859bd5 100644 --- a/packages/gem-book/docs/zh/002-guide/README.md +++ b/packages/gem-book/docs/zh/002-guide/README.md @@ -45,7 +45,12 @@ gem-book docs -t MyApp -i logo.png --home-mode --build 更多参数请查看[选项](./003-cli.md)。 -### 使用 `` +
+ + +使用 `` 元素 + + 上面的命令使用 `webpack` 打包完整的前端项目,但你也可以直接在 HTML 中使用 `` 元素。 @@ -69,6 +74,8 @@ render(html``, document.body); 你可以在任何框架中使用 `` 元素。 +
+ ### 渲染规则 命令行工具会将目录结构直接映射成侧边栏结构。文档中的一级标题和二级标题会作为侧边栏的链接的标题,没有一级标题时会使用文件名。 diff --git a/packages/gem-book/package.json b/packages/gem-book/package.json index b63764b9..f8e819e2 100644 --- a/packages/gem-book/package.json +++ b/packages/gem-book/package.json @@ -1,6 +1,6 @@ { "name": "gem-book", - "version": "1.5.18", + "version": "1.5.19", "description": "Create your document website easily and quickly", "keywords": [ "doc", diff --git a/packages/gem-book/src/bin/index.ts b/packages/gem-book/src/bin/index.ts index 2295cad7..9ccc42cc 100644 --- a/packages/gem-book/src/bin/index.ts +++ b/packages/gem-book/src/bin/index.ts @@ -116,9 +116,16 @@ function readDir(dir: string, link = '/') { sidebarIgnore, hero, features, + redirect, } = getMetadata(fullPath, bookConfig.displayRank); Object.assign(item, { title, children, isNav, navTitle, sidebarIgnore, hero, features }); - result.push(item); + if (redirect) { + bookConfig.redirects = Object.assign(bookConfig.redirects || {}, { + [item.link]: new URL(redirect, `file:${item.link}`).pathname, + }); + } else { + result.push(item); + } } } else { item.type = 'dir'; diff --git a/packages/gem-book/src/common/config.ts b/packages/gem-book/src/common/config.ts index 905f1b9a..6b151e37 100644 --- a/packages/gem-book/src/common/config.ts +++ b/packages/gem-book/src/common/config.ts @@ -27,6 +27,7 @@ interface CommonConfig { } export type BookConfig = { + redirects: Record; sidebar: SidebarConfig; // navbar icon absolute path icon?: string; diff --git a/packages/gem-book/src/common/frontmatter.ts b/packages/gem-book/src/common/frontmatter.ts index c85d2d2e..ac05c13e 100644 --- a/packages/gem-book/src/common/frontmatter.ts +++ b/packages/gem-book/src/common/frontmatter.ts @@ -11,6 +11,7 @@ export interface Feature { } export interface FrontMatter { + redirect?: string; title?: string; isNav?: boolean; navTitle?: string; diff --git a/packages/gem-book/src/element/elements/main.ts b/packages/gem-book/src/element/elements/main.ts index 1797d725..75267d1b 100644 --- a/packages/gem-book/src/element/elements/main.ts +++ b/packages/gem-book/src/element/elements/main.ts @@ -58,6 +58,9 @@ const style = createCSSSheet(css` margin: -0.5em -1em; padding: 0.5em 1em; } + summary p { + display: contents; + } summary:hover { background: rgba(${theme.textColorRGB}, 0.02); } diff --git a/packages/gem-book/src/element/store.ts b/packages/gem-book/src/element/store.ts index 89ab68cb..80a43281 100644 --- a/packages/gem-book/src/element/store.ts +++ b/packages/gem-book/src/element/store.ts @@ -108,7 +108,22 @@ function getNavRoutes(nav: NavItem[]): RouteItem[] { .map(({ link, children }) => ({ pattern: link, redirect: children?.[0].link })); } -function getRouter(links: NavItemWithLink[], title: string, lang: string, displayRank: boolean | undefined) { +function getRedirectRoutes(redirects: Record, displayRank?: boolean): RouteItem[] { + const list = Object.entries(redirects); + return list + .map(([link, redirect]) => ({ + pattern: getLinkPath(link, true), + redirect: getLinkPath(redirect, displayRank), + })) + .concat( + list.map(([link, redirect]) => ({ + pattern: getLinkPath(link, false), + redirect: getLinkPath(redirect, displayRank), + })), + ); +} + +function getLinkRouters(links: NavItemWithLink[], title: string, lang: string, displayRank?: boolean) { const routes: RouteItem[] = []; links.forEach((item) => { const { title: pageTitle, link, userFullPath, originLink, hash } = item; @@ -204,12 +219,16 @@ function getHomePage(links: RouteItem[]) { return link.redirect || link.pattern; } -export function updateBookConfig(config: BookConfig | undefined, gemBookElement?: GemBookElement) { +export function updateBookConfig(config?: BookConfig, gemBookElement?: GemBookElement) { const { sidebar, lang, langList, languagechangeHandle } = getI18nSidebar(config); const sidebarResult = processSidebar(sidebar, config?.displayRank); const links = flatNav(sidebarResult); const nav = getNav(sidebarResult, config?.nav || []); - const routes = [...getNavRoutes(nav), ...getRouter(links, config?.title || '', lang, config?.displayRank)]; + const routes = [ + ...getRedirectRoutes(config?.redirects || {}, config?.displayRank), + ...getNavRoutes(nav), + ...getLinkRouters(links, config?.title || '', lang, config?.displayRank), + ]; const currentSidebar = getCurrentSidebar(sidebarResult); const homePage = getHomePage(routes); const currentLinks = flatNav(currentSidebar).filter( diff --git a/packages/gem-examples/package.json b/packages/gem-examples/package.json index a351dbd4..1a0647c0 100644 --- a/packages/gem-examples/package.json +++ b/packages/gem-examples/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@mantou/gem": "^1.7.1", - "duoyun-ui": "^1.0.2" + "duoyun-ui": "^1.1.0" }, "devDependencies": { "@gemjs/config": "^1.6.11", diff --git a/packages/gem-examples/src/tree/index.ts b/packages/gem-examples/src/tree/index.ts index a6b0e669..2a8d1d8e 100644 --- a/packages/gem-examples/src/tree/index.ts +++ b/packages/gem-examples/src/tree/index.ts @@ -1,6 +1,6 @@ import { connect, createStore, html, render, updateStore } from '@mantou/gem'; import type { MouseEventDetail, TreeItem } from 'duoyun-ui/elements/tree'; -import { ContextMenu } from 'duoyun-ui/elements/menu'; +import { ContextMenu } from 'duoyun-ui/elements/contextmenu'; import { sleep } from 'duoyun-ui/lib/utils'; import 'duoyun-ui/elements/tree';