diff --git a/packages/site/.gitignore b/packages/site/.gitignore index 18ccb9f7..30f44df4 100644 --- a/packages/site/.gitignore +++ b/packages/site/.gitignore @@ -3,4 +3,5 @@ src/app/configs/* src/app/i18n/resources.json -src/app/routes/components/ +src/app/routes/components/* +!src/app/routes/components/*.md diff --git a/packages/site/src/app/components/route/DemoBox.scss b/packages/site/src/app/components/route/DemoBox.scss deleted file mode 100644 index 07e857a2..00000000 --- a/packages/site/src/app/components/route/DemoBox.scss +++ /dev/null @@ -1,84 +0,0 @@ -@import '~rfs/scss'; - -.app-demo-box { - border: 1px solid var(--d-divider-color); - - &.is-active { - border-color: var(--d-color-primary); - } - - @include font-size(1rem); - - & + & { - margin-top: 24px; - } - - .app-demo-box__renderer { - padding: 42px 24px; - overflow-x: auto; - } - - .app-demo-box__info { - position: relative; - - border-top: 1px solid var(--d-divider-color); - } - - .app-demo-box__title { - position: absolute; - top: -14px; - left: 16px; - - padding: 1px 8px; - - background-color: var(--d-background-color); - } - - .app-demo-box__description { - padding: 24px; - } - - .app-demo-box__toolbar { - display: flex; - justify-content: center; - width: 100%; - padding: 12px 0; - border-top: 1px dashed var(--d-divider-color); - - .icon-button { - color: var(--d-color-step-300); - - transition: color 0.1s linear, transform 0.1s linear; - - &:hover { - color: var(--d-color-primary); - - transform: scale(1.2); - } - - &:nth-of-type(2) { - margin-left: 12px; - } - - &:nth-of-type(3) { - margin-left: 10px; - } - - &:nth-of-type(4) { - margin-left: 12px; - } - } - } - - .app-demo-box__code { - border-top: 1px dashed var(--d-divider-color); - - pre { - margin: 0; - } - - pre code.hljs { - padding: 24px; - } - } -} diff --git a/packages/site/src/app/components/route/RouteArticle.scss b/packages/site/src/app/components/route/RouteArticle.scss index f445a79e..842602e4 100644 --- a/packages/site/src/app/components/route/RouteArticle.scss +++ b/packages/site/src/app/components/route/RouteArticle.scss @@ -1,6 +1,6 @@ @import '~rfs/scss'; -.app-route__anchor { +.app-route-article__anchor { position: fixed; top: 120px; right: 20px; @@ -13,7 +13,7 @@ } } -.app-route__anchor-conatiner { +.app-route-article__anchor-conatiner { position: fixed; right: 0; bottom: 0; @@ -27,7 +27,7 @@ background-color: var(--d-background-color); } -.app-route__anchor-button { +.app-route-article__anchor-button { position: fixed; right: 20px; bottom: 44px; @@ -49,169 +49,3 @@ appearance: none; } - -.app-route-article { - code { - word-break: break-all; - } - - pre > code { - font-family: Consolas, Menlo, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - } - - pre code.hljs { - background-color: var(--app-code-background-color); - } - - code:not(pre > code) { - margin: 0 1px; - padding: 4px 6px; - border-radius: 3px; - - font-family: Consolas, Menlo, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - - background-color: var(--app-code-background-color); - } - - a:not(.app-demo-box__renderer a) { - color: var(--d-color-primary); - text-decoration: none; - - &:hover { - color: var(--d-color-primary-lighter); - } - } - - h1 { - margin: 8px 0 20px; - - font-weight: 500; - @include font-size(2rem); - } - - h2 { - margin: 38px 0 20px; - - font-weight: 500; - @include font-size(1.5rem); - } - - h3 { - margin: 28px 0 12px; - - font-weight: 500; - @include font-size(1.25rem); - } - - table { - width: 100%; - margin: 8px 0 16px; - border: 1px solid var(--d-border-color); - border-collapse: collapse; - border-spacing: 0; - - empty-cells: show; - - th { - font-weight: 500; - white-space: nowrap; - - background: var(--app-th-background-color); - } - - th, - td { - padding: 16px 24px; - border: 1px solid var(--d-divider-color); - - text-align: left; - } - } - - .anchor { - display: inline-block; - margin-left: 8px; - - color: var(--d-color-primary); - text-decoration: none; - - opacity: 0; - - transition: opacity 0.2s linear; - - &:focus-visible { - outline: none; - opacity: 1; - } - } - - h1, - h2, - h3, - h4, - h5, - h6 { - &:hover .anchor { - opacity: 1; - } - } - - .icon-button { - color: var(--d-color-step-400); - - cursor: pointer; - - transition: color 0.1s linear; - - &:hover { - color: var(--d-color-primary); - } - } - - .app-route-article__subtitle { - margin-left: 12px; - } - - .app-route-article__demos { - pre code.hljs { - background-color: transparent; - } - } - - .app-route-article__api { - .app-table-container { - width: 100%; - overflow-x: auto; - } - - table { - min-width: 1200px; - - table-layout: fixed; - - th:nth-of-type(1) { - width: 260px; - - white-space: nowrap; - } - - th:nth-of-type(2) { - width: calc(100% - 720px); - } - - th:nth-of-type(3) { - width: 300px; - } - - th:nth-of-type(4) { - width: 160px; - } - - td:nth-of-type(1), - td:nth-of-type(3), - td:nth-of-type(4) { - font-family: Consolas, Menlo, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - } - } - } -} diff --git a/packages/site/src/app/components/route/RouteArticle.tsx b/packages/site/src/app/components/route/RouteArticle.tsx index 5f0adfce..d81a9f97 100644 --- a/packages/site/src/app/components/route/RouteArticle.tsx +++ b/packages/site/src/app/components/route/RouteArticle.tsx @@ -1,29 +1,23 @@ -import { useTranslation } from 'react-i18next'; +import { isUndefined } from 'lodash'; +import { useEffect } from 'react'; -import { DTooltip, DIcon, DAnchor, DAnchorLink, DRow } from '@react-devui/ui'; +import { DIcon, DAnchor, DAnchorLink, DRow } from '@react-devui/ui'; import { DTransition } from '@react-devui/ui/components/_transition'; import { useImmer, useRefCallback } from '@react-devui/ui/hooks'; import './RouteArticle.scss'; -import { toString } from './utils'; +import { toString } from './component/utils'; export interface AppRouteArticleProps { - title: string; - subtitle: string; - description: number[]; - api: number[]; - demos: React.ReactNode; - links: Array<{ href: string; title: string }>; + html?: number[]; + links?: Array<{ href: string; title: string }>; + children?: React.ReactNode; } export function AppRouteArticle(props: AppRouteArticleProps) { - const { title, subtitle, demos, links } = props; - - const description = toString(props.description); - const api = toString(props.api); - - const { t, i18n } = useTranslation(); + const html = props.html ? toString(props.html) : undefined; + const [links, setLinks] = useImmer>(props.links ?? []); const [menuOpen, setMenuOpen] = useImmer(false); const [el, ref] = useRefCallback(); @@ -59,20 +53,31 @@ m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, 'leave-to': { opacity: '0', transform: 'translateY(120px)', transition: 'opacity 0.2s linear, transform 0.2s ease-out' }, }; + useEffect(() => { + if (isUndefined(props.links)) { + const arr: Array<{ href: string; title: string }> = []; + document.querySelectorAll('.app-route-article h2').forEach((el) => { + arr.push({ href: '#' + el.id, title: el.id }); + }); + setLinks(arr); + return () => { + setLinks([]); + }; + } + }, [props.links, setLinks]); + return ( ( <> - {matchs.includes('md') && ( - - {links && - links.map((link) => ( - - {link.title} - - ))} - API + {matchs.includes('md') && links.length > 0 && ( + + {links.map((link) => ( + + {link.title} + + ))} )} {!matchs.includes('md') && ( @@ -84,51 +89,30 @@ m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, beforeEnter: () => transitionState, beforeLeave: () => transitionState, }} - dRender={(hidden) => ( - + ) + } > -
setMenuOpen(!menuOpen)}> +
setMenuOpen(!menuOpen)}> {icon(true)} {icon(false)}
)} -
-

- {title} - {i18n.language !== 'en-US' && {subtitle}} - - - - - -

-
-

- {t('Examples')} - - - - - -

-
{demos}
-
+
+ {props.children}
)} diff --git a/packages/site/src/app/components/route/component/ComponentRoute.tsx b/packages/site/src/app/components/route/component/ComponentRoute.tsx new file mode 100644 index 00000000..dcdaa326 --- /dev/null +++ b/packages/site/src/app/components/route/component/ComponentRoute.tsx @@ -0,0 +1,11 @@ +import type { AppComponentRouteArticleProps } from './ComponentRouteArticle'; + +import { useTranslation } from 'react-i18next'; + +import { AppComponentRouteArticle } from './ComponentRouteArticle'; + +export function AppComponentRoute(props: { 'en-US': AppComponentRouteArticleProps; 'zh-Hant': AppComponentRouteArticleProps }) { + const { i18n } = useTranslation(); + + return ; +} diff --git a/packages/site/src/app/components/route/component/ComponentRouteArticle.scss b/packages/site/src/app/components/route/component/ComponentRouteArticle.scss new file mode 100644 index 00000000..100a199e --- /dev/null +++ b/packages/site/src/app/components/route/component/ComponentRouteArticle.scss @@ -0,0 +1,11 @@ +@import '~rfs/scss'; + +.app-component-route-article__subtitle { + margin-left: 12px; +} + +.app-component-route-article__demos { + pre code.hljs { + background-color: transparent; + } +} diff --git a/packages/site/src/app/components/route/component/ComponentRouteArticle.tsx b/packages/site/src/app/components/route/component/ComponentRouteArticle.tsx new file mode 100644 index 00000000..43e9faba --- /dev/null +++ b/packages/site/src/app/components/route/component/ComponentRouteArticle.tsx @@ -0,0 +1,50 @@ +import { useTranslation } from 'react-i18next'; + +import { DTooltip, DIcon } from '@react-devui/ui'; + +import { AppRouteArticle } from '../RouteArticle'; +import './ComponentRouteArticle.scss'; +import { toString } from './utils'; + +export interface AppComponentRouteArticleProps { + title: string; + subtitle: string; + description: number[]; + api: number[]; + demos: React.ReactNode; + links: Array<{ href: string; title: string }>; +} + +export function AppComponentRouteArticle(props: AppComponentRouteArticleProps) { + const { title, subtitle, demos, links } = props; + + const description = toString(props.description); + const api = toString(props.api); + + const { t, i18n } = useTranslation(); + + return ( + +

+ {title} + {i18n.language !== 'en-US' && {subtitle}} + + + + + +

+
+

+ {t('Examples')} + + + + + +

+
{demos}
+
+ + ); +} diff --git a/packages/site/src/app/components/route/component/DemoBox.scss b/packages/site/src/app/components/route/component/DemoBox.scss new file mode 100644 index 00000000..65a6982a --- /dev/null +++ b/packages/site/src/app/components/route/component/DemoBox.scss @@ -0,0 +1,84 @@ +@import '~rfs/scss'; + +.app-demo-box { + border: 1px solid var(--d-divider-color); + + &.is-active { + border-color: var(--d-color-primary); + } + + @include font-size(1rem); + + & + & { + margin-top: 24px; + } +} + +.app-demo-box__renderer { + padding: 42px 24px; + overflow-x: auto; +} + +.app-demo-box__info { + position: relative; + + border-top: 1px solid var(--d-divider-color); +} + +.app-demo-box__title { + position: absolute; + top: -14px; + left: 16px; + + padding: 1px 8px; + + background-color: var(--d-background-color); +} + +.app-demo-box__description { + padding: 24px; +} + +.app-demo-box__toolbar { + display: flex; + justify-content: center; + width: 100%; + padding: 12px 0; + border-top: 1px dashed var(--d-divider-color); + + .app-icon-button { + color: var(--d-color-step-300); + + transition: color 0.1s linear, transform 0.1s linear; + + &:hover { + color: var(--d-color-primary); + + transform: scale(1.2); + } + + &:nth-of-type(2) { + margin-left: 12px; + } + + &:nth-of-type(3) { + margin-left: 10px; + } + + &:nth-of-type(4) { + margin-left: 12px; + } + } +} + +.app-demo-box__code { + border-top: 1px dashed var(--d-divider-color); + + pre { + margin: 0; + } + + pre code.hljs { + padding: 24px; + } +} diff --git a/packages/site/src/app/components/route/DemoBox.tsx b/packages/site/src/app/components/route/component/DemoBox.tsx similarity index 92% rename from packages/site/src/app/components/route/DemoBox.tsx rename to packages/site/src/app/components/route/component/DemoBox.tsx index 8086f1b2..11b55255 100644 --- a/packages/site/src/app/components/route/DemoBox.tsx +++ b/packages/site/src/app/components/route/component/DemoBox.tsx @@ -80,7 +80,7 @@ export function AppDemoBox(props: AppDemoBoxProps) {
{title} - + @@ -89,17 +89,17 @@ export function AppDemoBox(props: AppDemoBoxProps) {
- + - + - + {copyCode ? ( ) : ( @@ -108,7 +108,7 @@ export function AppDemoBox(props: AppDemoBoxProps) { - + {openCode ? ( ) : ( diff --git a/packages/site/src/app/components/route/component/index.ts b/packages/site/src/app/components/route/component/index.ts new file mode 100644 index 00000000..d0d78bc3 --- /dev/null +++ b/packages/site/src/app/components/route/component/index.ts @@ -0,0 +1,3 @@ +export * from './DemoBox'; +export * from './ComponentRoute'; +export * from './ComponentRouteArticle'; diff --git a/packages/site/src/app/components/route/utils.ts b/packages/site/src/app/components/route/component/utils.ts similarity index 100% rename from packages/site/src/app/components/route/utils.ts rename to packages/site/src/app/components/route/component/utils.ts diff --git a/packages/site/src/app/components/route/index.ts b/packages/site/src/app/components/route/index.ts index 1df1e30a..b7cabe93 100644 --- a/packages/site/src/app/components/route/index.ts +++ b/packages/site/src/app/components/route/index.ts @@ -1,2 +1,3 @@ -export * from './DemoBox'; +export * from './component'; export * from './Route'; +export * from './RouteArticle'; diff --git a/packages/site/src/app/components/sidebar/Sidebar.scss b/packages/site/src/app/components/sidebar/Sidebar.scss index d921b6dd..de918425 100644 --- a/packages/site/src/app/components/sidebar/Sidebar.scss +++ b/packages/site/src/app/components/sidebar/Sidebar.scss @@ -7,7 +7,7 @@ width: 260px; height: calc(100% - 64px); - padding: 20px 0; + padding: 0; overflow: auto; &::after { diff --git a/packages/site/src/app/components/sidebar/Sidebar.tsx b/packages/site/src/app/components/sidebar/Sidebar.tsx index c4ea8c9b..2439ce0d 100644 --- a/packages/site/src/app/components/sidebar/Sidebar.tsx +++ b/packages/site/src/app/components/sidebar/Sidebar.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; -import { DDrawer, DDrawerHeader, DMenu, DMenuGroup, DMenuItem, DRow } from '@react-devui/ui'; +import { DDrawer, DDrawerHeader, DMenu, DMenuGroup, DMenuItem, DRow, DSeparator } from '@react-devui/ui'; import { useCustomContext, useImmer } from '@react-devui/ui/hooks'; import { AppContext } from '../../App'; @@ -26,28 +26,39 @@ export function AppSidebar() { setActiveId(child.title); } }); + + if (to === '/components/Interface') { + setActiveId('Interface'); + } } }, [pageMounted, setActiveId]); + const menuNode = ( + onMenuOpenChange?.(false)}> + {menu.map((group) => ( + + {group.children.map((child) => ( + navigate(child.to, { replace: true })}> + {child.title} + {i18n.language !== 'en-US' && {t(`menu.${child.title}`)}} + + ))} + + ))} + + navigate('/components/Interface', { replace: true })}> + Interface + {i18n.language !== 'en-US' && {t(`Documentation.Interface`)}} + + + ); + return ( matchs.includes('md') ? ( - + ) : ( onMenuOpenChange?.(false)} > - onMenuOpenChange?.(false)}> - {menu.map((group) => ( - - {group.children.map((child) => ( - navigate(child.to, { replace: true })}> - {child.title} - {i18n.language !== 'en-US' && {t(`menu.${child.title}`)}} - - ))} - - ))} - + {menuNode} ) } diff --git a/packages/site/src/app/routes/Routes.tsx b/packages/site/src/app/routes/Routes.tsx index 943fc21b..bb93439a 100644 --- a/packages/site/src/app/routes/Routes.tsx +++ b/packages/site/src/app/routes/Routes.tsx @@ -1,7 +1,8 @@ -import React, { Suspense } from 'react'; +import React, { lazy, Suspense } from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; import { ComponentRoutes } from './components/routes'; +const ComponentInterfaceRoute = lazy(() => import('./components/Interface/Interface')); export function AppRoutes() { return ( @@ -14,6 +15,11 @@ export function AppRoutes() { /> ))} + }>{React.createElement(ComponentInterfaceRoute)}} + /> + }> ); diff --git a/packages/site/src/app/routes/components/Interface.md b/packages/site/src/app/routes/components/Interface.md new file mode 100644 index 00000000..0ae728f1 --- /dev/null +++ b/packages/site/src/app/routes/components/Interface.md @@ -0,0 +1,96 @@ +# Interface + +## DElementSelector + +```tsx +export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); +``` + +## DPopupProps + +Extend `React.HTMLAttributes`. + + +| Property | Description | Type | Default | +| --- | --- | --- | --- | +| dVisible | Control the display of popup | boolean | - | +| dPopupContent | The contents of the popup | React.ReactNode | - | +| dTriggerRender | The target node of the popup | `(props: DTriggerRenderProps) => React.ReactNode` | - | +| dTriggerEl | Custom popup target node | HTMLElement \| null | - | +| dContainer | Mount node of popup, `false` represents the parent node mounted to the target node | [DElementSelector](/components/Interface#DElementSelector) \| false | - | +| dPlacement | popup direction | 'top' \| 'top-left' \| 'top-right' \| 'right' \| 'right-top' \| 'right-bottom' \| 'bottom' \| 'bottom-left' \| 'bottom-right' \| 'left' \| 'left-top' \| 'left-bottom' | 'top' | +| dAutoPlace | When the popup is occluded, the position is automatically adjusted. If the `dContainer` attribute is not specified, the `window` view will be compared by default | boolean | true | +| dTrigger | Trigger behavior | 'hover' \| 'focus' \| 'click' \| null | 'hover' | +| dDistance | The distance of the pop-up window from the target node | number | 10 | +| dArrow | Whether to show arrow | boolean | true | +| dZIndex | Manually control the value of `z-index` | number | - | +| dDestroy | Destroy the node after shutdown | boolean | false | +| dMouseEnterDelay | How many milliseconds after the mouse is moved to display | number | 150 | +| dMouseLeaveDelay | How many milliseconds after the mouse is moved out will it be displayed | number | 150 | +| dCustomPopup | Custom popup | `(popupEl: HTMLElement, targetEl: HTMLElement) => { top: number; left: number; stateList: DTransitionStateList; arrowPosition?: React.CSSProperties }` | - | +| onVisibleChange | popup display/hide callback | `(visible: boolean) => void` | - | +| afterVisibleChange | Callback for the end of the popup show/hide animation | `(visible: boolean) => void` | - | + + +## DPopupRef + +```tsx +export interface DPopupRef { + el: HTMLDivElement | null; + triggerEl: HTMLElement | null; + updatePosition: () => void; +} +``` + +## DTriggerRenderProps + +```tsx +export interface DTriggerRenderProps { + [key: `data-${string}popup-trigger`]: string; + onMouseEnter?: React.MouseEventHandler; + onMouseLeave?: React.MouseEventHandler; + onFocus?: React.FocusEventHandler; + onBlur?: React.FocusEventHandler; + onClick?: React.MouseEventHandler; +} +``` + +## DTransitionStateList + +```tsx +export interface DTransitionStateList { + 'enter-from'?: Partial; + 'enter-active'?: Partial; + 'enter-to'?: Partial; + 'leave-from'?: Partial; + 'leave-active'?: Partial; + 'leave-to'?: Partial; +} +``` + +## DHeaderProps + +Extend `React.HTMLAttributes`. + + +| Property | Description | Type | Default | +| --- | --- | --- | --- | +| dCloseIcon | Set the icon of the close button, `null` means hide the button | React.ReactNode | - | +| dExtraIcons | Add some extra action buttons | React.ReactNode[] | - | +| onClose | Callback when the close button is clicked | `() => void` | - | + + +## DFooterProps + +Extend `React.HTMLAttributes`. + + +| Property | Description | Type | Default | +| --- | --- | --- | --- | +| dAlign | Set the horizontal position of the button | 'left' \| 'center' \| 'right' | 'right' | +| dButtons | Custom button, `'cancel'` stands for cancel button, `'ok'` stands for OK button | React.ReactNode[] | `['cancel', 'ok']` | +| dOkButtonProps | Provide additional `Props` for the OK button | [DButtonProps](/components/Button#DButtonProps) | - | +| dCancelButtonProps | Provide additional `Props` for the cancel button | [DButtonProps](/components/Button#DButtonProps) | - | +| onOkClick | The callback of clicking the OK button | `() => void` | - | +| onCancelClick | The callback of clicking the cancel button | `() => void` | - | + diff --git a/packages/site/src/app/routes/components/Interface.zh-Hant.md b/packages/site/src/app/routes/components/Interface.zh-Hant.md new file mode 100644 index 00000000..cae3bf67 --- /dev/null +++ b/packages/site/src/app/routes/components/Interface.zh-Hant.md @@ -0,0 +1,96 @@ +# 接口 + +## DElementSelector + +```tsx +export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); +``` + +## DPopupProps + +继承 `React.HTMLAttributes`. + + +| Property | Description | Type | Default | +| --- | --- | --- | --- | +| dVisible | Control the display of popup | boolean | - | +| dPopupContent | The contents of the popup | React.ReactNode | - | +| dTriggerRender | The target node of the popup | `(props: DTriggerRenderProps) => React.ReactNode` | - | +| dTriggerEl | Custom popup target node | HTMLElement \| null | - | +| dContainer | Mount node of popup, `false` represents the parent node mounted to the target node | [DElementSelector](/components/Interface#DElementSelector) \| false | - | +| dPlacement | popup direction | 'top' \| 'top-left' \| 'top-right' \| 'right' \| 'right-top' \| 'right-bottom' \| 'bottom' \| 'bottom-left' \| 'bottom-right' \| 'left' \| 'left-top' \| 'left-bottom' | 'top' | +| dAutoPlace | When the popup is occluded, the position is automatically adjusted. If the `dContainer` attribute is not specified, the `window` view will be compared by default | boolean | true | +| dTrigger | Trigger behavior | 'hover' \| 'focus' \| 'click' \| null | 'hover' | +| dDistance | The distance of the pop-up window from the target node | number | 10 | +| dArrow | Whether to show arrow | boolean | true | +| dZIndex | Manually control the value of `z-index` | number | - | +| dDestroy | Destroy the node after shutdown | boolean | false | +| dMouseEnterDelay | How many milliseconds after the mouse is moved to display | number | 150 | +| dMouseLeaveDelay | How many milliseconds after the mouse is moved out will it be displayed | number | 150 | +| dCustomPopup | Custom popup | `(popupEl: HTMLElement, targetEl: HTMLElement) => { top: number; left: number; stateList: DTransitionStateList; arrowPosition?: React.CSSProperties }` | - | +| onVisibleChange | popup display/hide callback | `(visible: boolean) => void` | - | +| afterVisibleChange | Callback for the end of the popup show/hide animation | `(visible: boolean) => void` | - | + + +## DPopupRef + +```tsx +export interface DPopupRef { + el: HTMLDivElement | null; + triggerEl: HTMLElement | null; + updatePosition: () => void; +} +``` + +## DTriggerRenderProps + +```tsx +export interface DTriggerRenderProps { + [key: `data-${string}popup-trigger`]: string; + onMouseEnter?: React.MouseEventHandler; + onMouseLeave?: React.MouseEventHandler; + onFocus?: React.FocusEventHandler; + onBlur?: React.FocusEventHandler; + onClick?: React.MouseEventHandler; +} +``` + +## DTransitionStateList + +```tsx +export interface DTransitionStateList { + 'enter-from'?: Partial; + 'enter-active'?: Partial; + 'enter-to'?: Partial; + 'leave-from'?: Partial; + 'leave-active'?: Partial; + 'leave-to'?: Partial; +} +``` + +## DHeaderProps + +继承 `React.HTMLAttributes`。 + + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| dCloseIcon | 设置关闭按钮的图标, `null` 表示隐藏按钮 | React.ReactNode | - | +| dExtraIcons | 添加一些额外的操作按钮 | React.ReactNode[] | - | +| onClose | 点击关闭按钮的回调 | `() => void` | - | + + +## DFooterProps + +继承 `React.HTMLAttributes`。 + + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| dAlign | 设置按钮的水平位置 | 'left' \| 'center' \| 'right' | 'right' | +| dButtons | 自定义按钮,`'cancel'` 代表取消按钮,`'ok'` 代表确定按钮 | React.ReactNode[] | `['cancel', 'ok']` | +| dOkButtonProps | 为确定按钮提供额外的 `Props` | [DButtonProps](/components/Button#DButtonProps) | - | +| dCancelButtonProps | 为取消按钮提供额外的 `Props` | [DButtonProps](/components/Button#DButtonProps) | - | +| onOkClick | 点击确定按钮的回调 | `() => void` | - | +| onCancelClick | 点击取消按钮的回调 | `() => void` | - | + diff --git a/packages/site/src/app/styles/_app.scss b/packages/site/src/app/styles/_app.scss index 789acd06..c3aee8ed 100644 --- a/packages/site/src/app/styles/_app.scss +++ b/packages/site/src/app/styles/_app.scss @@ -19,28 +19,191 @@ body { -webkit-tap-highlight-color: rgb(0 0 0 / 0%); // 4 @include font-size(1rem); +} + +.app-main { + position: absolute; + right: 0; + bottom: 0; + + width: 100%; + height: calc(100% - 64px); + padding: 20px; + overflow: auto; +} + +@media (min-width: 768px) { .app-main { - position: absolute; - right: 0; - bottom: 0; + width: calc(100% - 260px); + padding: 32px 200px 32px 64px; + } +} - width: 100%; - height: calc(100% - 64px); - padding: 20px; +.app-icon-button { + color: var(--d-color-step-400); + + cursor: pointer; + + transition: color 0.1s linear; + + user-select: none; - overflow: auto; + &:hover { + color: var(--d-color-primary); } +} + +h1, +h2, +h3, +h4, +h5, +h6 { + .anchor { + display: inline-block; + margin-left: 8px; + + color: var(--d-color-primary); + text-decoration: none; - @media (min-width: 768px) { - .app-main { - width: calc(100% - 260px); - padding: 32px 200px 32px 64px; + opacity: 0; + + transition: opacity 0.2s linear; + + &:focus-visible { + outline: none; + opacity: 1; + } + } + + &:hover .anchor { + opacity: 1; + } +} + +code { + word-break: break-all; +} + +pre > code { + font-family: Consolas, Menlo, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; +} + +pre code.hljs { + background-color: var(--app-code-background-color); +} + +code:not(pre > code) { + margin: 0 1px; + padding: 4px 6px; + border-radius: 3px; + + font-family: Consolas, Menlo, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + + background-color: var(--app-code-background-color); +} + +p a[href] { + color: var(--d-color-primary); + text-decoration: none; + + &:hover { + color: var(--d-color-primary-lighter); + } +} + +h1 { + margin: 8px 0 20px; + + font-weight: 500; + @include font-size(2rem); +} + +h2 { + margin: 38px 0 20px; + + font-weight: 500; + @include font-size(1.5rem); +} + +h3 { + margin: 28px 0 12px; + + font-weight: 500; + @include font-size(1.25rem); +} + +.app-table-container { + width: 100%; + overflow-x: auto; + + table { + width: 100%; + min-width: 1200px; + margin: 8px 0 16px; + border: 1px solid var(--d-border-color); + border-collapse: collapse; + border-spacing: 0; + + table-layout: fixed; + + empty-cells: show; + + th { + font-weight: 500; + white-space: nowrap; + + background: var(--app-th-background-color); + } + + th, + td { + padding: 16px 24px; + border: 1px solid var(--d-divider-color); + + text-align: left; + } + + th:nth-of-type(1) { + width: 260px; + + white-space: nowrap; + } + + th:nth-of-type(2) { + width: calc(100% - 720px); + } + + th:nth-of-type(3) { + width: 300px; + } + + th:nth-of-type(4) { + width: 160px; + } + + td:nth-of-type(1), + td:nth-of-type(3), + td:nth-of-type(4) { + font-family: Consolas, Menlo, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; } } } // demo general style +.app-demo-box__renderer { + .d-menu:not(.d-menu--horizontal) { + width: 320px; + max-width: 100%; + border-right: 1px solid var(--d-divider-color); + } + + .d-row + .d-row { + margin-top: 12px; + } +} + .app-demo-drag { position: relative; @@ -95,15 +258,3 @@ body { .app-demo-col--lighter { background-color: var(--d-color-primary-lighter); } - -.app-route-article__demos { - .d-menu:not(.d-menu--horizontal) { - width: 320px; - max-width: 100%; - border-right: 1px solid var(--d-divider-color); - } - - .d-row + .d-row { - margin-top: 12px; - } -} diff --git a/packages/ui/src/components/_popup/Popup.tsx b/packages/ui/src/components/_popup/Popup.tsx index a86090fb..724679f8 100644 --- a/packages/ui/src/components/_popup/Popup.tsx +++ b/packages/ui/src/components/_popup/Popup.tsx @@ -518,6 +518,7 @@ export const DPopup = React.forwardRef((props, ref) => { onVisibleChange?.(false); } afterVisibleChange?.(true); + updatePosition(); }, beforeLeave: () => dataRef.current.transitionState, afterLeave: () => { diff --git a/packages/ui/src/components/affix/README.md b/packages/ui/src/components/affix/README.md index ee897fe2..fa9aa846 100644 --- a/packages/ui/src/components/affix/README.md +++ b/packages/ui/src/components/affix/README.md @@ -18,7 +18,7 @@ Extend `React.HTMLAttributes`. | Property | Description | Type | Default | | --- | --- | --- | --- | -| dTarget | Set the node that needs to listen to its scroll event, compare the `window` view by default | DElementSelector | - | +| dTarget | Set the node that needs to listen to its scroll event, compare the `window` view by default | [DElementSelector](/components/Interface#DElementSelector) | - | | dTop | Trigger after reaching the specified offset from the top | string \| number | 0 | | dBottom | Trigger after reaching the specified offset from the bottom | string \| number | 0 | | dZIndex | Manually control the value of `z-index` | number | 900 | @@ -33,9 +33,3 @@ export interface DAffixRef { updatePosition: () => void; } ``` - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/affix/README.zh-Hant.md b/packages/ui/src/components/affix/README.zh-Hant.md index afd7fbb5..806e7023 100644 --- a/packages/ui/src/components/affix/README.zh-Hant.md +++ b/packages/ui/src/components/affix/README.zh-Hant.md @@ -17,7 +17,7 @@ title: 固钉 | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| dTarget | 设置需要监听其滚动事件的节点,默认比较 `window` 视图 | DElementSelector | - | +| dTarget | 设置需要监听其滚动事件的节点,默认比较 `window` 视图 | [DElementSelector](/components/Interface#DElementSelector) | - | | dTop | 距离顶部达到指定偏移量后触发 | string \| number | 0 | | dBottom | 距离底部达到指定偏移量后触发 | string \| number | 0 | | dZIndex | 手动控制 `z-index` 的值 | number | 900 | @@ -32,9 +32,3 @@ export interface DAffixRef { updatePosition: () => void; } ``` - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/anchor/README.md b/packages/ui/src/components/anchor/README.md index 54097d24..0ffdc4d3 100644 --- a/packages/ui/src/components/anchor/README.md +++ b/packages/ui/src/components/anchor/README.md @@ -19,7 +19,7 @@ Extend `React.HTMLAttributes`. | Property | Description | Type | Default | | --- | --- | --- | --- | | dDistance | Distance from page to anchor | number | 0 | -| dPage | Set scrolling page, default is `window` view | DElementSelector | - | +| dPage | Set scrolling page, default is `window` view | [DElementSelector](/components/Interface#DElementSelector) | - | | dScrollBehavior | Custom scrolling behavior | 'instant' \| 'smooth' | 'instant' | | dIndicator | Custom indicator, pre-defined indicators of `'dot'` and `'line'` patterns | React.ReactNode | 'dot' | | onHrefChange | Anchor point change callback | `(href: string \| null) => void` | - | @@ -35,9 +35,3 @@ Extend `React.LiHTMLAttributes`. | dLevel | Set the anchor level | number | 0 | | href | Set anchor link | string | - | - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/anchor/README.zh-Hant.md b/packages/ui/src/components/anchor/README.zh-Hant.md index 2639e3c2..7f51fec9 100644 --- a/packages/ui/src/components/anchor/README.zh-Hant.md +++ b/packages/ui/src/components/anchor/README.zh-Hant.md @@ -18,7 +18,7 @@ title: 锚点 | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | dDistance | 页面到锚点的距离 | number | 0 | -| dPage | 设置滚动的页面,默认为 `window` 视图 | DElementSelector | - | +| dPage | 设置滚动的页面,默认为 `window` 视图 | [DElementSelector](/components/Interface#DElementSelector) | - | | dScrollBehavior | 自定义滚动行为 | 'instant' \| 'smooth' | 'instant' | | dIndicator | 自定义指示器,预定义了 `'dot'` 以及 `'line'` 形态的指示器 | React.ReactNode | 'dot' | | onHrefChange | 锚点改变的回调 | `(href: string \| null) => void` | - | @@ -34,9 +34,3 @@ title: 锚点 | dLevel | 设置锚点的层级 | number | 0 | | href | 设置锚点链接 | string | - | - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/drag-drop/README.md b/packages/ui/src/components/drag-drop/README.md index 73d5ffdc..85439c3d 100644 --- a/packages/ui/src/components/drag-drop/README.md +++ b/packages/ui/src/components/drag-drop/README.md @@ -29,7 +29,7 @@ Need to dynamically adjust the component position. | Property | Description | Type | Default | | --- | --- | --- | --- | -| dContainer | The container where the node is placed | DElementSelector | - | +| dContainer | The container where the node is placed | [DElementSelector](/components/Interface#DElementSelector) | - | | dDirection | The direction of the container to place the node | 'horizontal' \| 'vertical' | 'vertical' | | dPlaceholder | Placeholder node | React.ReactNode | 1000 | | children | Drag nodes | React.ReactNode | - | diff --git a/packages/ui/src/components/drag-drop/README.zh-Hant.md b/packages/ui/src/components/drag-drop/README.zh-Hant.md index 178129f1..fe83659b 100644 --- a/packages/ui/src/components/drag-drop/README.zh-Hant.md +++ b/packages/ui/src/components/drag-drop/README.zh-Hant.md @@ -28,7 +28,7 @@ title: 拖放 | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| dContainer | 放置节点的容器 | DElementSelector | - | +| dContainer | 放置节点的容器 | [DElementSelector](/components/Interface#DElementSelector) | - | | dDirection | 容器放置节点的方向 | 'horizontal' \| 'vertical' | 'vertical' | | dPlaceholder | 占位节点 | React.ReactNode | 1000 | | children | 拖拽节点 | React.ReactNode | - | diff --git a/packages/ui/src/components/drawer/README.md b/packages/ui/src/components/drawer/README.md index ce1dbe1d..310e4976 100644 --- a/packages/ui/src/components/drawer/README.md +++ b/packages/ui/src/components/drawer/README.md @@ -19,7 +19,7 @@ Extend `React.HTMLAttributes`. | Property | Description | Type | Default | | --- | --- | --- | --- | | dVisible | Is the drawer visible | [boolean, Updater\?] | - | -| dContainer | The mounted node of the drawer, `false` means it is mounted on the current node | DElementSelector \| false | - | +| dContainer | The mounted node of the drawer, `false` means it is mounted on the current node | [DElementSelector](/components/Interface#DElementSelector) \| false | - | | dPlacement | Drawer pop-up direction | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' | | dWidth | Drawer width | number \| string | 400 | | dHeight | Drawer height | number \| string | 280 | @@ -38,46 +38,17 @@ Extend `React.HTMLAttributes`. Equal `Omit`. -### DHeaderProps - -Extend `React.HTMLAttributes`. - - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| dCloseIcon | Set the icon of the close button, `null` means hide the button | React.ReactNode | - | -| dExtraIcons | Add some extra action buttons | React.ReactNode[] | - | -| onClose | Callback when the close button is clicked | `() => void` | - | - +Please refer to [DHeaderProps](/components/Interface#DHeaderProps). ### DDrawerFooterProps Extend `DFooterProps`. +Please refer to [DFooterProps](/components/Interface#DFooterProps). + | Property | Description | Type | Default | | --- | --- | --- | --- | | onOkClick | The callback of clicking the OK button, the operation feedback depends on the return value, and asynchronous operation can be achieved through `Promise` | `() => void \| boolean \| Promise` | - | | onCancelClick | The callback of clicking the cancel button, the operation feedback depends on the return value, and asynchronous operation can be achieved through `Promise` | `() => void \| boolean \| Promise` | - | - -### DFooterProps - -Extend `React.HTMLAttributes`. - - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| dAlign | Set the horizontal position of the button | 'left' \| 'center' \| 'right' | 'right' | -| dButtons | Custom button, `'cancel'` stands for cancel button, `'ok'` stands for OK button | React.ReactNode[] | `['cancel', 'ok']` | -| dOkButtonProps | Provide additional `Props` for the OK button | [DButtonProps](/components/Button#DButtonProps) | - | -| dCancelButtonProps | Provide additional `Props` for the cancel button | [DButtonProps](/components/Button#DButtonProps) | - | -| onOkClick | The callback of clicking the OK button | `() => void` | - | -| onCancelClick | The callback of clicking the cancel button | `() => void` | - | - - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/drawer/README.zh-Hant.md b/packages/ui/src/components/drawer/README.zh-Hant.md index d090417a..cee861be 100644 --- a/packages/ui/src/components/drawer/README.zh-Hant.md +++ b/packages/ui/src/components/drawer/README.zh-Hant.md @@ -18,7 +18,7 @@ title: 抽屉 | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | dVisible | 抽屉是否可见 | [boolean, Updater\?] | - | -| dContainer | 抽屉的挂载节点, `false` 表示挂载在当前节点 | DElementSelector \| false | - | +| dContainer | 抽屉的挂载节点, `false` 表示挂载在当前节点 | [DElementSelector](/components/Interface#DElementSelector) \| false | - | | dPlacement | 抽屉弹出方向 | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' | | dWidth | 抽屉宽度 | number \| string | 400 | | dHeight | 抽屉高度 | number \| string | 280 | @@ -37,46 +37,17 @@ title: 抽屉 等于 `Omit`。 -### DHeaderProps - -继承 `React.HTMLAttributes`。 - - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| dCloseIcon | 设置关闭按钮的图标, `null` 表示隐藏按钮 | React.ReactNode | - | -| dExtraIcons | 添加一些额外的操作按钮 | React.ReactNode[] | - | -| onClose | 点击关闭按钮的回调 | `() => void` | - | - +请参考 [DHeaderProps](/components/Interface#DHeaderProps)。 ### DDrawerFooterProps 继承 `DFooterProps`。 +请参考 [DFooterProps](/components/Interface#DFooterProps)。 + | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | onOkClick | 点击确定按钮的回调,操作反馈取决于返回值,可通过 `Promise` 实现异步操作 | `() => void \| boolean \| Promise` | - | | onCancelClick | 点击取消按钮的回调,操作反馈取决于返回值,可通过 `Promise` 实现异步操作 | `() => void \| boolean \| Promise` | - | - -### DFooterProps - -继承 `React.HTMLAttributes`。 - - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| dAlign | 设置按钮的水平位置 | 'left' \| 'center' \| 'right' | 'right' | -| dButtons | 自定义按钮,`'cancel'` 代表取消按钮,`'ok'` 代表确定按钮 | React.ReactNode[] | `['cancel', 'ok']` | -| dOkButtonProps | 为确定按钮提供额外的 `Props` | [DButtonProps](/components/Button#DButtonProps) | - | -| dCancelButtonProps | 为取消按钮提供额外的 `Props` | [DButtonProps](/components/Button#DButtonProps) | - | -| onOkClick | 点击确定按钮的回调 | `() => void` | - | -| onCancelClick | 点击取消按钮的回调 | `() => void` | - | - - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/input/Input.tsx b/packages/ui/src/components/input/Input.tsx index d2a3bedd..a6f96b01 100644 --- a/packages/ui/src/components/input/Input.tsx +++ b/packages/ui/src/components/input/Input.tsx @@ -27,7 +27,6 @@ export const DInput = React.forwardRef((props, ref) => { className, type = 'text', disabled, - children, onClick, onFocus, onBlur, diff --git a/packages/ui/src/components/input/README.md b/packages/ui/src/components/input/README.md index 13ef01f1..0bc92128 100644 --- a/packages/ui/src/components/input/README.md +++ b/packages/ui/src/components/input/README.md @@ -13,7 +13,7 @@ When the user needs to enter content. ### DRadioProps -Extend `React.InputHTMLAttributes, DFormControl`. +Extend `React.InputHTMLAttributes`, [DFormControl](/components/Form#DFormControl). | Property | Description | Type | Default | @@ -45,11 +45,3 @@ Extend `React.HTMLAttributes`. | dClearIcon | Custom clear icon | React.ReactNode | - | | dSize | Input size | 'smaller' \| 'larger' | - | - -### DFormControl - -```tsx -export interface DFormControl { - dFormControlName?: string; -} -``` diff --git a/packages/ui/src/components/input/README.zh-Hant.md b/packages/ui/src/components/input/README.zh-Hant.md index f7c51cf7..a632c1fa 100644 --- a/packages/ui/src/components/input/README.zh-Hant.md +++ b/packages/ui/src/components/input/README.zh-Hant.md @@ -12,7 +12,7 @@ title: 输入框 ### DInputProps -继承 `React.InputHTMLAttributes, DFormControl`。 +继承 `React.InputHTMLAttributes`,[DFormControl](/components/Form#DFormControl)。 | 参数 | 说明 | 类型 | 默认值 | @@ -44,11 +44,3 @@ export type DInputRef = HTMLInputElement; | dClearIcon | 自定义清除图标 | React.ReactNode | - | | dSize | 输入框尺寸 | 'smaller' \| 'larger' | - | - -### DFormControl - -```tsx -export interface DFormControl { - dFormControlName?: string; -} -``` diff --git a/packages/ui/src/components/radio/README.md b/packages/ui/src/components/radio/README.md index 59292850..cede1247 100644 --- a/packages/ui/src/components/radio/README.md +++ b/packages/ui/src/components/radio/README.md @@ -13,7 +13,7 @@ The user needs to select a single option from a data set, and can view all the a ### DRadioProps -Extend `React.HTMLAttributes, DFormControl`. +Extend `React.HTMLAttributes`, [DFormControl](/components/Form#DFormControl). | Property | Description | Type | Default | @@ -32,7 +32,7 @@ export type DRadioRef = HTMLInputElement; ### DRadioGroupProps -Extend `React.HTMLAttributes, DFormControl`. +Extend `React.HTMLAttributes`, [DFormControl](/components/Form#DFormControl). | Property | Description | Type | Default | @@ -51,11 +51,3 @@ Extend `React.HTMLAttributes, DFormControl`. ```tsx export type DValue = React.InputHTMLAttributes['value']; ``` - -### DFormControl - -```tsx -export interface DFormControl { - dFormControlName?: string; -} -``` diff --git a/packages/ui/src/components/radio/README.zh-Hant.md b/packages/ui/src/components/radio/README.zh-Hant.md index 7a283bfe..daf61e2e 100644 --- a/packages/ui/src/components/radio/README.zh-Hant.md +++ b/packages/ui/src/components/radio/README.zh-Hant.md @@ -12,7 +12,7 @@ title: 单选组 ### DRadioProps -继承 `React.HTMLAttributes, DFormControl`。 +继承 `React.HTMLAttributes`,[DFormControl](/components/Form#DFormControl)。 | 参数 | 说明 | 类型 | 默认值 | @@ -31,7 +31,7 @@ export type DRadioRef = HTMLInputElement; ### DRadioGroupProps -继承 `React.HTMLAttributes, DFormControl`。 +继承 `React.HTMLAttributes`,[DFormControl](/components/Form#DFormControl)。 | 参数 | 说明 | 类型 | 默认值 | @@ -50,11 +50,3 @@ export type DRadioRef = HTMLInputElement; ```tsx export type DValue = React.InputHTMLAttributes['value']; ``` - -### DFormControl - -```tsx -export interface DFormControl { - dFormControlName?: string; -} -``` diff --git a/packages/ui/src/components/textarea/Textarea.tsx b/packages/ui/src/components/textarea/Textarea.tsx index 0352485a..09d54c69 100644 --- a/packages/ui/src/components/textarea/Textarea.tsx +++ b/packages/ui/src/components/textarea/Textarea.tsx @@ -94,11 +94,13 @@ export const DTextarea = React.forwardRef((props, [changeBindValue, onChange, setRowNum] ); + //#region DidUpdate useEffect(() => { if (textareaEl) { setRowNum((textareaEl.scrollHeight - 6) / 24); } }, [setRowNum, textareaEl]); + //#endregion useImperativeHandle(ref, () => textareaEl, [textareaEl]); diff --git a/packages/ui/src/components/tooltip/README.md b/packages/ui/src/components/tooltip/README.md index d5fc6300..30f430db 100644 --- a/packages/ui/src/components/tooltip/README.md +++ b/packages/ui/src/components/tooltip/README.md @@ -15,6 +15,8 @@ Replace the system default `title` prompt. Extend `Omit`. +Please refer to [DPopupProps](/components/Interface#DPopupProps). + | Property | Description | Type | Default | | --- | --- | --- | --- | @@ -27,71 +29,3 @@ Extend `Omit`. ```tsx export type DTooltipRef = DPopupRef; ``` - -### DPopupProps - -Extend `React.HTMLAttributes`. - - -| Property | Description | Type | Default | -| --- | --- | --- | --- | -| dVisible | Control the display of popup | boolean | - | -| dPopupContent | The contents of the popup | React.ReactNode | - | -| dTriggerRender | The target node of the popup | `(props: DTriggerRenderProps) => React.ReactNode` | - | -| dTriggerEl | Custom popup target node | HTMLElement \| null | - | -| dContainer | Mount node of popup, `false` represents the parent node mounted to the target node | DElementSelector \| false | - | -| dPlacement | popup direction | 'top' \| 'top-left' \| 'top-right' \| 'right' \| 'right-top' \| 'right-bottom' \| 'bottom' \| 'bottom-left' \| 'bottom-right' \| 'left' \| 'left-top' \| 'left-bottom' | 'top' | -| dAutoPlace | When the popup is occluded, the position is automatically adjusted. If the `dContainer` attribute is not specified, the `window` view will be compared by default | boolean | true | -| dTrigger | Trigger behavior | 'hover' \| 'focus' \| 'click' \| null | 'hover' | -| dDistance | The distance of the pop-up window from the target node | number | 10 | -| dArrow | Whether to show arrow | boolean | true | -| dZIndex | Manually control the value of `z-index` | number | - | -| dDestroy | Destroy the node after shutdown | boolean | false | -| dMouseEnterDelay | How many milliseconds after the mouse is moved to display | number | 150 | -| dMouseLeaveDelay | How many milliseconds after the mouse is moved out will it be displayed | number | 150 | -| dCustomPopup | Custom popup | `(popupEl: HTMLElement, targetEl: HTMLElement) => { top: number; left: number; stateList: DTransitionStateList; arrowPosition?: React.CSSProperties }` | - | -| onVisibleChange | popup display/hide callback | `(visible: boolean) => void` | - | -| afterVisibleChange | Callback for the end of the popup show/hide animation | `(visible: boolean) => void` | - | - - -### DPopupRef - -```tsx -export interface DPopupRef { - el: HTMLDivElement | null; - triggerEl: HTMLElement | null; - updatePosition: () => void; -} -``` - -### DTriggerRenderProps - -```tsx -export interface DTriggerRenderProps { - [key: `data-${string}popup-trigger`]: string; - onMouseEnter?: React.MouseEventHandler; - onMouseLeave?: React.MouseEventHandler; - onFocus?: React.FocusEventHandler; - onBlur?: React.FocusEventHandler; - onClick?: React.MouseEventHandler; -} -``` - -### DTransitionStateList - -```tsx -export interface DTransitionStateList { - 'enter-from'?: Partial; - 'enter-active'?: Partial; - 'enter-to'?: Partial; - 'leave-from'?: Partial; - 'leave-active'?: Partial; - 'leave-to'?: Partial; -} -``` - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/components/tooltip/README.zh-Hant.md b/packages/ui/src/components/tooltip/README.zh-Hant.md index e01800df..7564e04c 100644 --- a/packages/ui/src/components/tooltip/README.zh-Hant.md +++ b/packages/ui/src/components/tooltip/README.zh-Hant.md @@ -14,6 +14,8 @@ title: 文字提示 继承 `Omit`。 +请参考 [DPopupProps](/components/Interface#DPopupProps)。 + | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | @@ -26,71 +28,3 @@ title: 文字提示 ```tsx export type DTooltipRef = DPopupRef; ``` - -### DPopupProps - -继承 `React.HTMLAttributes`。 - - -| 参数 | 说明 | 类型 | 默认值 | -| --- | --- | --- | --- | -| dVisible | 控制 popup 的显示 | boolean | - | -| dPopupContent | popup 的内容 | React.ReactNode | - | -| dTriggerRender | popup 的目标节点 | `(props: DTriggerRenderProps) => React.ReactNode` | - | -| dTriggerEl | 自定义 popup 的目标节点 | HTMLElement \| null | - | -| dContainer | popup 的挂载节点,`false` 代表挂载到目标节点的父节点 | DElementSelector \| false | - | -| dPlacement | popup 弹出方向 | 'top' \| 'top-left' \| 'top-right' \| 'right' \| 'right-top' \| 'right-bottom' \| 'bottom' \| 'bottom-left' \| 'bottom-right' \| 'left' \| 'left-top' \| 'left-bottom' | 'top' | -| dAutoPlace | 当 popup 被遮挡时,自动调整位置,如果未指定 `dContainer` 属性,那么默认比较 `window` 视图 | boolean | true | -| dTrigger | 触发行为 | 'hover' \| 'focus' \| 'click' \| null | 'hover' | -| dDistance | 弹出窗口距离目标节点的距离 | number | 10 | -| dArrow | 是否显示箭头 | boolean | true | -| dZIndex | 手动控制 `z-index` 的值 | number | - | -| dDestroy | 关闭后销毁节点 | boolean | false | -| dMouseEnterDelay | 鼠标移入后多少毫秒后显示 | number | 150 | -| dMouseLeaveDelay | 鼠标移出后多少毫秒后显示 | number | 150 | -| dCustomPopup | 自定义 popup | `(popupEl: HTMLElement, targetEl: HTMLElement) => { top: number; left: number; stateList: DTransitionStateList; arrowPosition?: React.CSSProperties }` | - | -| onVisibleChange | popup 显示/隐藏的回调 | `(visible: boolean) => void` | - | -| afterVisibleChange | popup 显示/隐藏动画结束的回调 | `(visible: boolean) => void` | - | - - -### DPopupRef - -```tsx -export interface DPopupRef { - el: HTMLDivElement | null; - triggerEl: HTMLElement | null; - updatePosition: () => void; -} -``` - -### DTriggerRenderProps - -```tsx -export interface DTriggerRenderProps { - [key: `data-${string}popup-trigger`]: string; - onMouseEnter?: React.MouseEventHandler; - onMouseLeave?: React.MouseEventHandler; - onFocus?: React.FocusEventHandler; - onBlur?: React.FocusEventHandler; - onClick?: React.MouseEventHandler; -} -``` - -### DTransitionStateList - -```tsx -export interface DTransitionStateList { - 'enter-from'?: Partial; - 'enter-active'?: Partial; - 'enter-to'?: Partial; - 'leave-from'?: Partial; - 'leave-active'?: Partial; - 'leave-to'?: Partial; -} -``` - -### DElementSelector - -```tsx -export type DElementSelector = HTMLElement | null | string | (() => HTMLElement | null); -``` diff --git a/packages/ui/src/styles/_components.scss b/packages/ui/src/styles/_components.scss index 2cbc74fc..7cc118bb 100644 --- a/packages/ui/src/styles/_components.scss +++ b/packages/ui/src/styles/_components.scss @@ -16,4 +16,5 @@ @import 'components/popup'; @import 'components/radio'; @import 'components/tabs'; +@import 'components/textarea'; @import 'components/tooltip'; diff --git a/packages/ui/src/styles/components/_textarea.scss b/packages/ui/src/styles/components/_textarea.scss new file mode 100644 index 00000000..dfb1f137 --- /dev/null +++ b/packages/ui/src/styles/components/_textarea.scss @@ -0,0 +1,56 @@ +@include b(textarea) { + display: block; + box-sizing: border-box; + width: 100%; + min-width: 0; + margin: 0; + padding: 3px 9px; + border: 1px solid var(--#{$variable-prefix}border-color); + border-radius: 2px; + + font: inherit; + font-size: var(--#{$variable-prefix}font); + line-height: 24px; + letter-spacing: inherit; + + outline: none; + + transition: border-color 0.2s linear; + + appearance: none; + caret-color: var(--#{$variable-prefix}color-primary); + + @include utils-disabled(':disabled', true); + + &:not(:disabled) { + &:hover { + z-index: var(--#{$variable-prefix}hover-z-index); + + border-color: var(--#{$variable-prefix}color-primary-lighter); + } + + &:focus { + z-index: var(--#{$variable-prefix}hover-z-index); + + border-color: var(--#{$variable-prefix}color-primary); + } + } + + &::placeholder { + color: var(--#{$variable-prefix}color-step-400); + + transform: translateX(1px); + } + + &:disabled::placeholder { + color: var(--#{$variable-prefix}color-step-100); + } + + @include e(count) { + color: var(--#{$variable-prefix}color-step-400); + font-size: var(--#{$variable-prefix}font); + font-variant-numeric: tabular-nums; + line-height: 28px; + text-align: right; + } +} diff --git a/tools/executors/site/build-base/impl.js b/tools/executors/site/build-base/impl.js index 95c28b6b..caeed44a 100644 --- a/tools/executors/site/build-base/impl.js +++ b/tools/executors/site/build-base/impl.js @@ -27,7 +27,8 @@ marked_1.default.setOptions({ langPrefix: 'hljs ', }); var COMPONENT_DIR = String.raw(templateObject_1 || (templateObject_1 = (0, tslib_1.__makeTemplateObject)(["packages/ui/src/components"], ["packages/ui/src/components"]))); -var OUTPUT_DIR = String.raw(templateObject_2 || (templateObject_2 = (0, tslib_1.__makeTemplateObject)(["packages/site/src/app"], ["packages/site/src/app"]))); +var ROUTE_DIR = [String.raw(templateObject_2 || (templateObject_2 = (0, tslib_1.__makeTemplateObject)(["packages/site/src/app/routes/components"], ["packages/site/src/app/routes/components"])))]; +var OUTPUT_DIR = String.raw(templateObject_3 || (templateObject_3 = (0, tslib_1.__makeTemplateObject)(["packages/site/src/app"], ["packages/site/src/app"]))); var GenerateSite = /** @class */ (function () { function GenerateSite() { Object.defineProperty(this, "hashList", { @@ -60,7 +61,13 @@ var GenerateSite = /** @class */ (function () { writable: true, value: void 0 }); - Object.defineProperty(this, "routesTmp", { + Object.defineProperty(this, "componentRoutesTmp", { + enumerable: true, + configurable: true, + writable: true, + value: void 0 + }); + Object.defineProperty(this, "componentRouteTmp", { enumerable: true, configurable: true, writable: true, @@ -105,7 +112,7 @@ var GenerateSite = /** @class */ (function () { value: function (file, outDir) { var _a, _b, _c; var meta = yamlFront.loadFront(file.data); - var fileNameRegExp = new RegExp(String.raw(templateObject_3 || (templateObject_3 = (0, tslib_1.__makeTemplateObject)(["(?<=^[0-9]+.)[a-zA-Z]+(?=.md$)"], ["(?<=^[0-9]+.)[a-zA-Z]+(?=.md$)"]))), 'g'); + var fileNameRegExp = new RegExp(String.raw(templateObject_4 || (templateObject_4 = (0, tslib_1.__makeTemplateObject)(["(?<=^[0-9]+.)[a-zA-Z]+(?=.md$)"], ["(?<=^[0-9]+.)[a-zA-Z]+(?=.md$)"]))), 'g'); var fileName = (_a = file.name.match(fileNameRegExp)) === null || _a === void 0 ? void 0 : _a[0]; var id = file.component[0].toUpperCase() + file.component.slice(1) + fileName + 'Demo'; var tsx = (_b = meta.__content.match(/(?<=```tsx)[\s\S]*?(?=```)/g)) === null || _b === void 0 ? void 0 : _b[0]; @@ -114,11 +121,11 @@ var GenerateSite = /** @class */ (function () { var outTSX = tsx; if (scss) { outTSX = - String.raw(templateObject_4 || (templateObject_4 = (0, tslib_1.__makeTemplateObject)(["import './", ".scss';\n"], ["import './", ".scss';\n"])), fileName) + outTSX; - this.outputFile(path_1.default.join(outDir, "".concat(fileName, ".scss")), String.raw(templateObject_5 || (templateObject_5 = (0, tslib_1.__makeTemplateObject)(["\n#", "{\n ", "\n}\n"], ["\n#", "{\n ", "\n}\n"])), id, scss.split(/\n/g).join('\n '))); + String.raw(templateObject_5 || (templateObject_5 = (0, tslib_1.__makeTemplateObject)(["import './", ".scss';\n"], ["import './", ".scss';\n"])), fileName) + outTSX; + this.outputFile(path_1.default.join(outDir, "".concat(fileName, ".scss")), String.raw(templateObject_6 || (templateObject_6 = (0, tslib_1.__makeTemplateObject)(["\n#", "{\n ", "\n}\n"], ["\n#", "{\n ", "\n}\n"])), id, scss.split(/\n/g).join('\n '))); } outTSX = - String.raw(templateObject_6 || (templateObject_6 = (0, tslib_1.__makeTemplateObject)(["/* eslint-disable */\n// @ts-nocheck\n"], ["/* eslint-disable */\n// @ts-nocheck\n"]))) + outTSX; + String.raw(templateObject_7 || (templateObject_7 = (0, tslib_1.__makeTemplateObject)(["/* eslint-disable */\n// @ts-nocheck\n"], ["/* eslint-disable */\n// @ts-nocheck\n"]))) + outTSX; this.outputFile(path_1.default.join(outDir, "".concat(fileName, ".tsx")), outTSX); var demo_1 = new Map([ ['en-US', {}], @@ -130,12 +137,12 @@ var GenerateSite = /** @class */ (function () { obj.id = id; obj.name = fileName; obj.title = meta.title[lang]; - var descriptionRegExp = new RegExp(String.raw(templateObject_7 || (templateObject_7 = (0, tslib_1.__makeTemplateObject)(["(?<=# ", ")[sS]*", ""], ["(?<=# ", ")[\\s\\S]*", ""])), lang, index === langs.length - 1 ? '(?=```tsx)' : "(?=# ".concat(langs[index + 1], ")")), 'g'); + var descriptionRegExp = new RegExp(String.raw(templateObject_8 || (templateObject_8 = (0, tslib_1.__makeTemplateObject)(["(?<=# ", ")[sS]*", ""], ["(?<=# ", ")[\\s\\S]*", ""])), lang, index === langs.length - 1 ? '(?=```tsx)' : "(?=# ".concat(langs[index + 1], ")")), 'g'); var description = (_a = meta.__content.match(descriptionRegExp)) === null || _a === void 0 ? void 0 : _a[0]; if (description) { obj.description = (0, marked_1.default)(description); } - obj.importStatement = String.raw(templateObject_8 || (templateObject_8 = (0, tslib_1.__makeTemplateObject)(["import ", "Demo from './demos/", "';\n"], ["import ", "Demo from './demos/", "';\n"])), fileName, fileName); + obj.importStatement = String.raw(templateObject_9 || (templateObject_9 = (0, tslib_1.__makeTemplateObject)(["import ", "Demo from './demos/", "';\n"], ["import ", "Demo from './demos/", "';\n"])), fileName, fileName); obj.tsx = meta.__content.match(/```tsx[\s\S]*?```/g)[0]; if (scss) { obj.scss = meta.__content.match(/```scss[\s\S]*?```/g)[0]; @@ -174,18 +181,18 @@ var GenerateSite = /** @class */ (function () { if (menuItemIndex === -1) { this.menuConfig[menuGroupIndex].children.push({ title: meta.title['en-US'], - to: String.raw(templateObject_9 || (templateObject_9 = (0, tslib_1.__makeTemplateObject)(["/components/", ""], ["/components/", ""])), meta.title['en-US']), + to: String.raw(templateObject_10 || (templateObject_10 = (0, tslib_1.__makeTemplateObject)(["/components/", ""], ["/components/", ""])), meta.title['en-US']), }); } else { this.menuConfig[menuGroupIndex].children[menuItemIndex] = { title: meta.title['en-US'], - to: String.raw(templateObject_10 || (templateObject_10 = (0, tslib_1.__makeTemplateObject)(["/components/", ""], ["/components/", ""])), meta.title['en-US']), + to: String.raw(templateObject_11 || (templateObject_11 = (0, tslib_1.__makeTemplateObject)(["/components/", ""], ["/components/", ""])), meta.title['en-US']), }; } this.routeConfig.set(meta.title['en-US'], { - import: String.raw(templateObject_11 || (templateObject_11 = (0, tslib_1.__makeTemplateObject)(["./", "/", ""], ["./", "/", ""])), file.name, meta.title['en-US']), - path: String.raw(templateObject_12 || (templateObject_12 = (0, tslib_1.__makeTemplateObject)(["/components/", ""], ["/components/", ""])), meta.title['en-US']), + import: String.raw(templateObject_12 || (templateObject_12 = (0, tslib_1.__makeTemplateObject)(["./", "/", ""], ["./", "/", ""])), file.name, meta.title['en-US']), + path: String.raw(templateObject_13 || (templateObject_13 = (0, tslib_1.__makeTemplateObject)(["/components/", ""], ["/components/", ""])), meta.title['en-US']), }); var importStr = ''; var demoList_1 = []; @@ -214,9 +221,9 @@ var GenerateSite = /** @class */ (function () { } finally { if (e_1) throw e_1.error; } } - var routeTmp_1 = this.routeTmp; - routeTmp_1 = routeTmp_1.replace(/__Route__/g, meta.title['en-US']); - routeTmp_1 = routeTmp_1.replace(/__import__/g, importStr); + var componentRouteTmp_1 = this.componentRouteTmp; + componentRouteTmp_1 = componentRouteTmp_1.replace(/__Route__/g, meta.title['en-US']); + componentRouteTmp_1 = componentRouteTmp_1.replace(/__import__/g, importStr); ['en-US', 'zh-Hant'].forEach(function (lang) { var _a, _b; _this.resources[lang].translation.menu[meta.title['en-US']] = meta.title[lang]; @@ -224,21 +231,21 @@ var GenerateSite = /** @class */ (function () { var linksStr = ''; demoList_1.forEach(function (demo) { if (demo) { - var demoStr = String.raw(templateObject_13 || (templateObject_13 = (0, tslib_1.__makeTemplateObject)(["\n}\n title=\"__title__\"\n description={[__description__]}\n tsx={[__tsx__]}\n __scss__\n tsxSource={[__tsxSource__]}\n __scssSource__\n/>\n"], ["\n}\n title=\"__title__\"\n description={[__description__]}\n tsx={[__tsx__]}\n __scss__\n tsxSource={[__tsxSource__]}\n __scssSource__\n/>\n"]))); + var demoStr = String.raw(templateObject_14 || (templateObject_14 = (0, tslib_1.__makeTemplateObject)(["\n}\n title=\"__title__\"\n description={[__description__]}\n tsx={[__tsx__]}\n __scss__\n tsxSource={[__tsxSource__]}\n __scssSource__\n/>\n"], ["\n}\n title=\"__title__\"\n description={[__description__]}\n tsx={[__tsx__]}\n __scss__\n tsxSource={[__tsxSource__]}\n __scssSource__\n/>\n"]))); demoStr = demoStr.replace(/__id__/g, demo.get(lang).id); demoStr = demoStr.replace(/__renderer__/g, demo.get(lang).name); demoStr = demoStr.replace(/__title__/g, demo.get(lang).title); demoStr = demoStr.replace(/__description__/g, new TextEncoder().encode(demo.get(lang).description).join()); demoStr = demoStr.replace(/__tsx__/g, new TextEncoder().encode((0, marked_1.default)(demo.get(lang).tsx)).join()); - demoStr = demoStr.replace(/__scss__/g, demo.get(lang).scss ? String.raw(templateObject_14 || (templateObject_14 = (0, tslib_1.__makeTemplateObject)(["scss={String.raw", "", "", "}"], ["scss={String.raw", "", "", "}"])), '`', (0, marked_1.default)(demo.get(lang).scss), '`') : ''); + demoStr = demoStr.replace(/__scss__/g, demo.get(lang).scss ? String.raw(templateObject_15 || (templateObject_15 = (0, tslib_1.__makeTemplateObject)(["scss={String.raw", "", "", "}"], ["scss={String.raw", "", "", "}"])), '`', (0, marked_1.default)(demo.get(lang).scss), '`') : ''); demoStr = demoStr.replace(/__tsxSource__/g, new TextEncoder().encode(demo.get(lang).tsx.match(/(?<=```tsx\n)[\s\S]*?(?=```)/g)[0]).join()); demoStr = demoStr.replace(/__scssSource__/g, demo.get(lang).scss - ? String.raw(templateObject_15 || (templateObject_15 = (0, tslib_1.__makeTemplateObject)(["scssSource={String.raw", "", "", "}"], ["scssSource={String.raw", "", "", "}"])), '`', demo.get(lang).scss.match(/(?<=```scss\n)[\s\S]*?(?=```)/g)[0], '`') : ''); + ? String.raw(templateObject_16 || (templateObject_16 = (0, tslib_1.__makeTemplateObject)(["scssSource={String.raw", "", "", "}"], ["scssSource={String.raw", "", "", "}"])), '`', demo.get(lang).scss.match(/(?<=```scss\n)[\s\S]*?(?=```)/g)[0], '`') : ''); demosStr += demoStr; - linksStr += String.raw(templateObject_16 || (templateObject_16 = (0, tslib_1.__makeTemplateObject)(["{ href: '#", "', title: '", "' }, "], ["{ href: '#", "', title: '", "' }, "])), demo.get(lang).id, demo.get(lang).title); + linksStr += String.raw(templateObject_17 || (templateObject_17 = (0, tslib_1.__makeTemplateObject)(["{ href: '#", "', title: '", "' }, "], ["{ href: '#", "', title: '", "' }, "])), demo.get(lang).id, demo.get(lang).title); } }); - var routeArticleProps = String.raw(templateObject_17 || (templateObject_17 = (0, tslib_1.__makeTemplateObject)(["\n{\n title: '__title__',\n subtitle: '__subtitle__',\n description: [__description__],\n api: [__api__],\n demos: (\n <>\n ", "\n \n ),\n links: [__links__],\n}\n"], ["\n{\n title: '__title__',\n subtitle: '__subtitle__',\n description: [__description__],\n api: [__api__],\n demos: (\n <>\n ", "\n \n ),\n links: [__links__],\n}\n"])), demosStr); + var routeArticleProps = String.raw(templateObject_18 || (templateObject_18 = (0, tslib_1.__makeTemplateObject)(["\n{\n title: '__title__',\n subtitle: '__subtitle__',\n description: [__description__],\n api: [__api__],\n demos: (\n <>\n ", "\n \n ),\n links: [__links__],\n}\n"], ["\n{\n title: '__title__',\n subtitle: '__subtitle__',\n description: [__description__],\n api: [__api__],\n demos: (\n <>\n ", "\n \n ),\n links: [__links__],\n}\n"])), demosStr); routeArticleProps = routeArticleProps.replace(/__title__/g, meta.title['en-US']); routeArticleProps = routeArticleProps.replace(/__subtitle__/g, meta.title[lang]); routeArticleProps = routeArticleProps.replace(/__links__/g, linksStr); @@ -249,13 +256,29 @@ var GenerateSite = /** @class */ (function () { routeArticleProps = routeArticleProps.replace(/__description__/g, new TextEncoder().encode((0, marked_1.default)(description)).join()); routeArticleProps = routeArticleProps.replace(/__api__/g, new TextEncoder().encode((0, marked_1.default)(api)).join()); } - var langRegExp = new RegExp(String.raw(templateObject_18 || (templateObject_18 = (0, tslib_1.__makeTemplateObject)(["__", "__"], ["__", "__"])), lang), 'g'); - routeTmp_1 = routeTmp_1.replace(langRegExp, routeArticleProps); + var langRegExp = new RegExp(String.raw(templateObject_19 || (templateObject_19 = (0, tslib_1.__makeTemplateObject)(["__", "__"], ["__", "__"])), lang), 'g'); + componentRouteTmp_1 = componentRouteTmp_1.replace(langRegExp, routeArticleProps); }); - this.outputFile(path_1.default.join(outDir, "".concat(meta.title['en-US'], ".tsx")), routeTmp_1); + this.outputFile(path_1.default.join(outDir, "".concat(meta.title['en-US'], ".tsx")), componentRouteTmp_1); } } }); + Object.defineProperty(GenerateSite.prototype, "generateRoute", { + enumerable: false, + configurable: true, + writable: true, + value: function (routeName, dirPath) { + var routeTmp = this.routeTmp; + routeTmp = routeTmp.replace(/__Route__/g, routeName); + ['en-US', 'zh-Hant'].forEach(function (lang) { + var langRegExp = new RegExp(String.raw(templateObject_20 || (templateObject_20 = (0, tslib_1.__makeTemplateObject)(["__", "__"], ["__", "__"])), lang), 'g'); + routeTmp = routeTmp.replace(langRegExp, new TextEncoder() + .encode((0, marked_1.default)((0, fs_extra_1.readFileSync)(path_1.default.join(dirPath, routeName + (lang === 'en-US' ? '' : ".".concat(lang))) + '.md').toString())) + .join()); + }); + this.outputFile(path_1.default.join(dirPath, routeName, "".concat(routeName, ".tsx")), routeTmp); + } + }); Object.defineProperty(GenerateSite.prototype, "generateGlobalFiles", { enumerable: false, configurable: true, @@ -269,8 +292,8 @@ var GenerateSite = /** @class */ (function () { try { for (var _b = (0, tslib_1.__values)(this.routeConfig.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = (0, tslib_1.__read)(_c.value, 2), key = _d[0], value = _d[1]; - importStr += String.raw(templateObject_19 || (templateObject_19 = (0, tslib_1.__makeTemplateObject)(["const ", "Route = lazy(() => import('", "'));\n"], ["const ", "Route = lazy(() => import('", "'));\n"])), key, value.import); - routeStr += String.raw(templateObject_20 || (templateObject_20 = (0, tslib_1.__makeTemplateObject)(["\n{\n path: '", "',\n component: ", "Route,\n},\n"], ["\n{\n path: '", "',\n component: ", "Route,\n},\n"])), value.path, key); + importStr += String.raw(templateObject_21 || (templateObject_21 = (0, tslib_1.__makeTemplateObject)(["const ", "Route = lazy(() => import('", "'));\n"], ["const ", "Route = lazy(() => import('", "'));\n"])), key, value.import); + routeStr += String.raw(templateObject_22 || (templateObject_22 = (0, tslib_1.__makeTemplateObject)(["\n{\n path: '", "',\n component: ", "Route,\n},\n"], ["\n{\n path: '", "',\n component: ", "Route,\n},\n"])), value.path, key); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } @@ -280,10 +303,10 @@ var GenerateSite = /** @class */ (function () { } finally { if (e_2) throw e_2.error; } } - var routesTmp = this.routesTmp; - routesTmp = routesTmp.replace(/__import__/g, importStr); - routesTmp = routesTmp.replace(/__Route__/g, routeStr); - this.outputFile(path_1.default.join(OUTPUT_DIR, 'routes', 'components', 'routes.ts'), routesTmp); + var componentRoutesTmp = this.componentRoutesTmp; + componentRoutesTmp = componentRoutesTmp.replace(/__import__/g, importStr); + componentRoutesTmp = componentRoutesTmp.replace(/__Route__/g, routeStr); + this.outputFile(path_1.default.join(OUTPUT_DIR, 'routes', 'components', 'routes.ts'), componentRoutesTmp); } }); Object.defineProperty(GenerateSite.prototype, "generateAll", { @@ -291,7 +314,8 @@ var GenerateSite = /** @class */ (function () { configurable: true, writable: true, value: function () { - var e_3, _a; + var e_3, _a, e_4, _b, e_5, _c; + var _d; var components = (0, fs_extra_1.readdirSync)(COMPONENT_DIR); try { for (var components_1 = (0, tslib_1.__values)(components), components_1_1 = components_1.next(); !components_1_1.done; components_1_1 = components_1.next()) { @@ -309,6 +333,34 @@ var GenerateSite = /** @class */ (function () { } finally { if (e_3) throw e_3.error; } } + try { + for (var ROUTE_DIR_1 = (0, tslib_1.__values)(ROUTE_DIR), ROUTE_DIR_1_1 = ROUTE_DIR_1.next(); !ROUTE_DIR_1_1.done; ROUTE_DIR_1_1 = ROUTE_DIR_1.next()) { + var ROUTE = ROUTE_DIR_1_1.value; + var files = (0, fs_extra_1.readdirSync)(ROUTE); + try { + for (var files_1 = (e_5 = void 0, (0, tslib_1.__values)(files)), files_1_1 = files_1.next(); !files_1_1.done; files_1_1 = files_1.next()) { + var file = files_1_1.value; + if (file.endsWith('.md') && ((_d = file.match(/\./g)) === null || _d === void 0 ? void 0 : _d.length) === 1) { + this.generateRoute(file.slice(0, -3), ROUTE); + } + } + } + catch (e_5_1) { e_5 = { error: e_5_1 }; } + finally { + try { + if (files_1_1 && !files_1_1.done && (_c = files_1.return)) _c.call(files_1); + } + finally { if (e_5) throw e_5.error; } + } + } + } + catch (e_4_1) { e_4 = { error: e_4_1 }; } + finally { + try { + if (ROUTE_DIR_1_1 && !ROUTE_DIR_1_1.done && (_b = ROUTE_DIR_1.return)) _b.call(ROUTE_DIR_1); + } + finally { if (e_4) throw e_4.error; } + } this.generateGlobalFiles(); } }); @@ -320,7 +372,8 @@ var GenerateSite = /** @class */ (function () { var _this = this; this.resources = (0, fs_extra_1.readJsonSync)(path_1.default.join(__dirname, 'site', 'resources.json')); this.menuGroups = (0, fs_extra_1.readJsonSync)(path_1.default.join(__dirname, 'site', 'menu-groups.json')); - this.routesTmp = (0, fs_extra_1.readFileSync)(path_1.default.join(__dirname, 'site', 'routes.txt')).toString(); + this.componentRoutesTmp = (0, fs_extra_1.readFileSync)(path_1.default.join(__dirname, 'site', 'component-routes.txt')).toString(); + this.componentRouteTmp = (0, fs_extra_1.readFileSync)(path_1.default.join(__dirname, 'site', 'ComponentRoute.txt')).toString(); this.routeTmp = (0, fs_extra_1.readFileSync)(path_1.default.join(__dirname, 'site', 'Route.txt')).toString(); this.menuConfig = []; this.menuGroups.forEach(function (item) { @@ -361,19 +414,19 @@ var FileWatcher = /** @class */ (function () { get: function () { var _this = this; return this.subject.pipe((0, operators_1.debounceTime)(200), (0, operators_1.tap)(function () { - var e_4, _a; + var e_6, _a; try { for (var _b = (0, tslib_1.__values)(_this.taskQueue.values()), _c = _b.next(); !_c.done; _c = _b.next()) { var cb = _c.value; cb(); } } - catch (e_4_1) { e_4 = { error: e_4_1 }; } + catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } - finally { if (e_4) throw e_4.error; } + finally { if (e_6) throw e_6.error; } } _this.taskQueue.clear(); })); @@ -419,19 +472,19 @@ var FileWatcher = /** @class */ (function () { configurable: true, writable: true, value: function () { - var e_5, _a; + var e_7, _a; try { for (var _b = (0, tslib_1.__values)(this.watcherList.values()), _c = _b.next(); !_c.done; _c = _b.next()) { var watcher = _c.value; watcher.close(); } } - catch (e_5_1) { e_5 = { error: e_5_1 }; } + catch (e_7_1) { e_7 = { error: e_7_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } - finally { if (e_5) throw e_5.error; } + finally { if (e_7) throw e_7.error; } } this.watcherList.clear(); } @@ -458,7 +511,8 @@ function siteBuildExecutor(options, context) { if (!options.watch) return [3 /*break*/, 4]; fileWatcher_1 = new FileWatcher(); refreshComponentWatcher_1 = function () { - var e_6, _a; + var e_8, _a, e_9, _b; + var _c; var components = (0, fs_extra_1.readdirSync)(COMPONENT_DIR); var _loop_1 = function (component) { var componentPath = path_1.default.join(COMPONENT_DIR, component); @@ -484,12 +538,59 @@ function siteBuildExecutor(options, context) { _loop_1(component); } } - catch (e_6_1) { e_6 = { error: e_6_1 }; } + catch (e_8_1) { e_8 = { error: e_8_1 }; } finally { try { if (components_2_1 && !components_2_1.done && (_a = components_2.return)) _a.call(components_2); } - finally { if (e_6) throw e_6.error; } + finally { if (e_8) throw e_8.error; } + } + var _loop_2 = function (ROUTE) { + var e_10, _d; + var files = (0, fs_extra_1.readdirSync)(ROUTE); + var _loop_3 = function (file) { + if (file.endsWith('.md') && ((_c = file.match(/\./g)) === null || _c === void 0 ? void 0 : _c.length) === 1) { + var routeName_1 = file.slice(0, -3); + var task = { + id: "generateRoute_".concat(routeName_1), + callback: function () { + console.info("Update ".concat(routeName_1, "...")); + generateMediator.generateRoute(routeName_1, ROUTE); + generateMediator.generateGlobalFiles(); + }, + }; + if (!fileWatcher_1.hasWatcher(path_1.default.join(ROUTE, file))) { + fileWatcher_1.addWatcher(path_1.default.join(ROUTE, routeName_1 + '.md'), task); + fileWatcher_1.addWatcher(path_1.default.join(ROUTE, routeName_1 + '.zh-Hant.md'), task); + } + } + }; + try { + for (var files_2 = (e_10 = void 0, (0, tslib_1.__values)(files)), files_2_1 = files_2.next(); !files_2_1.done; files_2_1 = files_2.next()) { + var file = files_2_1.value; + _loop_3(file); + } + } + catch (e_10_1) { e_10 = { error: e_10_1 }; } + finally { + try { + if (files_2_1 && !files_2_1.done && (_d = files_2.return)) _d.call(files_2); + } + finally { if (e_10) throw e_10.error; } + } + }; + try { + for (var ROUTE_DIR_2 = (0, tslib_1.__values)(ROUTE_DIR), ROUTE_DIR_2_1 = ROUTE_DIR_2.next(); !ROUTE_DIR_2_1.done; ROUTE_DIR_2_1 = ROUTE_DIR_2.next()) { + var ROUTE = ROUTE_DIR_2_1.value; + _loop_2(ROUTE); + } + } + catch (e_9_1) { e_9 = { error: e_9_1 }; } + finally { + try { + if (ROUTE_DIR_2_1 && !ROUTE_DIR_2_1.done && (_b = ROUTE_DIR_2.return)) _b.call(ROUTE_DIR_2); + } + finally { if (e_9) throw e_9.error; } } }; fileWatcher_1.addWatcher(path_1.default.join(__dirname, 'site'), { @@ -519,4 +620,4 @@ function siteBuildExecutor(options, context) { }); } exports.default = siteBuildExecutor; -var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12, templateObject_13, templateObject_14, templateObject_15, templateObject_16, templateObject_17, templateObject_18, templateObject_19, templateObject_20; +var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6, templateObject_7, templateObject_8, templateObject_9, templateObject_10, templateObject_11, templateObject_12, templateObject_13, templateObject_14, templateObject_15, templateObject_16, templateObject_17, templateObject_18, templateObject_19, templateObject_20, templateObject_21, templateObject_22; diff --git a/tools/executors/site/build-base/impl.ts b/tools/executors/site/build-base/impl.ts index 9f982fa3..21683df5 100644 --- a/tools/executors/site/build-base/impl.ts +++ b/tools/executors/site/build-base/impl.ts @@ -43,6 +43,7 @@ marked.setOptions({ }); const COMPONENT_DIR = String.raw`packages/ui/src/components`; +const ROUTE_DIR = [String.raw`packages/site/src/app/routes/components`]; const OUTPUT_DIR = String.raw`packages/site/src/app`; export interface SiteBuildExecutorOptions { @@ -87,7 +88,8 @@ class GenerateSite { }; }; private menuGroups!: Array<{ 'en-US': string; 'zh-Hant': string }>; - private routesTmp!: string; + private componentRoutesTmp!: string; + private componentRouteTmp!: string; private routeTmp!: string; constructor() { @@ -239,9 +241,9 @@ class GenerateSite { } } - let routeTmp = this.routeTmp; - routeTmp = routeTmp.replace(/__Route__/g, meta.title['en-US']); - routeTmp = routeTmp.replace(/__import__/g, importStr); + let componentRouteTmp = this.componentRouteTmp; + componentRouteTmp = componentRouteTmp.replace(/__Route__/g, meta.title['en-US']); + componentRouteTmp = componentRouteTmp.replace(/__import__/g, importStr); (['en-US', 'zh-Hant'] as const).forEach((lang) => { this.resources[lang].translation.menu[meta.title['en-US']] = meta.title[lang]; @@ -313,13 +315,28 @@ class GenerateSite { routeArticleProps = routeArticleProps.replace(/__api__/g, new TextEncoder().encode(marked(api)).join()); } const langRegExp = new RegExp(String.raw`__${lang}__`, 'g'); - routeTmp = routeTmp.replace(langRegExp, routeArticleProps); + componentRouteTmp = componentRouteTmp.replace(langRegExp, routeArticleProps); }); - this.outputFile(path.join(outDir, `${meta.title['en-US']}.tsx`), routeTmp); + this.outputFile(path.join(outDir, `${meta.title['en-US']}.tsx`), componentRouteTmp); } } + generateRoute(routeName: string, dirPath: string) { + let routeTmp = this.routeTmp; + routeTmp = routeTmp.replace(/__Route__/g, routeName); + (['en-US', 'zh-Hant'] as const).forEach((lang) => { + const langRegExp = new RegExp(String.raw`__${lang}__`, 'g'); + routeTmp = routeTmp.replace( + langRegExp, + new TextEncoder() + .encode(marked(readFileSync(path.join(dirPath, routeName + (lang === 'en-US' ? '' : `.${lang}`)) + '.md').toString())) + .join() + ); + }); + this.outputFile(path.join(dirPath, routeName, `${routeName}.tsx`), routeTmp); + } + generateGlobalFiles() { this.outputJson(path.join(OUTPUT_DIR, 'configs', 'menu.json'), this.menuConfig); this.outputJson(path.join(OUTPUT_DIR, 'i18n', 'resources.json'), this.resources); @@ -336,10 +353,10 @@ class GenerateSite { }, `; } - let routesTmp = this.routesTmp; - routesTmp = routesTmp.replace(/__import__/g, importStr); - routesTmp = routesTmp.replace(/__Route__/g, routeStr); - this.outputFile(path.join(OUTPUT_DIR, 'routes', 'components', 'routes.ts'), routesTmp); + let componentRoutesTmp = this.componentRoutesTmp; + componentRoutesTmp = componentRoutesTmp.replace(/__import__/g, importStr); + componentRoutesTmp = componentRoutesTmp.replace(/__Route__/g, routeStr); + this.outputFile(path.join(OUTPUT_DIR, 'routes', 'components', 'routes.ts'), componentRoutesTmp); } generateAll() { @@ -354,13 +371,23 @@ class GenerateSite { } } + for (const ROUTE of ROUTE_DIR) { + const files = readdirSync(ROUTE); + for (const file of files) { + if (file.endsWith('.md') && file.match(/\./g)?.length === 1) { + this.generateRoute(file.slice(0, -3), ROUTE); + } + } + } + this.generateGlobalFiles(); } updateTmp() { this.resources = readJsonSync(path.join(__dirname, 'site', 'resources.json')); this.menuGroups = readJsonSync(path.join(__dirname, 'site', 'menu-groups.json')); - this.routesTmp = readFileSync(path.join(__dirname, 'site', 'routes.txt')).toString(); + this.componentRoutesTmp = readFileSync(path.join(__dirname, 'site', 'component-routes.txt')).toString(); + this.componentRouteTmp = readFileSync(path.join(__dirname, 'site', 'ComponentRoute.txt')).toString(); this.routeTmp = readFileSync(path.join(__dirname, 'site', 'Route.txt')).toString(); this.menuConfig = []; @@ -462,6 +489,27 @@ export default async function* siteBuildExecutor(options: SiteBuildExecutorOptio } } } + for (const ROUTE of ROUTE_DIR) { + const files = readdirSync(ROUTE); + for (const file of files) { + if (file.endsWith('.md') && file.match(/\./g)?.length === 1) { + const routeName = file.slice(0, -3); + const task = { + id: `generateRoute_${routeName}`, + callback: () => { + console.info(`Update ${routeName}...`); + + generateMediator.generateRoute(routeName, ROUTE); + generateMediator.generateGlobalFiles(); + }, + }; + if (!fileWatcher.hasWatcher(path.join(ROUTE, file))) { + fileWatcher.addWatcher(path.join(ROUTE, routeName + '.md'), task); + fileWatcher.addWatcher(path.join(ROUTE, routeName + '.zh-Hant.md'), task); + } + } + } + } }; fileWatcher.addWatcher(path.join(__dirname, 'site'), { diff --git a/tools/executors/site/build-base/site/ComponentRoute.txt b/tools/executors/site/build-base/site/ComponentRoute.txt new file mode 100644 index 00000000..8d10f001 --- /dev/null +++ b/tools/executors/site/build-base/site/ComponentRoute.txt @@ -0,0 +1,25 @@ +// @ts-nocheck + +import { useEffect } from 'react'; + +import { useCustomContext } from '@react-devui/ui/hooks'; + +import { AppContext } from '../../../App'; +import { AppComponentRoute, AppDemoBox } from '../../../components'; + +__import__ + +export default function __Route__() { + const props = { + 'en-US': __en-US__, + 'zh-Hant': __zh-Hant__, + }; + + const [{ onMount: _onMount }] = useCustomContext(AppContext); + + useEffect(() => { + _onMount?.(); + }, []); + + return ; +} diff --git a/tools/executors/site/build-base/site/Route.txt b/tools/executors/site/build-base/site/Route.txt index 84c1b294..d4a6e0cd 100644 --- a/tools/executors/site/build-base/site/Route.txt +++ b/tools/executors/site/build-base/site/Route.txt @@ -5,14 +5,12 @@ import { useEffect } from 'react'; import { useCustomContext } from '@react-devui/ui/hooks'; import { AppContext } from '../../../App'; -import { AppRoute, AppDemoBox } from '../../../components'; - -__import__ +import { AppRoute } from '../../../components'; export default function __Route__() { const props = { - 'en-US': __en-US__, - 'zh-Hant': __zh-Hant__, + 'en-US': { html: [__en-US__] }, + 'zh-Hant': { html: [__zh-Hant__] }, }; const [{ onMount: _onMount }] = useCustomContext(AppContext); diff --git a/tools/executors/site/build-base/site/routes.txt b/tools/executors/site/build-base/site/component-routes.txt similarity index 100% rename from tools/executors/site/build-base/site/routes.txt rename to tools/executors/site/build-base/site/component-routes.txt diff --git a/tools/executors/site/build-base/site/resources.json b/tools/executors/site/build-base/site/resources.json index 4f6ac2f5..583db898 100644 --- a/tools/executors/site/build-base/site/resources.json +++ b/tools/executors/site/build-base/site/resources.json @@ -11,6 +11,9 @@ "Copy code": "Copy code", "Copied!": "Copied!", "Edit this demo on GitHub": "Edit this demo on GitHub", + "Documentation": { + "Interface": "Interface" + }, "menu-group": {}, "menu": {} } @@ -27,6 +30,9 @@ "Copy code": "复制代码", "Copied!": "复制成功!", "Edit this demo on GitHub": "在 GitHub 上编辑此示例", + "Documentation": { + "Interface": "接口" + }, "menu-group": {}, "menu": {} } diff --git a/yarn.lock b/yarn.lock index 91512067..cfa60b57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12201,11 +12201,16 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.4.3, typescript@~4.5.2: +typescript@^4.4.3: version "4.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.3.tgz#afaa858e68c7103317d89eb90c5d8906268d353c" integrity sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ== +typescript@~4.5.2: + version "4.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" + integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== + uglify-js@^3.1.4: version "3.14.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.4.tgz#68756f17d1b90b9d289341736cb9a567d6882f90"