Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
See #121
  • Loading branch information
mantou132 committed Apr 18, 2024
1 parent 4984a06 commit 4d4b993
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 93 deletions.
73 changes: 71 additions & 2 deletions packages/duoyun-ui/docs/en/01-guide/60-integrate.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,81 @@ However, there is no [type hint](https://code.visualstudio.com/docs/editor/intel
## React

> [!NOTE]
> Only the experimental version of React supports custom elements. Use `npm install react@experimental react-dom@experimental` to install the experimental version of React.
> Only the React 19 supports custom elements. Use `npm install react@canary react-dom@canary` to install the React 19.
Use DuoyunUI like any other React component library:

<gbp-raw range="import DyCard,<DyCard-</DyCard>" src="https://raw.githubusercontent.com/mantou132/nextjs-learn/main/pages/ce-test.tsx"></gbp-raw>

### Use React Component in `<dy-route>`

`<dy-route>` only supports rendering `TemplateResult`:

```ts
const routes = {
about: {
pattern: '/about',
title: `About`,
getContent(_, ele) {
return html`<p-about></p-about>`;
},
},
} satisfies RoutesObject;
```

To render the React component, need to manually mount it onto the `<dy-route>`:

```ts
function renderReactNode(ele: any, node: ReactNode) {
ele.react?.unmount();
ele.react = createRoot(ele);
ele.react.render(node);
}

const routes = {
about: {
pattern: '/about',
title: `About`,
getContent(_, ele) {
renderReactNode(ele, <About />);
},
},
} satisfies RoutesObject;
```

### Using the React component as Property

Some elements support custom rendering content, such as the `header` of `<dy-card>`:

```ts
function Page() {
return <DyCard header={html`<div>No.</div>`}></DyCard>;
}
```

If want to render the React component, need to first mount it to the `HTMLElement`, which can be achieved through custom Hooks:

```tsx
function useReactNode(node: ReactNode) {
const ref = useRef<{ root: Root; container: HTMLElement }>();
useEffect(() => () => ref.current?.root.unmount(), []);
if (ref.current) {
ref.current.root.render(node);
return ref.current.container;
}
const container = document.createElement('div');
container.style.display = 'contents';
const root = createRoot(container);
ref.current = { root, container };
root.render(node);
return container;
}

function Page() {
return <DyCard header={useReactNode(<>No</>)}></DyCard>;
}
```

## Vue

DuoyunUI also exports Vue components, which are used the same as React. The only difference is that the path is changed from `react` to `vue`,
Expand All @@ -33,7 +102,7 @@ In the Vue project, it also supports directly writing custom elements, but [dist

DuoyunUI does not re-export as a Svelte component, and you can use the custom element directly:

<gbp-raw codelang="html" range="2-9,46-57" src="https://raw.githubusercontent.com/mantou132/sveltekit-learn/main/src/routes/ce-test/+page.svelte"></gbp-raw>
<gbp-raw codelang="html" range="2-9,44-55" src="https://raw.githubusercontent.com/mantou132/sveltekit-learn/main/src/routes/ce-test/+page.svelte"></gbp-raw>

> [!NOTE]
> Use the `Sveltekit`, please make sure the `Svelte` is installed as a `dependencies` instead of `DevDependenCies`, otherwise the type cannot be import successfully;
Expand Down
73 changes: 71 additions & 2 deletions packages/duoyun-ui/docs/zh/01-guide/60-integrate.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,81 @@
## React

> [!NOTE]
> React 的实验版才支持自定义元素,使用 `npm install react@experimental react-dom@experimental` 安装 React 实验版
> React 19 才支持自定义元素,当前使用 `npm install react@canary react-dom@canary` 安装 React 19
跟使用其他 React 组件库一样使用 DuoyunUI:

<gbp-raw range="import DyCard,<DyCard-</DyCard>" src="https://raw.githubusercontent.com/mantou132/nextjs-learn/main/pages/ce-test.tsx"></gbp-raw>

### `<dy-route>` 中使用 React 组件

`<dy-route>` 只支持渲染 `TemplateResult`

```ts
const routes = {
about: {
pattern: '/about',
title: `About`,
getContent(_, ele) {
return html`<p-about></p-about>`;
},
},
} satisfies RoutesObject;
```

要渲染 React 组件需要手动挂载到 `<dy-route>` 上:

```ts
function renderReactNode(ele: any, node: ReactNode) {
ele.react?.unmount();
ele.react = createRoot(ele);
ele.react.render(node);
}

const routes = {
about: {
pattern: '/about',
title: `About`,
getContent(_, ele) {
renderReactNode(ele, <About />);
},
},
} satisfies RoutesObject;
```

### 在 Property 上使用 React 组件

一些元素支持自定义渲染内容,例如 `<dy-card>``header`

```ts
function Page() {
return <DyCard header={html`<div>No.</div>`}></DyCard>;
}
```

如果要渲染 React 组件,则需要先渲染到 `HTMLElement` 上,可以通过自定义 Hooks 实现:

```tsx
function useReactNode(node: ReactNode) {
const ref = useRef<{ root: Root; container: HTMLElement }>();
useEffect(() => () => ref.current?.root.unmount(), []);
if (ref.current) {
ref.current.root.render(node);
return ref.current.container;
}
const container = document.createElement('div');
container.style.display = 'contents';
const root = createRoot(container);
ref.current = { root, container };
root.render(node);
return container;
}

function Page() {
return <DyCard header={useReactNode(<>No</>)}></DyCard>;
}
```

## Vue

DuoyunUI 也导出了 Vue 组件,使用和 React 一样,唯一的区别是路径将 `react` 改成 `vue`
Expand All @@ -33,7 +102,7 @@ DuoyunUI 也导出了 Vue 组件,使用和 React 一样,唯一的区别是

DuoyunUI 没有重导出为 Svelte 组件,直接使用自定义元素即可:

<gbp-raw codelang="html" range="2-9,46-57" src="https://raw.githubusercontent.com/mantou132/sveltekit-learn/main/src/routes/ce-test/+page.svelte"></gbp-raw>
<gbp-raw codelang="html" range="2-9,44-55" src="https://raw.githubusercontent.com/mantou132/sveltekit-learn/main/src/routes/ce-test/+page.svelte"></gbp-raw>

> [!NOTE]
> 使用 `SvelteKit` 请确保 `svelte` 安装成 `dependencies` 而非 `devDependencies`,否则类型不能成功导入;
Expand Down
3 changes: 2 additions & 1 deletion packages/duoyun-ui/src/elements/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const style = createCSSSheet(css`
.actions:where(:hover, [data-active], :state(active)) {
background-color: ${theme.hoverBackgroundColor};
}
slot[name='body']::slotted(*) {
slot[name='body']::slotted(*),
slot:not([name])::slotted(*) {
hyphens: auto;
margin-block-end: 0em !important;
}
Expand Down
73 changes: 43 additions & 30 deletions packages/duoyun-ui/src/elements/code-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,15 @@ export class DuoyunCodeBlockElement extends GemElement {

@refobject codeRef: RefObject<HTMLElement>;

constructor() {
super();
new MutationObserver(() => this.update()).observe(this, {
childList: true,
characterData: true,
subtree: true,
});
}

#getRanges(range: string) {
const ranges = range.split(/,\s*/);
return ranges.map((range) => {
Expand All @@ -356,37 +365,41 @@ export class DuoyunCodeBlockElement extends GemElement {
return parts.join('\n...\n\n');
}

#updateHtml = async () => {
if (!this.codeRef.element) return;
await import(/* @vite-ignore */ /* webpackIgnore: true */ prismjs);
const { Prism } = window as any;
if (this.codelang && !Prism.languages[this.codelang]) {
const codelang = langAliases[this.codelang] || this.codelang;
const langDeps = ([] as string[]).concat(langDependencies[codelang] || []);
const load = (lang: string) =>
import(/* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${lang}.min.js`);
try {
await Promise.all(langDeps.map((langDep) => !Prism.languages[langDep] && load(langDep)));
await load(codelang);
} catch {
//
}
}
const html = Prism.languages[this.codelang]
? Prism.highlight(this.textContent || '', Prism.languages[this.codelang], this.codelang)
: this.innerHTML;
this.codeRef.element.innerHTML = this.#getParts(html);
};

mounted() {
this.effect(
async () => {
if (!this.codeRef.element) return;
await import(/* @vite-ignore */ /* webpackIgnore: true */ prismjs);
const { Prism } = window as any;
if (this.codelang && !Prism.languages[this.codelang]) {
const lang = langAliases[this.codelang] || this.codelang;
const langDeps = ([] as string[]).concat(langDependencies[lang] || []);
try {
await Promise.all(
langDeps.map((langDep) => {
if (!Prism.languages[langDep]) {
return import(
/* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${langDep}.min.js`
);
}
}),
);
await import(/* @vite-ignore */ /* webpackIgnore: true */ `${prismjs}/components/prism-${lang}.min.js`);
} catch {
//
}
}
const content = Prism.languages[this.codelang]
? Prism.highlight(this.textContent || '', Prism.languages[this.codelang], this.codelang)
: this.innerHTML;
this.codeRef.element.innerHTML = this.#getParts(content);
},
() => [],
);
const io = new IntersectionObserver((entries) => {
entries.forEach(({ intersectionRatio }) => {
if (intersectionRatio === 0) return;
io.disconnect();
this.effect(
() => this.#updateHtml(),
() => [this.textContent, this.codelang],
);
});
});
io.observe(this);
return () => io.disconnect();
}

render() {
Expand Down
1 change: 1 addition & 0 deletions packages/duoyun-ui/src/elements/input-capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const style = createCSSSheet(css`
text-align: center;
white-space: nowrap;
background: rgba(0, 0, 0, calc(${theme.maskAlpha} + 0.4));
line-height: 2;
}
.kbd {
background: transparent;
Expand Down
57 changes: 25 additions & 32 deletions packages/duoyun-ui/src/elements/paragraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,31 @@ const style = createCSSSheet(css`
:where(dy-paragraph):where(:lang(zh), :lang(ja), :lang(kr)) {
line-height: 1.7;
}
:where(gem-link, dy-link):where(:not([hidden])) {
display: inline-block;
color: ${theme.primaryColor};
text-decoration: underline;
}
:where(gem-link, dy-link):where(:lang(zh), :lang(ja), :lang(kr)) {
text-underline-offset: 0.125em;
}
ul,
ol {
margin-block: 0 1em;
padding: 0;
list-style-position: inside;
}
li {
padding-inline-start: 0.5em;
}
code,
kbd {
font-family: ${theme.codeFont};
margin-inline: 0.2em;
padding: 0.15em 0.4em 0.1em;
font-size: 0.9em;
border: 1px solid ${theme.borderColor};
border-radius: ${theme.smallRound};
}
code {
background: ${theme.hoverBackgroundColor};
}
kbd {
background: ${theme.lightBackgroundColor};
border-bottom-width: 2px;
:where(dy-paragraph) {
:where(gem-link, dy-link):where(:not([hidden])) {
display: inline-block;
color: ${theme.primaryColor};
text-decoration: underline;
}
:where(gem-link, dy-link):where(:lang(zh), :lang(ja), :lang(kr)) {
text-underline-offset: 0.125em;
}
code,
kbd {
font-family: ${theme.codeFont};
margin-inline: 0.2em;
padding: 0.15em 0.4em 0.1em;
font-size: 0.9em;
border: 1px solid ${theme.borderColor};
border-radius: ${theme.smallRound};
}
code {
background: ${theme.hoverBackgroundColor};
}
kbd {
background: ${theme.lightBackgroundColor};
border-bottom-width: 2px;
}
}
`);

Expand Down
4 changes: 4 additions & 0 deletions packages/duoyun-ui/src/elements/space.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const style = createCSSSheet(css`
align-items: center;
gap: 0.4em;
}
:where(dy-space[orientation='vertical']) {
flex-direction: column;
}
:where(dy-space[size='small']) {
gap: 0.2em;
}
Expand All @@ -25,6 +28,7 @@ const style = createCSSSheet(css`
@adoptedStyle(style)
export class DuoyunSpaceElement extends GemElement {
@attribute size: 'normal' | 'small' | 'large';
@attribute orientation: 'horizontal' | 'vertical';

constructor() {
super({ isLight: true });
Expand Down
18 changes: 18 additions & 0 deletions packages/gem-examples/src/console/dynamic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { html, GemElement } from '@mantou/gem/lib/element';
import { connectStore, customElement } from '@mantou/gem/lib/decorators';
import { locationStore } from 'duoyun-ui/patterns/console';

import 'duoyun-ui/elements/code-block';
import 'duoyun-ui/elements/heading';
import 'duoyun-ui/elements/title';

@customElement('console-page-dynamic')
@connectStore(locationStore)
export class ConsolePageDynamicElement extends GemElement {
render = () => {
return html`
<dy-heading style="margin-block: 0 1em"><dy-title inert></dy-title></dy-heading>
<dy-code-block codelang="json">${JSON.stringify(locationStore.params, null, 2)}</dy-code-block>
`;
};
}
2 changes: 1 addition & 1 deletion packages/gem-examples/src/console/home.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class ConsolePageHomeElement extends GemElement {
const text = `Current Path: ${locationStore.path}`;
return html`
<dy-heading style="margin-block: 0 1em"><dy-title inert></dy-title></dy-heading>
<dy-code-block .textContent=${text}></dy-code-block>
<dy-code-block codelang="yaml" .textContent=${text}></dy-code-block>
`;
};
}
Loading

0 comments on commit 4d4b993

Please sign in to comment.